Building WPF GUIs in PowerShell: Beginner’s Guide

This guide walks you through creating a PowerShell GUI with Windows Presentation Foundation. We will examine key differences from Windows Forms, focusing on how WPF uses a grid layout to position GUI elements.

Brien Posey

January 9, 2025

6 Min Read
the words windows presentation foundation across a background of metallic gears

Most of the GUI-based PowerShell scripts I have created rely on Windows Forms. However, Windows Forms has limitations, especially for more advanced GUI designs. In such cases, Windows Presentation Framework is a better choice.

While the Windows Presentation Framework (WPF) isn’t overly complex to learn, its approach to building GUIs differs significantly from Windows Forms. In this guide, I will show you the basics of creating a WPF-based GUI in PowerShell.

WPF vs. Windows Forms

One notable difference between Windows Forms and WPF is how you place GUI items on the window.

Windows Forms' pixel-based coordinates

In Windows Forms, you typically position items using pixel-based coordinates relative to the window’s upper-left corner (exceptions exist). For example, to add a block of text to a Windows Form, you would create a label object and specify its location like this:


$Label = New-Object Windows.Forms.Label
$Label.Text = "Hello World"
$Label.Location = New-Object Drawing.Point(100, 40)

In this code example:

  1. The first line creates the label object.

  2. The second line defines the text to display (i.e., “Hello World”).

  3. The third line specifies the label’s position within the window.

The code positions the label’s top-left corner 100 pixels to the right and 40 pixels below the window’s upper-left corner.

WPF's grid system

Things work a bit differently when using WPF. Rather than using pixel-based coordinates, you generally use a grid system. In other words, you will create a grid within the window. Think of it as a spreadsheet: the grid consists of rows and columns, and you place objects in specific “cells” by referencing their rows and columns. While the grid layout is defined primarily by rows and columns, you can still use pixel values to set the row and column dimensions as needed.

Related:Intro to Microsoft Dialog Boxes in PowerShell

Let’s revisit the previous example where we displayed a text label in a GUI environment. This time, we will use WPF instead of Windows Forms. I will start by showing only the part of the code that defines the label’s location on the window. The rest of the script will come later. Here is the code:


$Label = New-Object System.Windows.Controls.Label 
$Label.Content = "Hello World" 
[System.Windows.Controls.Grid]::SetRow($Label, 0)  [System.Windows.Controls.Grid]::SetColumn($Label, 0)
$Grid.Children.Add($Label)

The first two lines work the same way as the Windows Forms example. The first line creates the label object, and the second line sets the label’s text to “Hello World.”

The third line is where things begin to differ. The Windows Forms example specifies the label’s position using pixel values, where here I define the label’s position using two separate lines of code: one to set the row and another to set the column.

In the WPF code example, you will see that the row command includes the instruction SetRow($Label,0). The SetRow instruction tells PowerShell that we are defining the label’s row (rather than the column). The value inside the parentheses—$Label—indicates the GUI element, and 0 specifies that it should go in the first row of the grid.

Related:How To Use .NET Properties and Methods in PowerShell

Similarly, the subsequent line uses the SetColumn instruction, specifying the column for the label. Again, the values in the parentheses indicate the label ($Label) and the column number. Here, 0 refers to the leftmost column in the grid.

The final line of code adds the $Label element to the grid. The grid is defined earlier within the script.

The Full Script for the WPF Example

Now that I have shown you how to place objects within the grid, let’s take a step back and look at how to create the grid and the rest of the required code.

Here is the complete code:


Add-Type -AssemblyName PresentationFramework

# Create the application window
$Window = New-Object System.Windows.Window
$Window.Width = 800
$Window.Height = 600

# Create the grid
$Grid = New-Object System.Windows.Controls.Grid

# Define 3 rows and 3 columns
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))
$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))

$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))
$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))

# Add a label to Row 0, Column 0
$Label = New-Object System.Windows.Controls.Label
$Label.Content = "Hello World"
[System.Windows.Controls.Grid]::SetRow($Label, 0) 
[System.Windows.Controls.Grid]::SetColumn($Label, 0)
$Grid.Children.Add($Label)

$Window.Content = $Grid
$Window.ShowDialog()

Breakdown of the Script

The first line of code adds the PresentationFramework assembly to the script, allowing us to use the Windows Presentation Framework.

Next, we create the application window. We define a variable called $Window and set it equal to an object of type System.Windows.Window. We then set the window’s width to 800 pixels and its height to 600 pixels.

Following that, we create the grid by defining a variable called $Grid and assigning it to an object of type System.Windows.Controls.Grid.

Related:How To Use PowerShell and WPF To Create Advanced GUIs

The next step in the script configures the grid’s size. Unfortunately, PowerShell doesn’t allow us to specify a 3x3 grid directly. Instead, we must execute a separate command for each row and column we want to create.

To create the row in the grid, we use the following command:

$Grid.RowDefinitions.Add((New-Object System.Windows.Controls.RowDefinition))

This command is repeated three times in the script, creating three rows. Remember, the numbering of grid rows starts from 0, so these lines create Row 0, Row 1, and Row 2.

After setting up the rows, we create the columns. The command to create a column is:

$Grid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition))

We repeat this command for each column we want to add. Since our grid has three columns (Column 0, Column 1, and Column 2), we repeat this line three times.

The next code section creates the label element to display within the grid. It is the same code I covered earlier, so I won’t rehash it. However, note that the label is in Row 0, Column 0.

Wrapping up, the second-to-last line adds the grid to the window. The final line displays the window on the screen. You can see the script output in Figure 1.

screenshot showing the label, containing the words “Hello World,” displayed in the upper-left corner of the powershell gui window

Figure 1. The label, containing the words “Hello World,” is displayed in Row 0, Column 0.

Centering Elements in WPF

What if we want to move the “Hello World” label to the center of the window instead of having it appear in the upper-left corner? To do this, we must modify the SetRow and SetColumn instructions to specify a new location. Since the grid is 3x3, the center position is Row 1, Column 1. Here is how the modified lines of code would look:


[System.Windows.Controls.Grid]::SetRow($Label, 1) 
[System.Windows.Controls.Grid]::SetColumn($Label, 1)

In Figure 2, you will see that while these changes moved the label closer to the center of the window, it is not perfectly centered. That is because the changes we made told PowerShell only the grid position. Even though we selected the center grid position (Row 1, Column 1), the text is shown in the upper-left corner of the designated “cell” within the grid, not its center.

a screenshot showing the

Figure 2. The text now displays in the center grid position.

There are many ways to gain more precise control over the placement of objects within the grid. For example, we can define margins (padding) within the cells or dynamically adjust the size of the rows and columns. I plan to explore these options in a future article.

About the Author

Brien Posey

Brien Posey is a bestselling technology author, a speaker, and a 20X Microsoft MVP. In addition to his ongoing work in IT, Posey has spent the last several years training as a commercial astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space.

https://brienposey.com/

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like