Building Forms with PowerShell – Part 1 (The Form)


When I teach PowerShell workshops, I’m frequently asked if there are any good resources for learning about how to build forms in PowerShell. There are a number of good resources out there to be sure, but you can never have too many. This is my contribution to the education of the scripting masses. I’m going to start very simple, and over the next several posts, we’ll build up an advanced form repertoire.

This first post is about the form itself. The form is just a window on which we can put useful (or whatever) things to build a GUI. For the most part, the form is the easiest of the elements to work with, but you can get somewhat fancy with it. We’ll explore some different form scenarios.

The Simplest Form

There are only three things required to launch a form from PowerShell:

1.       You must load the System.Windows.Forms assembly (if not already done);

2.       You must create a new object of type system.windows.forms.form; and,

3.       You must call the ShowDialog() method on your new object. Note—don’t try calling the Show() method, unless you want your script to hang.

For example:

Add-Type -AssemblyName System.Windows.Forms

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

$Form.ShowDialog()

 

Depending on your Windows shell environment, this is what your form might look like:

clip_image001

Of course, that’s not terribly useful, so we’ll keep going.

Adding Some Text

Text will be helpful in adding some purpose to our form. There are a couple of pieces of text we’ll add.

First, let’s add a window title for the form by setting the form’s Text property. This will show up in the top of the form and will also serve as the window title as shown in the task bar.

Then we’ll add some text in the main window by adding a label control. In order to add a label, we need to create a new Label object, set the relevant properties and add it to the Controls collection of the form. For now, we’ll set only two properties—Text and AutoSize. Enabling AutoSize will ensure that our label is large enough to display all our text.

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

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

$Label.Text = "This form is very simple."

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

clip_image002

 

Note – Most forms will contain at least several controls. Usually there would be at least one button. We’ll add more controls later in this series, but for now we’ll just stick with a single label.

We might want to change the font used by the form. In order to change the font, we need to create a new font object with the appropriate properties and assign the new font object to the form’s Font property.

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

$Font = New-Object System.Drawing.Font("Times New Roman",18,[System.Drawing.FontStyle]::Italic)

# Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

clip_image003

 

Now we have a bit of a problem because the text is too large to fit on the form in its default size. There are a few different ways we could address this:

·         Specify a form size – we could set a particular height and width that would be large enough. This would work, but it’s somewhat difficult to figure out what the appropriate size should be.

$Form.Width = 500

$Form.Height = 200

 

clip_image004

·         Enable scroll bars – By enabling AutoScroll, we allow the user to scroll over to see the remaining text. This is obviously not an optimum solution, but scroll bars are probably a good idea when necessary.

$Form.AutoScroll = $True

clip_image005

·         Enable AutoSize – This is a much better idea for our purposes.  By enabling AutoSize on the form, it will automatically resize to accommodate whatever controls we add to it.

 

$Form.AutoSize = $True

$Form.AutoSizeMode = "GrowAndShrink"

    # or GrowOnly

 

However, you should know that enabling AutoSize in this way will prevent the user from manually resizing the form.  The strategy you choose will depend on your specific requirements.

Here is the new form code:

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

 

Form.AutoScroll = $True

$Form.AutoSize = $True

$Form.AutoSizeMode = "GrowAndShrink"

    # or GrowOnly

 

Font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Italic)

    # Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

 

clip_image006

It’s looking better.  Now let’s keep going.

Window Settings

There are a number of window settings we can customize for our form.  Here we’ll experiment with the following:

·         Disabling the minimize and maximize functionality

·         Setting the window state to normal (versus maximized or minimized)

·         Hiding the size grip (usually in the lower right corner of the window)

·         Setting the opacity to 70%, making the window partially transparent

·         Setting the window start position so that the window will open in the middle of the visible screen

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

Form.AutoScroll = $True

$Form.AutoSize = $True

$Form.AutoSizeMode = "GrowAndShrink"

    # or GrowOnly

 

$Form.MinimizeBox = $False

$Form.MaximizeBox = $False

$Form.WindowState = "Normal"

    # Maximized, Minimized, Normal

$Form.SizeGripStyle = "Hide"

    # Auto, Hide, Show

$Form.ShowInTaskbar = $False

$Form.Opacity = 0.7

    # 1.0 is fully opaque; 0.0 is invisible

