Posey's Tips & Tricks
Dynamically Construct a PowerShell GUI, Part 1
Learn how to use loops and dynamic object naming in PowerShell to build GUI settings interfaces that can adapt as new parameters are added.
For the past several months, I have been hard at work writing a massive PowerShell script that will eventually function as a line of business application. From the very beginning, I knew that this particular script would need to include a Settings function that would allow me to configure various parameters, such as the location where temp files are stored.
When I started writing the applications code, the Settings interface was the very first thing that I created. After all, other parts of the application would need to be able to access the Settings, so it made sense to start there. Unfortunately, as I built other parts of the application, I kept discovering that there were more settings that I needed to add to the Settings dialog box. Each of these additional settings caused me to have to reconfigure the Settings dialog box and write additional code related to the new setting.
Needless to say, it didnt take me long to realize that I would be a lot better off handling the settings dynamically. Sure, it would involve some extra work up front, but the benefit would be that I wouldnt have to stop what I was working on and rebuild the settings screen yet again, every time I wanted to add a setting. Ultimately though, building a dynamic interface proved to be much more challenging than I expected it to be. As such, I wanted to share my technique in case it is helpful to anyone else.
My initial idea for building a dynamic Settings interface was to create a key / value pair for each setting. The key would be the setting name and the value would be the setting itself (such as a backup path). I then planned to design my PowerShell code to read each of the records and then use a ForEach loop to create GUI elements for each. While I did use a variation of this technique, there was a big problem that I had to work around.
When you create a Windows Forms based GUI in PowerShell, the first thing that you do is to create a form. A form is essentially just a window. Next, you create a series of GUI objects such as labels (blocks of text), text boxes (input fields), and buttons. Finally, you attach those GUI objects to the form. Let me show you what this looks like. The block of code shown below creates a form:
$SettingsForm = New-Object System.Windows.Forms.Form
$SettingsForm.Text = "Settings"
$SettingsForm.Size = New-Object System.Drawing.Size(1024,768)
$SettingsForm.StartPosition = "CenterScreen"
pre class="codesnippet">
This form is called Settings. Its got a resolution of 1024x768 and it is displayed at the center of the screen. The process of creating GUI objects works a little bit differently for each object type, but the basic idea is that you have to create the object and then assign attributes to the object. As an example, here is some code that is used to create a button:
$SettingsSubmitButton = New-Object System.Windows.Forms.Button
$SettingsSubmitButton.Text = "Update"
$SettingsSubmitButton.Font = New-Object System.Drawing.Font("Arial", 14)
$SettingsSubmitButton.Location = New-Object System.Drawing.Point(80, 600)
$SettingsSubmitButton.Size = New-Object System.Drawing.Size(150,50)
$SettingsSubmitButton.BackColor = "LightGreen"
Once the GUI objects have been created, you can add the object to the form by referencing the forms name and the objects name. Here is a command that adds this button object to the form:
$SettingsForm.Controls.Add($SettingsSubmitButton)
Normally, each GUI object that you create has a unique name assigned to it. That name is what allows you to add the object to the form. As an example, the button that I just created is called $SettingsSubmitButton. I referenced this name when I added the button to the form. I also referenced this name when I assigned attributes such as size and color to the button.
A GUI objects name is also used any time that you want to get information into or out of a GUI object. As an example, lets suppose that you have created a textbox named $UserInput and you wanted to take whatever the user enters into this textbox and add it to a variable called $A. To do so, you could use the command: $A=UserInput.text. As you can see, this command requires you to reference the text boxs unique name. If all of the text boxes on the screen had the same name (which you can do), it would be impossible to act on text that has been typed into a specific textbox.
So herein lies the problem. If you simply use a loop to create textboxes, then the loop will assign exactly the same name to each textbox that was created. As such, I decided to store an object name value as a part of each record. My idea was to loop through the various settings and then create a series of uniquely named GUI objects by referencing the names stored alongside the settings. This approach did work, but it required me to do quite a bit of string manipulation work.
So now that I have talked about how GUI objects normally work and I have presented my strategy of using a loop to assist in the creation of GUI objects, I want to show you how I accomplished my objectives. I will share the full source code with you in Part 2.
About the Author
Brien Posey is a 22-time Microsoft MVP with decades of IT experience. As a freelance writer, Posey has written thousands of articles and contributed to several dozen books on a wide variety of IT topics. Prior to going freelance, Posey was a CIO for a national chain of hospitals and health care facilities. He has also served as a network administrator for some of the country's largest insurance companies and for the Department of Defense at Fort Knox. In addition to his continued work in IT, Posey has spent the last several years actively training as a commercial scientist-astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space. You can follow his spaceflight training on his Web site.