My standard methodology around the office is to find a common problem that I can solve using a repeatable method, I then turn this into a tool I give to my help desk or clients and move on to the next interesting problem.

While you or I might be comfortable in a console or digging deep into systems settings and can turn a PC with an issue in practically no time, others on our team or that we support might want the process to be more approachable, and have more automation. This also means, to an extent, that it should be made into a tool.

So, lets say in your environment you’ve located an issue (for the sake of this example, computers not responding to ping indicating some problem) and need a mechanism to test whether a machine is connected to the network using a Ping operation, we could do this with just an easy command line entry, but lets build a full graphical tool around this that anybody could use, in order to teach the procedure.

So we know our base code is working. Now to create the outline of the GUI we want.

First and foremost, in order to have access to the Systems.Windows.Forms .NET elements we need to draw our GUI, we have to load the assemblies. This is done with the following two lines, added to the top of our script.

One of the cool things you can do with the System.Windows.Forms object is to modify it’s KeyPreview property to True and then add listeners for certain key presses to have your form respond to them. Basically if you enable KeyPreview, your form itself will intecept a key press and can do things with it before the control that is selected gets the press. So instead of the user having to click the X button or click enter, yowe can tell the form to do something when the user hits Escape or Enter instead.

With that in mind, lets add a hook into both the Enter and Escape keys to make them function.

And now, lets comment block out the Ping section of the script (we’ll also use #region and #endregion to allow us to collapse away that block for the time being) and add the following lines to the bottom to display our form.

If you’ve been following along from home, you should have something similar to this.

And now lets give it a try!

Mmmm, tasty progress.

Ah, the sweet taste of progress. We now have a form and some code which works. Lets add a box where a user can specify the computer name to test, and then a button to start the test.

We’ll be using the Systems.Windows.Forms.Label (Abbreviated as simply Forms.whatever from now on), Forms. TextBox and Forms.Button controls to add the rest of our app for now. While I’m here, if you’d like a listing of all of the available other .net controls you can make use of, check out this link: http://msdn.microsoft.com/en-us/library/system.windows.forms.aspx

First, lets add a label (a field of uneditable text), in which we will describe what this tool will do. To start, instantiate a new System.Windows.Forms object of type .label, and then we’ll set the location, size and text properties. Finally, we’ll add the control to our form using the .Add() method, as you’ll see below. Add the following text above the commented out Actual Code region.

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Size(5,5)
$label.Size = New-Object System.Drawing.Size(240,30)
$label.Text = "Type any computer name to test if it is on the network and can respond to ping"
$Form.Controls.Add($label)

Some notes about this. Location here is given in (x,y) with distances being pixels away from the upper left hand corner of the form. Using this method of building a GUI from scratch, it is not uncommon to spend some time fiddling with the sizing by tweaking values and executing, back and forth.

Note the #regions used to make editing our code a bit cleaner

Lets save our script and see what happens!

We are making a GUI interface using Visual Basi–er, PowerShell!

Alright, next, to throw a textbox on there and add a button to begin the ping test, add the following lines in the ‘#region begin to draw forms’.

At this point you may be noticing a whole lot of forms form forms. I know, there is a lot of retyping the same things. In fact, this whole procedure is begging to be made into a simple New-Control function, but I haven’t had time to hash it out yet, maybe in a future post! Also, one thing I want to draw attention to is the $OKButton.Add_Click; specifying this property will associate the contents of the $ping_computer_click variable (currently empty) as a function to execute when the button is clicked. We’ll go over that in a future post!

Before heading out, lets see what we have thus far.

Seeing the UI come together is such a satisfying feeling

Alright, next time we reconvene, we’ll link our pinging function from earlier into this tool, and see if it works!

Great post Stephen! Like I mentioned at happy hour, I always like to use custom icons with my forms. This is easy to embed in a Posh Script, you just need to pass the icon image’s converted Base64 string to the .Icon property of the Form object (http://webcodertools.com/imagetobase64converter makes it easy):

First off, making this into a function is exactly the way it should be done. In hindsight, boy was I sleep-deprived to leave that out and instead call Invoke-Expression on a variable. Silly me!

Good catch!

As for whats going on with your scrip; here’s the problem: you’ve already got a perfectly good control on your form called $result_label. And yet when you’re running your script, you add a new control on top of the old one, called $results_label_results. The reason this is failing the second time is that you can only add a control of a given name to a form once. If you want to continually write new forms on top of the old, you COULD using an incrementing name, like $results_$i, and then have $i++ at the top of your function. But that would be really weird, and kind of hard.

Here is an easier method. Just change the text of your label. Here is your original code with just a few edits. I’ve removed the definition of $results_label_result and all of its sizing, etc. If you give it a try, it should work!

The code is working really fine. But if I click on OK button i am getting this error

The term ping_computer_click : The term ‘ping_computer_click’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Double check the function names, I think I made a mistake in my own code. Good catch!

naveen basati said:November 24, 2014 at 1:42 pm

Thanks ,
I have changed the function name as ping_computer_click. Its working fine now. I want to add a browse button to load multiple ips and pinging it back with output to grid view. Your suggesstions are appreciable!!!!!!!!!!!!!!