Building a PowerShell GUI (Part 9)

by [Published on 23 Aug. 2016 / Last Updated on 23 Aug. 2016]

This article continues the discussion of building a PowerShell GUI by demonstrating techniques for removing interface objects from the screen, and creating list boxes.

If you would like to read the other parts in this article series please go to:

In my previous article, I showed you how to create a relatively simple PowerShell script that would allow you to click a button to see a list of the virtual machines that are running on a server. That technique made for a good demonstration of PowerShell’s ability to retrieve data from the OS and display it within a GUI, but the script does not do anything practical. But what if we could modify the script so that the user is able to select a virtual machine from a list, and then perform some sort of action on the selected virtual machine? That’s what we are going to do next.

The first step in achieving this goal is to create a list box. A list box, which is sometimes referred to as a drop down list, is a standard GUI element, and is really easy to add to a PowerShell GUI. Let’s take a look at how this works:

#Create List Box

$ListBox1 = New-Object System.Windows.Forms.ListBox

$ListBox1.Location = New-Object System.Drawing.Size(80,80)

$ListBox1.Size = New-Object System.Drawing.Size(260,20)

$ListBox1.Height = 80

 

$VirtualMachines = Get-VM

ForEach ($VM in $VirtualMachines)

                {

[void] $ListBox1.Items.Add($VM.Name)

                }

This is the code used to create a list box. Like all of the other GUI elements that we have been working with, a list box is an object. Therefore, we can define a list box in exactly the same way that we define any other object (by using the New-Object cmdlet). And like the other objects that we have worked with, we are also defining a size and a location. The only thing really different that we are doing as a part of the object definition is defining the list box height. The height controls the size of the list box, and therefore the number of items that are exposed without the need for scrolling.

The lower portion of the code shown above adds items to the list box. In this case, I borrowed the code from the button click action that I set up in the previous article. I am retrieving a list of virtual machines and assigning it to a variable named $VirtualMachines. I am then setting up a ForEach loop in which I perform an action for each virtual machine ($VM) in the list of virtual machines ($VirtualMachines). The action that I am performing is to add the virtual machine name to the list box.

One last thing that we need to do is to add the list box to the GUI. As was the case for other objects, we can do this by using $Form.Controls.Add, followed by the name of the list box ($ListBox1). Here is the actual command:

$Form.Controls.Add($ListBox1)

I will show you the full script later on in this article, but for right now, here is what the list box looks like:

Image
I have modified the script to display a list box containing the names of the virtual machines that exist on the server.

OK, so we have created a list box containing the names of all of the virtual machines on the server. It is possible to click a virtual machine name and click the OK button. As it stands right now however, the click action is left over from before I ever created the list box. In fact, the button is oblivious to the list box’s existence. So the question now becomes, how do we base a click action on the selected item?

Here is the original line of code that defined the button’s click behavior:

$Button1.Add_Click({DisplayVMs})

I am going to replace this line of code with this one:

$Button1.Add_Click({$ChosenItem=$ListBox1.SelectedItem;Display-VMInfo $ChosenItem})

There are a few different things going on in this line of code. First, when someone clicks the button, we are creating a variable named $ChosenItem. This variable will contain the name of the virtual machine that was selected from the list box.

You will also notice the semicolon following SelectedItem. This semicolon represents the start of a new command. The command is Display-VMInfo $ChosenItem. Display-VMInfo is the name of a function that I have created, and I am passing the $ChosenItem variable to that function.

When you call a function in response to a button click, you can make that function do anything that you want. For right now, my function only displays the name of the selected virtual machine. We will eventually do more with the function, but for right now I want to show you another useful technique.

If you think back to the script that I had created in the previous article, you will recall that the script included a simple message instructing the user to click a button to see a list of virtual machines that existed on the server. Upon clicking the button, the list of virtual machines was displayed, as shown in the figure below:

Image
The previous version of the script displayed a list of virtual machines in response to a button click.

As you look at the figure above, you can see that the output was displayed within a textbox. More importantly, this text box was added to the interface objects that already existed. In this case, doing so wasn’t a big deal because the window had plenty of free space available. In the real world however, you may need to clear the screen before displaying information. In native PowerShell, you can use the CLS cmdlet to clear the screen. In the case of a GUI interface however, things work a little bit differently.

