---
title: "Create WPF PowerShell GUIs: Functions, Inputs, and Results"
description: "Build and import a basic WPF PowerShell GUI with functions that accept input and return results."
canonical: "https://adamtheautomator.com/powershell-gui/"
---

# Create WPF PowerShell GUIs: Functions, Inputs, and Results

> Build and import a basic WPF PowerShell GUI with functions that accept input and return results.

Source: https://adamtheautomator.com/powershell-gui/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Create WPF PowerShell GUIs: Functions, Inputs, and Results](https://adamtheautomator.com/wp-content/uploads/2019/08/gui-2311261_1280.png)

# Create WPF PowerShell GUIs: Functions, Inputs, and Results

[![](https://secure.gravatar.com/avatar/9a14f10ff1b1ec7d790d34f5b559e4d3de2d31b172e6ef266dfd8b479174d97b?s=192&d=mm&r=g)June Castillote](https://adamtheautomator.com/author/june/)26 August 20198 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Prerequisites](#prerequisites)
*   [Building the Script](#build-the-script)
*   [Writing the Function](#the-function)
*   [Importing the Code (Dot Sourcing)](#h-importing-the-code-dot-sourcing)
*   [Building the PowerShell GUI](#build-the-gui)
*   [Designing the PowerShell GUI Form](#h-designing-the-powershell-gui-form)
*   [Combining the Script and the PowerShell GUI](#combine-the-script-and-the-gui)
*   [Adding the Button Click Event Code](#add-the-button-click-event-code)
*   [Testing the Finished PowerShell GUI](#finished-code)
*   [Summary](#summary)
*   [Further Reading](#further-reading)

PowerShell is a command-line tool but did you know it can also be used as a base for graphical interfaces? Sometimes command-line isn’t the best kind of interface for a particular instance. Building a PowerShell GUI for your service desk is a great example. This is one of those times when it is more appropriate to build graphical tools instead.

Not a reader? Watch this related video.

**_Not seeing the video? Make sure your ad blocker is disabled._**

> _Enforce end-user verification when resetting passwords at the helpdesk. Reduce your social engineering vulnerability with Specops Secure Service Desk. [Contact us for a Demo!](https://specopssoft.com/contact-us/?utm_source=ata&utm_medium=referral&utm_campaign=na_ata&utm_content=mention)_

PowerShell can use and expose .NET functionality and features. As a result, it is possible to write GUI front ends for the scripts you create. Building PowerShell GUIs may seem complicated, especially if you are a beginner.

But if you have basic experience with PowerShell scripting then there’s no reason for you not to learn and adapt the practice of creating GUI for your scripts.

In this post, you will learn how to [create a PowerShell](https://adamtheautomator.com/teams-webhooks/) GUI using the Windows Presentation Framework (WPF).

## Prerequisites

Before you dive in, please be sure you meet the following requirements:

1.  **Visual Studio 2017 or later** – You’ll use this to create the graphical user interface using WPF. You can download a [free/community version](https://visualstudio.microsoft.com/vs/community/).
2.  **A script editor** – I use [Visual Studio Code](https://code.visualstudio.com/download), but you can also use another text editor of your choice. Some other options are [Notepad++](https://notepad-plus-plus.org/downloads/) and the built-in PowerShell ISE
3.  **A Windows 10 computer with Windows PowerShell 5.1**.

## Building the Script

In this post, you’ll create a simple script named _Main.ps1._ In the script, you’ll write code that will pull disk information from a local or remote system by querying the _Win32\_LogicalDisk_ WMI class.

You’ll need a script to wrap a GUI around first. I’ve chosen to use a script that allows you to provide a computer name and query disk information. This is, by no means, necessary to build a GUI though. Use the techniques you learn in this post to adapt your GUIs to your own scripts.

As an example script, I’ll create a function that performs the following actions:

1.  Accept input for the name of the computer to query
2.  Query the computer and store the fixed disks information to a variable
3.  Return the results

### Writing the Function

Below is the function you’ll use for this project, aptly named `Get-FixedDisk`. This project’s purpose is to get the information about the non-removable or _fixed disks_ on the target machine.

While this piece of code can be used as is, creating a GUI would be beneficial if you just want to perform a quick query without having to dot source the function and manually typing in the commands each time.

```powershell
Function Get-FixedDisk {
    [CmdletBinding()]
    # This param() block indicates the start of parameters declaration
    param (
        <# 
            This parameter accepts the name of the target computer.
            It is also set to mandatory so that the function does not execute without specifying the value.
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        WMI query command which gets the list of all logical disks and saves the results to a variable named $DiskInfo
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
   $DiskInfo
}
```

You can see that I’ve added a _param()_ block in the code. This is to instruct the function to accept inputs based on the type of data indicated.

In the example, I’ve added a `Computer` parameter which accepts a string value. Also, by adding the `Mandatory` parameter attribute, it ensures that the function does not run if the `Computer` parameter is not specified at runtime.

Next, _line 18_ shows the actual WMI query command which gets the list of all logical disks and saves the results to a variable named `$DiskInfo`. I’ve also added a filter to get only the disks with `DriveType=3`. This filter ensures that only the information about local fixed disks is displayed.

### Importing the Code (Dot Sourcing)

At this point, you now have a working script and are ready to test it. But before you can test the script, you need to import the code into a PowerShell session. One way of loading code into a PowerShell session is by _[dot sourcing](https://mcpmag.com/articles/2017/02/02/exploring-dot-sourcing-in-powershell.aspx)_.

To dot source a script, type a dot (`.`) and a space before the script path. If the script were in the _C:\\PoshGUI-sample_ folder, you could dot source it like below.

```powershell
PS C:\PoshGUI-sample> . .\Main.ps1
```

You can also specify the full path if you’re no in the current working directory. In the example code below, you can see the full path of the script.

```powershell
PS C:>. C:\PoshGUI-sample\Main.ps1
```

Now that we have imported the code into the memory, we can proceed with testing the function we’ve created. In the below example, it shows that the `Get-FixedDisk` function is used to query the computer _poshLabExc_.

```powershell
PS51> Get-FixedDisk -Computer poshLabExc

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 53037772800
Size         : 135838822400
VolumeName   : Windows

DeviceID     : D:
DriveType    : 3
ProviderName :
FreeSpace    : 14872641536
Size         : 17178750976
VolumeName   : Temporary Storage

DeviceID     : E:
DriveType    : 3
ProviderName :
FreeSpace    : 488202240
Size         : 524283904
VolumeName   : System Reserved
```

## Building the PowerShell GUI

At this point, you’ve created the script file named _Main.ps1_, and inside the script created the function `Get-FixedDisk`. You were also able to test and confirm that the function is working.

Now that you know that the script works, you can start building the GUI.

### Designing the PowerShell GUI Form

First plan how you’d like the GUI to look and the elements you’d like to use. For this simple example, our GUI will have:

*   a text box where the computer name can be entered
*   a button to execute the function
*   a text box where we can display the results

Next, you can begin building it!

To start creating the GUI, open up Visual Studio and create a new project.

Once Visual Studio is open, click on _File_ (**1**) –> _New_ (**2**) –> Project (**3**).

![Creating a new Visual Studio project](/wp-content/uploads/2019/08/powershell-gui1.png "image_tooltip")

Creating a new Visual Studio project

Under the _New Project_ window, choose _Visual C# (**1**),_ select _WPF App (.NET Framework) (**2**)_, change the name to _PoshGUI-sample (**3**)_ and click _OK_.

![Choosing a Visual Studio project](/wp-content/uploads/2019/08/visual-studio.png "image_tooltip")

Choosing a Visual Studio project

Once the project is created, a blank form will be presented with the name of _MainWindow.xaml_.

![Visual Studio MainWindow.xaml](/wp-content/uploads/2019/08/mainwindow-xaml.png "image_tooltip")

Visual Studio MainWindow.xaml

You now need to format this form to fit our requirements. Below are the controls and format that you’ll need to add.

*   Window
    *   Title: Disk Information
    *   Height: 326
    *   Width: 403
*   Controls (4)
    *   Label
        *   Content: “Computer Name:”
        *   Margin: 10, 10, 0, 0
    *   TextBox
        *   Name: txtComputer
        *   Text: “”
        *   Height: 23
        *   Width: 174
    *   Button
        *   Name: btnQuery
        *   Content: Query
        *   Margin: 0, 13, 12, 0
    *   TextBox
        *   Name: txtResults
        *   Text: “”
        *   IsReadOnly: True
        *   Margin: 10, 60, 0, 0
        *   Height: 225
        *   Width: 373

The final appearance of the form should be similar to what is shown in the image below. You can rearrange the layout of your window differently. Be creative!

![PowerShell GUI Template](/wp-content/uploads/2019/08/example-gui.png "image_tooltip")

PowerShell GUI Template

### Combining the Script and the PowerShell GUI

Once you are happy with your design, you can now start integrating it with the script.

PowerShell cannot display forms natively. To be able to display the form, we need to add a line of code to the very top of our script to support rendering of the WPF Form.

```powershell
Add-Type -AssemblyName PresentationFramework
```

Then add code to perform the following actions:

1.  Import and read the XAML code of the form.
2.  Dynamically create variables assigned to each named controls
3.  Display the form

Below is the updated code inside your script.

> _Note: Make sure to modify the line `$xamlFile` and point it to the full path of your MainWindow.xaml file._

```powershell
Add-Type -AssemblyName PresentationFramework

Function Get-FixedDisk {
    [CmdletBinding()]
    # This param() block indicates the start of parameters declaration
    param (
        <# 
            This parameter accepts the name of the target computer.
            It is also set to mandatory so that the function does not execute without specifying the value.
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        WMI query command which gets the list of all logical disks and saves the results to a variable named $DiskInfo
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
    $DiskInfo
}

# where is the XAML file?
$xamlFile = "C:\PoshGUI-sample\MainWindow.xaml"

#create window
$inputXML = Get-Content $xamlFile -Raw
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
[XML]$XAML = $inputXML

#Read XAML
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try {
    $window = [Windows.Markup.XamlReader]::Load( $reader )
} catch {
    Write-Warning $_.Exception
    throw
}

# Create variables based on form control names.
# Variable will be named as 'var_<control name>'

$xaml.SelectNodes("//*[@Name]") | ForEach-Object {
    #"trying item $($_.Name)"
    try {
        Set-Variable -Name "var_$($_.Name)" -Value $window.FindName($_.Name) -ErrorAction Stop
    } catch {
        throw
    }
}
Get-Variable var_*

$Null = $window.ShowDialog()
```

> _Note: `$Null = $window.ShowDialog()` must always be the last line of code inside your script._

When you run this code by executing the _Main.ps1_ script, you should see the example output below.

![PowerShell GUI variable and field mappings](/wp-content/uploads/2019/08/gui-to-variables.png "image_tooltip")

PowerShell GUI variable and field mappings

As you can see, the three named controls were assigned their variables. These variable names will be referenced later on in the script when we add the control logic code.

*   var\_btnQuery
*   var\_btnComputer
*   var\_txtResults

Bear in mind that the script at this point can only display the form, but the controls are useless since you haven’t added the code yet.

### Adding the Button Click Event Code

Now that you’ve successfully modified the script to import and display the GUI, begin adding the code to the controls to retrieve and display the disk information data.

In this project, only the `btnQuery` button will be assigned an action. The other controls will only serve as input and output/display controls. This means that we only need to add a _click_ event code to `btnQuery`.

To add the _click_ action to `btnQuery`, assign the code below to its corresponding variable name `$var_btnQuery`. Copy the code below and insert it in between the `Get-Variable var_*` and `$Null = $window.ShowDialog()` code references in the script.

```powershell
$var_btnQuery.Add_Click( {
   #clear the result box
   $var_txtResults.Text = ""
       if ($result = Get-FixedDisk -Computer $var_txtComputer.Text) {
           foreach ($item in $result) {
               $var_txtResults.Text = $var_txtResults.Text + "DeviceID: $($item.DeviceID)`n"
               $var_txtResults.Text = $var_txtResults.Text + "VolumeName: $($item.VolumeName)`n"
               $var_txtResults.Text = $var_txtResults.Text + "FreeSpace: $($item.FreeSpace)`n"
               $var_txtResults.Text = $var_txtResults.Text + "Size: $($item.Size)`n`n"
           }
       }       
   })

$var_txtComputer.Text = $env:COMPUTERNAME
```

## Testing the Finished PowerShell GUI

With all parts covered, below is the completed code for our script which incorporates the function and the PowerShell GUI that we’ve designed.

```powershell
Add-Type -AssemblyName PresentationFramework

Function Get-FixedDisk {
    [CmdletBinding()]
    # This param() block indicates the start of parameters declaration
    param (
        <# 
            This parameter accepts the name of the target computer.
            It is also set to mandatory so that the function does not execute without specifying the value.
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        WMI query command which gets the list of all logical disks and saves the results to a variable named $DiskInfo
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
   $DiskInfo
}

#where is the XAML file?
$xamlFile = "C:\Users\june\source\repos\PoshGUI-sample\PoshGUI-sample\MainWindow.xaml"

#create window
$inputXML = Get-Content $xamlFile -Raw
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
[xml]$XAML = $inputXML
#Read XAML

$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try {
    $window = [Windows.Markup.XamlReader]::Load( $reader )
}
catch {
    Write-Warning $_.Exception
    throw
}

#Create variables based on form control names.
#Variable will be named as 'var_<control name>'

$xaml.SelectNodes("//*[@Name]") | ForEach-Object {
    #"trying item $($_.Name)";
    try {
        Set-Variable -Name "var_$($_.Name)" -Value $window.FindName($_.Name) -ErrorAction Stop
    } catch {
        throw
   }
}

Get-Variable var_*

$var_btnQuery.Add_Click( {
   #clear the result box
   $var_txtResults.Text = ""
       if ($result = Get-FixedDisk -Computer $var_txtComputer.Text) {
           foreach ($item in $result) {
               $var_txtResults.Text = $var_txtResults.Text + "DeviceID: $($item.DeviceID)`n"
               $var_txtResults.Text = $var_txtResults.Text + "VolumeName: $($item.VolumeName)`n"
               $var_txtResults.Text = $var_txtResults.Text + "FreeSpace: $($item.FreeSpace)`n"
               $var_txtResults.Text = $var_txtResults.Text + "Size: $($item.Size)`n`n"
           }
       }       
   })

$var_txtComputer.Text = $env:COMPUTERNAME
$Null = $window.ShowDialog()
```

As you can see below, after calling the script in PowerShell, the PowerShell GUI windows appeared. Then you’re able to enter a valid computer name to test the functionality.

![PowerShell GUI Example Result](/wp-content/uploads/2019/08/powershell-gui-example.png "image_tooltip")

PowerShell GUI Example Result

> _Securely verify callers with authentication methods that remove the opportunity for user impersonation. Block helpdesk hackers with Specops Secure Service Desk. [Try i](https://specopssoft.com/product/secure-service-desk/?utm_source=ata&utm_medium=referral&utm_campaign=na_2023_ata&utm_content=mention)[t](https://specopssoft.com/contact-us/?utm_source=ata&utm_medium=referral&utm_campaign=na_ata&utm_content=mention) [Free!](https://specopssoft.com/product/secure-service-desk/?utm_source=ata&utm_medium=referral&utm_campaign=na_2023_ata&utm_content=mention)_

## Summary

In this article, you learned how to create a simple function that accepts input and return results. You also learned how to create a basic WPF PowerShell GUI as well as how to import it to act as a front-end for the PowerShell script you created.

This is just a basic script and GUI combination. Numerous improvements can be done such as:

*   Formatting the size and free space to display as GB values.
*   Change the name of the property displayed.
*   Use _GridView_ instead of _TextBox_ to show the results.
*   Add an import button to _[loop through a list of servers from a CSV file](https://adamtheautomator.com/import-csv-and-the-foreach-loop/)_.

It is up to you to modify and add functionality based on your requirements.

## Further Reading

*   **_[WMI Win32\_LogicalDisk class](https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logicaldisk)_**
*   **_[PowerShell Dot Sourcing](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-5.1#script-scope-and-dot-sourcing)_**
*   _**[Windows Presentation Foundation](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/?view=netdesktop-6.0&viewFallbackFrom=netdesktop-6.0%2F)**_
*   _**[Using WMI in PowerShell](https://adamtheautomator.com/powershell-wmi/)**_

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-gui%2F&text=Create%20WPF%20PowerShell%20GUIs%3A%20Functions%2C%20Inputs%2C%20and%20Results)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-gui%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-gui%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