$Form.StartPosition = "CenterScreen"

    # CenterScreen, Manual, WindowsDefaultLocation, WindowsDefaultBounds, CenterParent

 

Font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Italic)

    # Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

 

clip_image007

Note – I’ve positioned this form over the well-known sample image penguins.jpg to demonstrate that the form is 30% transparent.

Visual Stimulation

Note – for this section, we’ll revert the window settings changes we made to the form in the previous section.

There are a few things we can do to make our form pop visually.  The easiest way to change the look and feed is to change the background color of the form.

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

$Form.AutoSize = $True

$Form.AutoSizeMode = "GrowAndShrink"

    # or GrowOnly

 

$Form.BackColor = "Lime"

    # color names are static properties of System.Drawing.Color

    # you can also use ARGB values, such as "#FFFFEBCD"

 

$Font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Italic)

    # Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

 

clip_image008

Hmmm, interesting, but maybe not quite what we were looking for.

Let’s try adding a visually pleasing background image for our form.  In order to do that, we need to do the following:

·         Create a new system.drawing.image object from an image file (in this the sample picture “Oryx Antelope.jpg) and assign it to the BackgroundImage property of the form

·         Set the BackgroundImageLayout to None (The default is Tile, which tiles the image across the form as many times as it will fit.)

·         Remove the AutoSize feature from the form and instead set the size of the form to mage the image dimensions.

·         Configure the label so that it’s background is transparent, so as not to obstruct the picture

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

 

$Image = [system.drawing.image]::FromFile("$($Env:Public)\Pictures\Sample Pictures\Oryx Antelope.jpg")

$Form.BackgroundImage = $Image

$Form.BackgroundImageLayout = "None"

    # None, Tile, Center, Stretch, Zoom

 

$Form.Width = $Image.Width

$Form.Height = $Image.Height

 

$Font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Italic)

    # Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

 

$Label.BackColor = "Transparent"

 

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

 

clip_image010

Very nice.

Finishing Touch

One last thing we can do to refine our form is to add a customized icon.  We can load an icon from an image file (in this case GRAPH.ICO which is part of Office).  A good resource for creating custom icon files is http://www.xiconeditor.com/. 

$Icon = New-Object system.drawing.icon ("C:\Program Files\Microsoft Office\Office14\GRAPH.ICO")

$Form.Icon = $Icon

 

clip_image011

Alternatively, we can extract an icon from an associated file, such as PowerShell.exe.

Add-Type -AssemblyName System.Windows.Forms

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

$Form.Text = "Sample Form"

 

$Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell.exe")

$Form.Icon = $Icon

 

$Image = [system.drawing.image]::FromFile("$($Env:Public)\Pictures\Sample Pictures\Oryx Antelope.jpg")

$Form.BackgroundImage = $Image

$Form.BackgroundImageLayout = "None"

    # None, Tile, Center, Stretch, Zoom

$Form.Width = $Image.Width

$Form.Height = $Image.Height

$Font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Italic)

    # Font styles are: Regular, Bold, Italic, Underline, Strikeout

$Form.Font = $Font

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

$Label.Text = "This form is very simple."

$Label.BackColor = "Transparent"

$Label.AutoSize = $True

$Form.Controls.Add($Label)

$Form.ShowDialog()

 

 

clip_image012

Beautiful. 

So we’ve seen most of the commonly used functionality of Windows Forms.  For more esoteric customization, start with http://msdn.microsoft.com/en-us/library/system.windows.forms.form.aspx.

Stay tuned for the next part in this series, which will dive into form controls.


