GUI Creation with PowerShell: The Basics

WPF or Windows Forms?                     

If you want to create a GUI for your Powershell script, you’ve got two options. You can either use Windows Forms (WinForms) or Windows Presentation Foundation (WPF).

I wont bother you with the technical differences (they are well explained here if you’re interested). The practical differences however, are that with Windows Forms you will use the native Windows interface elements and you will have only limited control on how things will look like. With WPF you got the full freedom of design, but the downside is that it’s way more complicated to use than WinForms, especially for beginners. And for WinForms, there are WYSIWYG-Editors available, which generate native Powershell code. That’s a huge advantage, because you simply click your GUI-elements together and immediately get your ready-to-use Powershell code.

You usually won’t have the time to create a fancy design anyway and if you really want to, you can do a few nice things with WinForms too. But for the purpose of creating a GUI for your administrative script or a nice and convenient little tool for your users, WinForms will do just fine:gallery

So for this and the upcoming articles, we will focus on WinForms.

Understanding Windows Forms            

If you have been using Powershell for at least a little while, you should be used to working with objects. Well, WinForms GUI elements are also objects. And as you know, each object has a set of properties and methods.

A button for example has properties for it’s size, location, text, color and a lot more. Most of these properties you can set or change in the Forms editor (we will get to that later).

The methods of these objects you will use rather seldom, but there are some other things you can configure in the editor and these you will use constantly: events. Windows Forms are event driven. That means, after you created your window, placed your buttons, labels and other elements and run the whole thing, it just sits there and waits for something to happen. It waits that somebody clicks on a button, enters a text, whatever. And to configure if and what the script should do when something happens, that’s what events are for.

Each element has a lot of events for all kinds of things. Obvious ones, like a left mouse click on a button or a text was entered in a textbox, but also some not so obvious ones. I encourage you to take a moment and skim through the list of events for the button object in the MSDN library. Its a good resource and helpful in order to bring Windows Forms to its full potential. Therefore its important hat you get familiar with the way information is displayed there.

Get Started                                              

First of all, you need a Forms editor. There are currently three that I’m aware of, two commercial ones ( ASE Enterprise and PrimalForms 2011, each US$ 299.00, but different feature sets) and the free PrimalForms Community Edition. If you are going to use Windows Forms regularly in the future, i recommend thinking about buying one. They have a few advantages, for example they are fully integrated with a script editor and support more classes.
Update: Its 2015 now, and Sapiens PowerShell Studio (former PrimalForms) is  the last one standing. And as soon as the last competitor went offline, so did the “community“-edition of PrimalForms.  Maybe you can still find it somewhere, if you search for it.
BUT, there is still one free option out there, ASE 4.0 was made freeware in the end. Its available here.
Little warning: ASE was an excellent editor and still is, but the last version was never finished, is therefore a bit buggy and needs to be installed on a x86 version of windows with .Net 2.0 installed.

You will also need a script editor, you can use the shipped Powershell ISE, but i recommend using the free and quite powerful PowerGUI from Quest (now Dell).

Create your First GUI                                   

For this tutorial, we will create a simple little tool, which lets you type an username into a text box and after you press a button, will perform a “net user <username>” and displays the results in another text box.

Start up both PrimalForms and the script editor of your choice.
In PrimalForms, click on “New”.

image

In the middle you see your new form window. On the left pane are the GUI-elements which you can drag-and-drop on the form in the middle.

On the right pane, you see the properties for the objects in your form. At the moment there is just the form window itself and if you select it, you will see its properties. As the right pane looks very similar for most objects, you should always check which object (button, label, textbox etc.) is currently selected in the middle, before editing properties on the right side.
On the top of the pane, there is also a little button with a flash icon. Click it and you see the events available for the selected object.

If you click on the right side of a property or an event, you can change its value.

The Form Window

Let’s take a closer look at the form window properties. First of all you can configure the appearance of the window. The settings for Forecolor and Font for example, will be inherited by all other objects in your form, unless they don’t have these properties or they are set to a different value.

You can also set the border style, the minimum and maximum size of the window and whether the user shall be able to resize, minimize or maximize the window at all. I suggest playing around with these settings, most of of them are pretty straight forward.

Now lets take look at the code PrimalForms generates. Because its not integrated with a script editor you have to press CTRL+F7 to copy the code to your clipboard. Then switch to your code editor and insert it in an empty script.