As you will recall, the graphical interface is made up of a collection of objects such as labels, buttons, text boxes, and list boxes. We had to create each of these objects individually, and add them to the GUI one by one. Clearing the screen works in a similar manner. You can’t just clear the screen. Instead, you have to identify the specific GUI objects that you want to remove from the screen. Here is an example of how it’s done:

#Clear the window

$Form.Controls.Remove($ListBox1)

$Form.Controls.Remove($Label2)

$Form.Controls.Remove($Button1)

$Form.Refresh()

As you can see, you can use $Form.Controls.Remove, followed by the name of an object, to remove the object from the window. At the end of this block of code, I used $Form.Refresh() to refresh the GUI. In all honesty, the Refresh command is probably unnecessary, but I included it because some older versions of PowerShell have trouble with the removal of graphical items if you do not refresh the display.

So with that said, here is the script in its entirety:

#Load Assemblies

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null

[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null

$net = New-Object -ComObject Wscript.Network

 

#Define Button Click Function

Function Display-VMInfo($ChosenItem)

{

 

#Clear the window

$Form.Controls.Remove($ListBox1)

$Form.Controls.Remove($Label2)

$Form.Controls.Remove($Button1)

$Form.Refresh()

 

#Create Output

Add-Type -AssemblyName System.Windows.Forms

#Create text

$Label = New-Object System.Windows.Forms.textbox

$Label.Location = new-object System.Drawing.Size(50,50)

$Label.Size = New-Object System.Drawing.Size(250,150)

$Label.MultiLine = $True

$Label.Text = $ChosenItem

$Form.Controls.Add($Label)

}

 

#Draw form

$Form = New-Object System.Windows.Forms.Form

$Form.width = 525

$Form.height = 350

$Form.BackColor = "lightblue"

$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D

$Form.Text = "Hyper-V Virtual Machines"

$Form.maximumsize = New-Object System.Drawing.Size(525,350)

$Form.startposition = "centerscreen"

$Form.KeyPreview = $True

$Form.Add_KeyDown({if ($_.KeyCode -eq "Enter") {}})

 $Form.Add_KeyDown({if ($_.KeyCode -eq "Escape")

     {$Form.Close()}})

 

# Create Label2

$Label2 = New-Object System.Windows.Forms.Label

$Label2.AutoSize = $True

$Label2.Location = new-object System.Drawing.Size(20,50)

$Label2.ForeColor = "DarkBlue"

$Label2.Text = "Please select a virtual machine from the list."

 

#Create List Box

$ListBox1 = New-Object System.Windows.Forms.ListBox

$ListBox1.Location = New-Object System.Drawing.Size(80,80)

$ListBox1.Size = New-Object System.Drawing.Size(260,20)

$ListBox1.Height = 80

 

$VirtualMachines = Get-VM

ForEach ($VM in $VirtualMachines)

                {

[void] $ListBox1.Items.Add($VM.Name)

                }

 

#Create button

$Button1 = new-object System.Windows.Forms.Button

$Button1.Location = new-object System.Drawing.Size(20,170)

$Button1.Size = new-object System.Drawing.Size(70,30)

$Button1.BackColor ="LightGray"

$Button1.Text = "OK"

$Button1.Add_Click({$ChosenItem=$ListBox1.SelectedItem;Display-VMInfo $ChosenItem})

 

#Create the Form

$Form.Controls.Add($ListBox1)

$Form.Controls.Add($Button1)

$Form.Controls.Add($Label2)

$Form.Add_Shown({$Form.Activate()})

$Form.ShowDialog()

For right now, running the script displays a list box with the names of the virtual machines that exist on the server, as shown below:

Image
Click a virtual machine and click OK.

Upon making a selection, the screen is cleared, and the name of the selected virtual machine is displayed within a text box, as shown below:

Image
The name of the selected VM is displayed.

Conclusion

Now that I have shown you how to create a list box, and how to remove items from the GUI interface, I plan to make the output display some useful information. I will also show you how to clean things up a bit by adding a caption above the output text box, and by adding a Cancel button.

If you would like to read the other parts in this article series please go to:

See Also


The Author — Brien M. Posey

Brien M. Posey avatar

Brien Posey is an MCSE and has won the Microsoft MVP award for the last few years. Brien has written well over 4,000 technical articles and written or contributed material to 27 books.

Advertisement

Featured Links