Comments (29)

  1. LA Richards says:

    I like your introduction but…uhm, are you going to post a second part?  'Cause that would be really sweet.

  2. Anonymous says:

    I must ask with everyone else, when will we see part 2? This first part has made the intial drawing of the form so much easier for me. I'd like to see how much easier you can make handling buttons, boxes, and eventhandlers. Thanks for this.

  3. I continually reference this article, thank you! I know there are tools out there that do a lot of the heavy lifting with PowerShell forms, but I’m still a notepad guy.

  4. RobSampson says:

    Hi, this has been a great tutorial on quickly learning how to get started with forms.  It's a lot easier than I had imaged.

    To address a few of the other questions, you can prevent resizing of the form by setting the BorderStyle property of the form:

    msdn.microsoft.com/…/hw8kes41.aspx

    to something like FixedDialog by using

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

    See here for other BorderStyle values:

    msdn.microsoft.com/…/system.windows.forms.form.formborderstyle.aspx

    You can also see the example here for a good introduction to adding other controls:

    technet.microsoft.com/…/ff730941.aspx

    And to go a bit further and use a GUI to create the forms, look at the MS guide on using PrimalScript here:

    blogs.technet.com/…/hey-scripting-guy-march-1-2010.aspx

  5. Bijesh780 says:

    Awesome ! Awaiting for the second Part

  6. Anonymous says:

    Very well explained! Wonder if there is a way to have multiple text boxes in a single form?

  7. RobSampson says:

    Hi form controls.
    There is an article here that demonstrates the TabControl and it’s code requirements:
    https://gigadom.wordpress.com/2012/04/24/powershell-gui-adding-bells-whistles/

    Search for $tabControl and $tabPage to get an idea of how they are implemented.

  8. mike says:

    Yes, come on Steph – tell us. Obviously, these examples are great, but real simple. The first thing all my users do is resize the screen. How can youcapture the resize event. 'Autogrow' is great for a basic 1 box popup, but what about the classic '2×2 boxes, 3×1 buttons in the right hand corner' type form that don't all fall over each other when the screen resizes? Is it even possble or am I now in the realms of building in C# then importing to PS?

  9. shawn says:

    This is a fantastic introduction to PS forms, Stephanie.  I really hope you choose to continue developing this series, and I eagerly await the next installment.  Thanks for the great work!

  10. Thx for your guide line

    would you please tell more about how can i have textbox

  11. hi says:

    This is really nice introduction..

    and wonderful initiative…

  12. Alain says:

    Wonderfull, it's exactly what I was looking for.

    What a about a second part ?

  13. Aakanksha says:

    Great work.. Making things look so simple..

  14. Dhandapani says:

    Please post the second part!!!!

  15. Mark says:

    Please post Part 2…

  16. Reader says:

    Hi Stephanie

    Your tutorial is very interesting and useful. Should we expect a Part 2?

  17. ML49448 says:

    I do was hoping that Stephanie would have a part 2 and beyond to this series, but her TechNet profile has not contributed anything new since this post it seems. MIA!

    I’ve actually had great success using Sapien’s PowerShell Studio on a trial basis to easily drag and drop some elements on to a form, purely to see what each object is called (combobox, richtext, label etc) and what you can customise with it.

  18. Jordan says:

    Awesome tutorial! A job well done.

  19. tom says:

    How’s that second part coming along….

    Yeah =/

  20. form controls says:

    The form I am creating will have several panels with a number of buttons and other controls on them. What I need is a way to change the visibility of those panels. I have tried changing the visibility property as well as the opacity property ti no avail.

    Any help here will be greatly appreciated.

    Code sample:

    $frmMain.WindowState = $iniState
    $iniState = $frmMain.WindowState
    $frmMain.add_Load($OnLoadForm_StateCorrection)
    $frmMain.ShowDialog()| Out-Null

    Start-Sleep -Seconds 5
    $pnlMain.opacity = 0.0
    Start-Sleep -Seconds 5
    $pnlMain.opacity = 1.0

  21. An-kun says:

    Just have to mention the now free tool Admin Script Editor. It’s not being developed further anymore, but it is still a really great tool for building a form/gui. You can find it on the itninja website.

  22. KellyK says:

    So to add buttons:

    # LOAD WINDOWS FORMS
    # Load the Winforms assembly
    [reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")

    # CREATE FORM
    $form = New-Object Windows.Forms.Form

    #SET FORM TITLE
    $form.text = "My Test Form"

    # LABEL
    # Create the label control and set text, size and location
    $label = New-Object Windows.Forms.Label
    $label.Location = New-Object Drawing.Point 50,30
    $label.Size = New-Object Drawing.Point 250,30
    $label.text = "Enter your name and click the button"

    # TEXTBOX
    # Create TextBox and set text, size and location
    $textfield = New-Object Windows.Forms.TextBox
    $textfield.Location = New-Object Drawing.Point 50,60
    $textfield.Size = New-Object Drawing.Point 210,15

    # BUTTON
    # Create Button and set text and location
    $button = New-Object Windows.Forms.Button
    $button.text = "Name"
    $button.Location = New-Object Drawing.Point 100,100

    # INPUT HANDLER BUTTON – ON CLICK IN THIS CASE
    # Set up event handler to exit
    $button.add_click({
    $label.Text = "Hello " + $textfield.text
    })

    # CANCEL BUTTON
    # Create Button and set text and location
    $button2 = New-Object Windows.Forms.Button
    $button2.text = "Cancel"
    $button2.Location = New-Object Drawing.Point 100,130

    # INPUT HANDLER CANCEL BUTTON – CLOSE APP
    # close button – on click close app
    $button2.add_click({
    $form.Close()
    })

    # ADD CONTROLS TO FORM
    $form.controls.add($button)
    $form.controls.add($button2)
    $form.controls.add($label)
    $form.controls.add($textfield)

    # DISPLAY DIALOG
    $form.ShowDialog()

  23. looping through content to display in the form says:

    I’ve created a powershell script that reads a text file (get-content), then displays to the host (write-host) one word at a time with a start-sleep time determined by the user.
    I’d like to achieve the same thing with a Windows form using the code here. How can I loop the $label.text ? I dont want to redraw the form every time, just update the label.text

  24. Marc says:

    Fantastic,
    I learned a lot from this,
    Wrote my first Powershell Form in a few hours

    Thanks a lot

    $x = ""
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

    $objForm = New-Object System.Windows.Forms.Form
    $objForm.Text = "Data Entry Form"
    $objForm.Size = New-Object System.Drawing.Size(300,200)
    $objForm.FormBorderStyle = "FixedDialog"
    $objForm.StartPosition = "CenterScreen"
    $objForm.MinimizeBox = $False
    $objForm.MaximizeBox = $False
    #$objform.ControlBox = $false
    $objForm.WindowState = "Normal"
    # Maximized, Minimized, Normal
    $objForm.SizeGripStyle = "Hide"
    # Auto, Hide, Show
    $objForm.ShowInTaskbar = $False

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
    {$x=$objTextBox.Text;$objForm.Close()}})

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20)
    $objLabel.Size = New-Object System.Drawing.Size(280,20)
    $objLabel.Text = "Please enter your name here"
    $objLabel.ForeColor = "red"

    $objLabel2 = New-Object System.Windows.Forms.Label
    $objLabel2.Location = New-Object System.Drawing.Size(10,40)
    $objLabel2.Size = New-Object System.Drawing.Size(280,20)
    $objLabel2.Text = "Please enter your name here"
    $objLabel2.ForeColor = "blue"

    $objLabel3 = New-Object System.Windows.Forms.Label
    $objLabel3.Location = New-Object System.Drawing.Size(10,60)
    $objLabel3.Size = New-Object System.Drawing.Size(280,20)
    $objLabel3.Text = "Please enter your name here"
    $objLabel3.ForeColor = "green"

    $objForm.Controls.Add($objLabel)
    $objForm.Controls.Add($objLabel2)
    $objForm.Controls.Add($objLabel3)

    $objTextBox = New-Object System.Windows.Forms.TextBox
    $objTextBox.Location = New-Object System.Drawing.Size(10,80)
    $objTextBox.Size = New-Object System.Drawing.Size(260,20)
    $objForm.Controls.Add($objTextBox)

    $objForm.Topmost = $True

    $objForm.Add_Shown({$objForm.Activate(); $objTextBox.focus()})
    [void] $objForm.ShowDialog()
    $x
    if ($x -ne "")
    {$x | Out-File -append c:Usersmarc.MARCDocumentspersonaltasknaam.txt}
    else {C:Usersmarc.MARCDocumentspersonaltasktest.exe}

  25. State says:

    really I am happy.

  26. State says:

    how can i found second part

  27. State says:

    how can i found second part

  28. Jon says:

    In case anyone was wondering how to position new objects on the form, I found this works well:

    $button_1.Location = [System.Drawing.Point]::new($myform.Location.X + 50,$myform.Location.Y + 50)

    Hope this helps!

  29. EnjoysScripting says:

    Yes, but you can also use e.g.

    $buttonname.anchor = "left", "top"

    to align the button when forms or other objects change size

Skip to main content