To make your PowerShell scripts more user-friendly, you can add a simple graphical user interface (GUI) to them. This makes it easier for your users to use your scripts without having to learn the PowerShell command line interface.
You can use .NET Framework objects in Windows PowerShell to create graphical elements for your PowerShell scripts. Commonly used libraries are .NET Windows Forms (WinForms) or Windows Presentation Foundation (WPF).
Table of Contents
Create a GUI for PowerShell Script Using the WinForms Class
In this example, we’ll use the WinForms class to build a GUI for a simple PowerShell script, displaying the last password change date of the selected Active Directory user.
Open your PowerShell code editor (use the built-in PowerShell ISE or install VSCode), and create a new .PS1 file.
Create GUI Form with PowerShell
To use WinForms objects, load the .NET System.Windows.Forms class into your PowerShell session.
Add-Type -assembly System.Windows.Forms
Then create the form that will contain the graphical elements:
$main_form = New-Object System.Windows.Forms.Form
Set the form title and size (set its width and height in pixels):
$main_form.Text ='GUI for my PowerShell script' $main_form.Width = 600 $main_form.Height = 400
Enable the AutoSize property to automatically expand the form when elements exceed its boundaries.
$main_form.AutoSize = $true
Now display the form on the screen:
$main_form.ShowDialog()
Run the script (press F5 in your code editor).
Add Control Items to a PowerShell Form
Now add graphical dialog and control elements to your form. Insert the following code before the ShowDialog method.
Add a label to the form (shows custom text):
$Label = New-Object System.Windows.Forms.Label $Label.Text = "AD users" $Label.Location = New-Object System.Drawing.Point(0,10) $Label.AutoSize = $true $main_form.Controls.Add($Label)
The Location property sets the element’s relative position on the form. System.Drawing.Point object used to set two position coordinates: the first horizontal and the second vertical. The origin of the coordinates is in the upper left corner.
A drop-down list is the next element on this form. This list contains user accounts from the Active Directory domain retrieved using the Get-ADuser cmdlet from the PowerShell Active Directory module:
$ComboBox = New-Object System.Windows.Forms.ComboBox $ComboBox.Width = 300 $Users = Get-ADuser -filter * -Properties SamAccountName Foreach ($User in $Users) { $ComboBox.Items.Add($User.SamAccountName); } $ComboBox.Location = New-Object System.Drawing.Point(60,10) $main_form.Controls.Add($ComboBox)
Add two more labels to the form. The first should show a static text, and the second should show the last time that the password for the selected AD user account was changed.
$Label2 = New-Object System.Windows.Forms.Label $Label2.Text = "Last Password Set:" $Label2.Location = New-Object System.Drawing.Point(0,40) $Label2.AutoSize = $true $main_form.Controls.Add($Label2) $Label3 = New-Object System.Windows.Forms.Label $Label3.Text = "" $Label3.Location = New-Object System.Drawing.Point(110,40) $Label3.AutoSize = $true $main_form.Controls.Add($Label3)
Hint. The .Font property allows you to change the font family and size of the UI element:
$Label3.Font = 'Microsoft Sans Serif,14'
Now add the Button element to the form:
$Button = New-Object System.Windows.Forms.Button $Button.Location = New-Object System.Drawing.Size(400,10) $Button.Size = New-Object System.Drawing.Size(120,23) $Button.Text = "Check" $main_form.Controls.Add($Button)
Add Event Handlers to PowerShell Script
You can assign an action to the button click event. After click, the script will query the value of pwdLastSet for the AD user that has been selected in the $ComboBox.
$Button.Add_Click( { $Label3.Text = [datetime]::FromFileTime((Get-ADUser -identity $ComboBox.selectedItem -Properties pwdLastSet).pwdLastSet).ToString('MM dd yy : hh ss') } )
Some of the GUI elements on a form can be hidden using the Visible property.
$Label3.Text.Visible = $false # or $True if you want to show it
Run the PowerShell script. The drop-down list will fill with the AD user account names. When you select the user account in the list and click the Check button, the form will display the time when the user’s password was last changed in Active Directory.
In the same way, you can create the following graphical elements on the form:
- CheckBox — used to list and select multiple options;
- RadioButton — lists items and allows you to select only one;
- TextBox — text dialogue element for user input;
- Label — show text on a form;
- ChekedListBox — shows a list of items with checkboxes (allows to select multiple items);
- DataGridView — is used to display tabular data;
- GroupBox — group form elements together;
- ListBox — contains multiple text elements and allows you to select one or more items;
- TabControl — add tabs to your form;
- ListView — displays a list of items with text and (optionally) an icon;
- TreeView — hierarchical objects view;
- DateTimePicker — allows to select the date and time value;
- TrackBar — scrollable control;
- PictureBox —show a picture on the form;
- ProgressBar — indicates the operation progress;
- HScrollBar — horizontal scroll bar;
- VScrollBar — vertical scroll bar;
- ContextMenu — right-click menus;
- Menu — top menu in your form.
Add Custom Menu GUI in PowerShell Scripts
You can use graphical menus to your PowerShell scripts. We will add some menu items to a previously created PowerShell form with the following simple structure:
- File
- Open
- Save
- Exit
- Help
- About
The following WinForms object types are used to create different menu items:
- MenuStrip – create a horizontal menu on a form;
- ToolStripMenuItem – add menu items;
- ToolStripButton – bind actions (PowerShell functions) to menu items.
Create some new objects for your menu:
$menuMain = New-Object System.Windows.Forms.MenuStrip $mainToolStrip = New-Object System.Windows.Forms.ToolStrip $menuFile = New-Object System.Windows.Forms.ToolStripMenuItem $menuOpen = New-Object System.Windows.Forms.ToolStripMenuItem $menuSave = New-Object System.Windows.Forms.ToolStripMenuItem $menuExit = New-Object System.Windows.Forms.ToolStripMenuItem $menuHelp = New-Object System.Windows.Forms.ToolStripMenuItem $menuAbout = New-Object System.Windows.Forms.ToolStripMenuItem $toolStripOpen = New-Object System.Windows.Forms.ToolStripButton $toolStripSave = New-Object System.Windows.Forms.ToolStripButton $toolStripExit = New-Object System.Windows.Forms.ToolStripButton $toolStripAbout = New-Object System.Windows.Forms.ToolStripButton
Now you need to bind your menu to the GUI form ($main_form):
$main_form.MainMenuStrip = $menuMain $main_form.Controls.Add($menuMain) [void]$mainForm.Controls.Add($mainToolStrip)
Now you can display the first menu:
# Show Menu Bar [void]$main_Form.Controls.Add($menuMain) # Menu: File $menuFile.Text = "File" [void]$menuMain.Items.Add($menuFile)
Then add a drop-down menu item to the File menu:
# Menu: File -> Open $menuOpen.Text = "Open" $menuOpen.Add_Click({OpenFile}) [void]$menuFile.DropDownItems.Add($menuOpen) # Menu: File -> Save $menuSave.Text = "Save" $menuSave.Add_Click({SaveFile}) [void]$menuFile.DropDownItems.Add($menuSave) # Menu: File -> Exit
The Add_Click method used to perform an action when the user clicks a menu item (in this example, when you click the menu, a method is called to close the form and to stop the PowerShell script):
$menuExit.Text = "Exit" $menuExit.Add_Click({$main_Form.Close()}) [void]$menuFile.DropDownItems.Add($menuExit)
Now add the next menu section:
# Menu: Help $menuHelp.Text = "Help" [void]$menuMain.Items.Add($menuHelp) # Menu: Help -> About $menuAbout.Text = "About" $menuAbout.Add_Click({ShowAbout}) [void]$menuHelp.DropDownItems.Add($menuAbout)
Run the PowerShell script. A horizontal menu with nested sub-menu items will be displayed at the top of the form.
Add the handlers for the Click event on the rest menu items (SaveFile, OpenFile, ShowAbout). Let’s define the following PowerShell function for the About menu:
function ShowAbout { [void] [System.Windows.Forms.MessageBox]::Show( “My simple PowerShell GUI script with dialog elements and menus v1.0”, “About script”, “OK”, “Information” ) }
Hint. You can use the PS2EXE module to convert your PS1 PowerShell script file into full-featured EXE applications for the convenience of your users.
1. Install the module from the PowerShell Gallery:
Install-Module ps2exe -Repository PSGallery
2. Convert your PS1 script file into an EXE file:
ps2exe -inputFile “C:\PS\posh_gui.ps1” -outputFile “C:\PS\posh_gui.exe”
Using Standard Windows Dialog Boxes in PowerShell Scripts
To inform the user and prompt them to make a choice, you can use the standard Windows graphical dialogs in PowerShell scripts.
To display a simple modal window with text and buttons, use the MessageBox class. It can be used to notify the user when a task is completed or to get an answer to a simple question.
The message is a mandatory MessageBox attribute. The title, button, and icon are optional.
Show an OK message box:
[void] [System.Windows.MessageBox]::Show( "All changes have been implemented successfully ", "Script completed", "OK", "Information" )
Display a message box that requires a response (Yes/No/Cancel):
$answer = [System.Windows.MessageBox]::Show( "Dou you want to remove this user?", " Removal Confirmation", "YesNoCancel", "Warning" )
Prompt a user for credentials and split it on two variables:
$creds = Get-Credential $UserName $getUsername = $creds.GetNetworkCredential( ).UserName $getPassword = $creds.GetNetworkCredential( ).Password
Show the standarf Windows select file dialog box with a filter by file names:
Add-Type -AssemblyName System.Windows.Forms $initialDirectory = [Environment]::GetFolderPath('Desktop') $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.InitialDirectory = $initialDirectory $OpenFileDialog.Filter = 'Script files (*.ps1;*.cmd;*.bat)|*.ps1;*.bat;*.cmd' $OpenFileDialog.Multiselect = $false $response = $OpenFileDialog.ShowDialog( ) # $response can return OK or Cancel if ( $response -eq 'OK' ) { Write-Host 'You selected the file:' $OpenFileDialog.FileName }
Open the Browse for folder dialog box:
$shell = New-Object -ComObject Shell.Application $selectedfolder = $shell.BrowseForFolder( 0, 'Select a folder to proceed', 16, $shell.NameSpace( 17 ).Self.Path ).Self.Path
Select printer dialog form:
Add-Type -AssemblyName System.Windows.Forms $prntdlg = New-Object System.Windows.Forms.PrintDialog $prntdlg.AllowCurrentPage = $false $prntdlg.AllowPrintToFile = $trur $prntdlg.AllowSelection = $false $prntdlg.AllowSomePages = $true $prntdlg.ShowNetwork = $true $response = $prntdlg.ShowDialog( )# $response can return OK or Cancel if ( $response -eq 'OK' ) { Write-Host 'Selected printer:' $prntdlg.PrinterSettings.PrinterName }
You can use the Out-GridView cmdlet to display any data in the form of a graphical grid that where you can filter and sort it by the criteria you want. For example, the following PowerShell service status check script lists the services that are running on Windows.
The user must select the desired services (multiple lines can be selected by holding down the Ctrl key) and save the selection to a variable.
$Svcs = Get-Service | Where-Object {$_.Status -EQ "Running"}| Out-GridView -Title "List of running services" -PassThru| Select -ExpandProperty Name
Now you can use the list of services selected by the user in the Out-GridView for further processing in your PowerShell script.
Building the GUI for PowerShell Scripts with Visual Studio
You can use Visual Studio with a Windows Presentation Foundation (WPF) as a simple PowerShell GUI builder. Download and install the Visual Studio Community 2022 -> select .Net desktop development as your primary workload.
Run the Microsoft Visual Studio and create a new Project (File > New > Project). Select Visual C# > WPF App (.NET Framework) C#.
Use the Windows Forms element in the left Toolbox pane to place your control element on the form (with drag&drop).
The Visual Studio will generate a XAML code for you. Save this code into the file C:\PS\Script\MainWindow.xaml. Open this file using Notepad and remove the following string:
x:Class="test.MainWindow”
Save the changes in the XAML file.
Now you can read this XAML code from your PowerShell script and display a Windows Form.
Use the following function to load the XAML object:
Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System.Windows.Forms [xml]$XAML = Get-Content "C:\ps\gui\mainwindow.xaml" $XAML.Window.RemoveAttribute('x:Class') $XAML.Window.RemoveAttribute('mc:Ignorable') $XAMLReader = New-Object System.Xml.XmlNodeReader $XAML $MainWindow = [Windows.Markup.XamlReader]::Load($XAMLReader) $XAML.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $MainWindow.FindName($_.Name)}
To display your form run the method:
$xamGUI.ShowDialog()
Now add some event handlers for different form elements. For example, I want a message to appear when I click OK button.
- In the XAML file, set a name for the OK button, for example:
Name="OkButton"
- Add logic to your PowerShell script:
# Define the event handler function OnOkButtonClick { $null = [System.Windows.MessageBox]::Show("Button OK clicked!") } # Add the event handler to the "OK" button $OkButton = $MainWindow.FindName("OkButton") $OkButton.Add_Click({ OnOkButtonClick }) # Show the window $MainWindow.ShowDialog() | Out-Null
Check that the action from the OnOkButtonClick function is now performed when a button is clicked on the form.
6 comments
I have the following script which a Sharepoint page from powershell. I want other users to access it outside the server by proving parameter as required. Is GUI Powershell the best way to do it?
——
$PageLayoutUrl = “/_catalogs/masterpage/BlankWebPartPage.aspx”
$PageName = “Pages/PageSix.aspx”
$pagecontent = [string]$_.PageContent
# Get site object and create publishing site object
$SPSite = Get-SPSite(“http://xx.xxx.xx.xx:6060”)
$PublishingSite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($SPSite)
# Get web object and create publishing web object
$SPWeb = Get-SPWeb “http://xx.xx.xx.xx:6060”
$PublishingWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($SPWeb)
$LayoutsColl = $PublishingSite.GetPageLayouts($False)
# Get the page layout object and create Publishing Page based on it
$SPPageLayout = $LayoutsColl[$PageLayoutUrl]
$Page = $PublishingWeb.AddPublishingPage(“PageSix.aspx”, $SPPageLayout)
$Page.Title = “This is page six”
Write-Host “Creating $pagetitle”
$Page.ListItem[“Page Content”] = “PAGE SIX
TESTING 123 SENTENCE HERE. TESTING 123 SENTENCE HERE. TESTING 123 SENTENCE HERE.
adipiscing elit adipiscing elit adipiscing elit adipiscing elit adipiscing elit
Body page content enter here. Body page content enter here. Body page content enter here. Body page content enter here.
Body page content enter here. Body page content enter here.
Body page content enter here.”
$Page.Update();
$Page.CheckIn(“Page Created”)
$Page.ListItem.File.Publish(“Page Checked in and Publishing Completed”)
Good morning
Firstly can I just say thank you for this post as a complete beginner to this it has been immensely useful and allowed me to create all of my menus for the relatively simple tasks i was looking to do.
I have however tun into what seems in my mind to be a simple thing yet search after search has not revealed an answer for me. I have created a menu in Visual Studio that on the click of a button launches a second menu. The second menu contains a list of buttons that when clicked I want them to launch a pre-written power shell script. What I am failing to find is the command I need to add to teh On-Click function of the button that will launch a Powers hell script by clicking it ?
Excellent and very useful.
But i have a question:
Post adding the components and once form is ready.. can we convert to .exe? All i need is, double click an icon from my desktop and see my form?
Please advise!
Yes. you can use ps2exe. it is pretty simple to use and will work on most powershellscripts.
you can use iexpress, that’s implemented in Windows
I get a blank form and execution seems to be halted.
EDIT: Figured it out, I copy/pasted the show main form command, not cut/pasted!