Generated Code

What we have so far, looks like this (unless you played with the settings :-))

function GenerateForm {
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#region Generated Form Code
$form1.Text = "Primal Form"
$form1.Name = "form1"
$form1.StartPosition = 4
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 284
$System_Drawing_Size.Height = 262
$form1.ClientSize = $System_Drawing_Size
$form1.FormBorderStyle = 1

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm

The GenerateForm-function can be split in three parts:

  • the loading of the .net assemblies needed to create windows forms
  • the creation and configuration of the gui elements (just one in this case: $form1)
  • the command $form1.ShowDialog(), to run the form

Unfortunately the code PrimalForms generates is quite lengthily. And I’m not only talking about all the remarks, but some properties can be set much more straight forward. The same code stripped of all unnecessary things looks like this:

function GenerateForm {
[void][reflection.assembly]::loadwithpartialname("System.Windows.Forms") 

$form1 = New-Object System.Windows.Forms.Form
$form1.Text = "Primal Form"
$form1.StartPosition = 4
$form1.ClientSize = "284,262"
$form1.ShowDialog()
} 

GenerateForm

A tiny bit shorter, isn’t it? Its not necessary for example, to create a new System.Drawing.Size-object to set the size, you can simple add the height and width (in pixels) directly. If you configure the colors, font or other properties, you will see much more of these unnecessary objects. But they don’t really hurt, they just make the code hard to read. Especially when you consider the fact that the forms-region of a script can easily have 1000 or more lines.

But you don’t need to worry about that. I just tell you this, so that that if at some point, you want to set properties by hand, you know that you don’t need these extra objects.

Run the Form

As you can see PrimalForms puts all the stuff in one function and then calls the function. That’s one way to do it. You can also put all but the last command of the function somewhere in the script and then run the form with  $form1.ShowDialog() from the bottom of your script.

There are different ways to run a form and .ShowDialog() is just one of them. We will talk more about that in another article.
For now, there is one important thing to understand about this command: as soon as you run the form, your script will only react to the configured events. If you take a look at the script above, one could think that if you call the function GenerateForm, Powershell would process all the commands in it, displays the form and then continues with anything that comes after the function call, as it does with all other functions. But in this case, Powershell will stay in this function until you close the form window. As long as the window is visible, you need to have defined events in order to run commands and functions.
Furthermore, that means you have to put all the functions you want to call from the form, before the command which runs the form. The easiest way is to always put this command in the last line of the script and you’re fine.

Adding GUI elements

Now it’s time to to put some elements into the form: switch back to PrimalForms and drag the following elements to your form: a Button, a TextBox and a RichTextBox, so that the window looks like this:

image

Make Elements Resizable

Now run the form again (by that i always mean: Press CTRL+F7 in PrimalForms, switch to your script editor, paste it there and run it) and try to resize your form. Odd isn’t it? You can resize it, but the elements don’t get resized, they stay where they are.

This is due to a property named “anchor”, which you find in every GUI element. image The standard value for this is always “top,left” which means that the element will always hold its position in relation to the top and left border of the parent object. In this case that’s the form window. But there are other elements that can hold child objects as well, for example the “GroupBox” (a half transparent box, often used to group settings in option windows).

If you want an element to resize with the parent object, you need to anchor it to at least two opposite borders. Then it has no choice but to resize itself, in order to hold its position in relation to both borders. :-)

Alright, now find the right settings for all three elements so that: the RichTextBox resizes in width and height, the TextBox only in width, and the Button doesn’t resize at all, but always stays behind the TextBox. (tooltip solution)

Adding Events

Finally, we will breathe some life into our little program. The goal is to configure the button so that it calls a function when you press it. In this function we will read the text from the TextBox, process it and display the results in the RichTextBox.

In PrimalForms, select the button in your form and click on the flash-icon on the top of the right pane. Now find the “Click”-event and input the name of the new event handler, which we just call “processData”.

image

Hit enter and copy the code to your script-editor again.

Event Handler

When you take a look at the code, you see that the event gets added in line 94:

image

This means: Add the event “click” to the object “Button1” and if that event is raised (the button is pressed) process the code inside variable $processdata.

The variable $processdata gets configured in line 26, in the new section “Generated Event Script Blocks”:

image

