PowerShell is an advanced shell with integration of .NET objects. It's more than just a replacement for the older cmd.exe
. It can work with .NET assemblies, process large datasets and even interact with web services.
Because of the .NET assemblies support, it can work with WinForms (or even WPF), making it possible to create scripts with GUIs.
Requirements
This has been tested to work with Windows PowerShell verion 5.1. It's likely going to work with older versions as well, but it's not going to work with the new cross-platform PowerShell (there are no WinForms on Linux/macOS). You can check the version with
Get-Host | Select-Object version
Setting up the environment
Before we can start, let's check a few things.
The first one is the script execution policy. It controls which scripts can be run. By default, Windows blocks execution of all scripts (more on that here). We have to allow it to run local scripts that are not digitally signed. It's possible to do this this either by going through Windows Settings > Updates & Security > For developers, checking the Change execution policy... checkbox and clicking Apply, or just executing
Set-ExecutionPolicy RemoteSigned
from administrator PowerShell.
Another (less important) thing is the code editor. Even though we could just write the entire script directly in PowerShell, it's easier to use a full-featured editor with error checking and syntax highlighting. Windows already comes with PowerShell ISE (Integrated Scripting Environment), but you can use Visual Studio Code with the PowerShell extension.
Writing our script
Let's start!
Importing the assemblies
We have to import both System.Windows.Forms
and System.Drawing
assemblies. It's possible to only include the first one but we also need the 2nd to specify control sizes.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
You can test it by creating a blank form:
$form = New-Object System.Windows.Forms.Form
$form.ShowDialog()
Adding controls
Let's make a "Hello World" form. First, we create a top-level Form
object:
$form = New-Object System.Windows.Forms.Form
$form.Text = "Some form"
$form.Size = New-Object System.Drawing.Size(150, 145)
$form.AutoSize = $true
In PowerShell, objects are created using New-Object
. You can also pass parameters to constructors, similar to the new
keyword in C#. Values are assigned to properties directly. Another difference is using $true
instead of just true
.
Let's add a label and a button:
$lbl1 = New-Object System.Windows.Forms.Label
$lbl1.Text = "Hello World!"
$lbl1.Location = New-Object System.Drawing.Point(30, 20);
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "Close"
$btn.location = New-Object System.Drawing.Point(30, 60);
$btn.DialogResult = [System.Windows.Forms.DialogResult]::OK
The $btn.DialogResult
line tells the form what to return when the button is clicked. You can use this to figure out whether the user clicked OK or Cancel. We also make $btn
the default button and lay controls onto the form:
$form.AcceptButton = $btn
$form.controls.Add($lbl1)
$form.controls.Add($btn)
All that's left is showing the form itself:
$form.ShowDialog()
Event handlers
In our form, $btn
is the default OK button which just terminates the form. But we can use non-terminating event handlers as well. For example, let's make it possible to click on the label:
$lbl1.Add_Click({
[System.Windows.Forms.MessageBox]::Show("Hey!")
})
You can call functions from event handlers as you normally would.
Visual Styles
Something I've noticed with these GUI scripts is that different control styles are used when the script is run from the PowerShell console instead of VSCode. The console uses legacy rendering which falls back to using Windows 95-style controls. We need to enable Visual Styles to fix that:
[System.Windows.Forms.Application]::EnableVisualStyles()
From here on, you can add more controls and event handlers. If you've used C#/VB.NET before you can reuse large parts of that knowledge to create nicer and more powerful scripts.
That's it for now 😉
The full script:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()
$form = New-Object System.Windows.Forms.Form
$form.Text = "Some form"
$form.Size = New-Object System.Drawing.Size(150, 145)
$form.AutoSize = $true
$lbl1 = New-Object System.Windows.Forms.Label
$lbl1.Text = "Hello World!"
$lbl1.Location = New-Object System.Drawing.Point(30, 20);
$lbl1.Add_Click({
[System.Windows.Forms.MessageBox]::Show("Hey!")
})
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "Close"
$btn.location = New-Object System.Drawing.Point(30, 60);
$btn.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $btn
$form.controls.Add($lbl1)
$form.controls.Add($btn)
$Null = $form.ShowDialog()
Top comments (0)