We could now type in our code, where it says we should. I don’t recommend that. I prefer to place code always in functions, because it makes long scripts easier to read and you have the ability to simply call them e.g. out of other functions, without having to raise events manually.
So, instead of the code, we could add a function call there.

But there is an even simpler method: we can add it directly in line 94, where we add the event.

We are going to name the function “FNprocessdata” and therefore we change line 94 from $button1.add_Click($processData)  to  $button1.add_Click({FNprocessData}) (notice that the function call is between curly brackets).

This might be a bit confusing now, but especially in longer scripts with lots of events and functions, this method has its benefits.

Adding the Function

To read the text from the TextBox, we simply read the property $textBox1.text, which holds the content of the TextBox. It can also be used to set the content of the TextBox, by assigning a value to it (e.g. $textbox1.text = “mytext”)
The RichTextBox has the same property, so we could use that to display the results. Unfortunately if we pass the result of “net user …”  to the RichTextBox at once, we get one long line of text, without any line breaks. So instead, we add line by line with the method .Appendtext() and add a line break after each line.

This is the complete function, add it to the script, above the the command GenerateForm.

function FNprocessData {
  # Read the contents of the textBox1 and perfom the "net user" command with it
  $net = net user ($textBox1.text)        

  # Parse each line of the result, add a linebreak and append it to the RichTextBox
  foreach ($line in $net) {
      $richTextBox1.Appendtext($line+[char]13+[char]10)
  }
 }

And now run the script, input a username and hit the button.

image

You may notice that in opposite to when you run the “net user” -command on the console, the output in our RichtextBox is differently formatted. This is because the console uses a monospaced font.
We can fix that by changing the font for the RichTextBox, to such a font, e.g. Courier New. Add this line to the “GenerateForm” – function, preferably where the other RichTextBox properties are set:

$richTextBox1.font = "Courier New"

Now it looks better:

image

Well, that’s it for today. You’ve just created your first Powershell script with a GUI, congratulations! :-)
And this is really just the start. There is much, much more you can do with Windows Forms, you will see….

If you liked this tutorial or  had any trouble with this one, please drop me a comment or send me an email.

Have a nice day,
Denniver

(read the Part 2 of the series here)

  1. #1 by RedaDZ on Friday - 00:35

    Exeptional Tutorials for beginners

    Please keep them up

    Best Regards

    RedaDZ

  2. #2 by Greg (@Greg) on Friday - 08:41

    Thanks again for this great tuto, it helps me a lot when I started my first PowerShell project. ;)

  3. #3 by Peter Kriegel on Tuesday - 12:50

    Hello Denniver!

    You can create even a GUI with HTML Application (HTA).
    showed here:
    h**p://social.technet.microsoft.com/wiki/contents/articles/how-to-add-a-graphical-user-interface-to-a-powershell-script-by-using-html-applications.aspx
    and here:
    h**p://blogs.technet.com/b/heyscriptingguy/archive/2009/08/31/hey-scripting-guy-can-i-create-a-gui-for-a-windows-powershell-script.aspx

    For WPF i recomend ShowUI from JamesBrundage and Joel ‘Jaykul’ Bennett.
    h**p://showui.codeplex.com/
    h**p://huddledmasses.org/showui-tutorial-walkthrough/

    But in my point of view Windows Forms are the best method!
    No installation needed and out of the box usable.

    Schöne grüsse
    Peter

  4. #4 by Bandon on Monday - 12:20

    Easily the best tutorial about Winforms on the web! Thanks!

  5. #7 by Natasha on Wednesday - 01:21

    Magnificent web site. A lot of helpful info here.

    I’m sending it to a few friends ans additionally sharing in delicious. And of course, thank you on your effort!

  6. #8 by Bjorn Houben on Tuesday - 10:33

    Great tutorial, thanks a lot.

  7. #9 by Damian Garbus on Thursday - 22:12

    It’s awesome, thanks a lot :)

  8. #10 by Akash on Wednesday - 10:22

    Nice tutorial for creating GUI in PowerShell.

  1. PowerShell ‘Net User’ ShowUI GUI
  2. GUI Creation with PowerShell (Part 2): The Notify Icon or How to make your own HDD Health Monitor « BYTECOOKIE
  3. Episode 156 – Brandon Shell on The Coud, Bunnies and VDI « PowerScripting Podcast
  4. Summary of 2nd Dutch PowerShell User Group – DuPSUG meeting with additional resources | blog.bjornhouben.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: