Building a user interface (UI) in PowerShell may sound like a difficult process and you may not even know where to begin to accomplish something like this. Luckily, there are a few choices on what you can use to create a simple or complex UI that can be handed off to an individual to use with little to no effort. Whether you use WinForms of WPF as your building block for your UI, you still have more options with each to help build a nice UI. For the sake of this series of articles, I am going to be focusing on WPF and will show some of the controls that you can use to build a nice application for others to use.
With WPF, you have options on what you want to use to build out the interface. ShowUI, XAML and .Net are the most common ways to accomplish this. Each has its own strengths to use, but I personally usually stick with using XAML and sometimes use .Net to build dynamic controls on the fly if needed. But whatever path you choose is completely up to you as either of these ways will get you to your goal.
My goal with this is to start from the beginning and try to cover some basics of working with WPF and PowerShell over time. This is by no means a comprehensive all in one WPF guide. That would take up too much time and there are many things that I still do not know at this time. With that, this means that am I an expert at this (I’m an ITPro, not Dev ) but I have been able to build a few UI’s (PoshPAIG, PoshChat, Profile Removal, etc…) and want to share my knowledge with others and also provide a reference for myself in the process!
XAML or .Net?
Both actually! I won’t actually show both ways to accomplish the same task, but I will start out with the XAML approach and make updates to the existing object using PowerShell/.Net.
Loading the XAML With PowerShell
In every initial example, you will see me take the XAML code and plug it into PowerShell to display. In order to do this, I need to cast the data as xml using [xml] and then loading up the xml into PowerShell using System.Xml.XmlNodeReader and [Windows.Markup.XamlReader]::Load.
#Build the GUI [xml]$xaml = @" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen" Width = "800" Height = "600" ShowInTaskbar = "True"> </Window> "@ $reader=(New-Object System.Xml.XmlNodeReader $xaml) $Window=[Windows.Markup.XamlReader]::Load( $reader )
The Initial Window
This really is the starting point for most of your WPF UIs. The Window itself. I will be using the same code as above to demonstrate the initial Window. After which, I will rely on using Powershell to adjust or add various things to the existing object. You can find a plethora of information here on the msdn page.
Because this is going to be a generic Window with nothing spectacular, I will make the Width 800 and the Height 600 while starting the window up in the Center screen by setting WindowStartupLocation to ‘CenterScreen’. I also chose the name the Window as ‘Windows’ which is done in XAML by specifying x:Name = ‘Window’. And yes, when you are working in XAML, the properties are Case Sensitive! After loading up the code into PowerShell as an object, you can start the Window up by using the ShowDialog() method. Do not use Show() unless you want to lock up your console or ISE!
So lets go ahead and check out this exciting Window!
$Window.ShowDialog()
As you can see, nothing that groundbreaking. The window did come up in the center screen along with the size being what I set. The title also shows up correctly. You can close the window simply by clicking on the red X. Also, when you close the window, you will see $False appear on the console.
Properties You May Find Useful
Now that we have the window up and running, we can look at few of the properties that you may wish to use to make the window look a little nicer. In case you are wondering why I said a few, it is because there are a ton of properties and many of those will go beyond the scope of what I plan to do here.
ToolTip
A tooltip provides a message to the user simply by hovering the mouse cursor over the object, in this case, the window.
$window.ToolTip = "This is a window. Cool, isn't it?"
Transparency
You can set the Window to be transparent if you’d like. A word of caution is that you will lose your ability to close the Window with the red X. You will need to configure an alternate means of closing the window (see the event for Click To Close later in this article). You will need to set the 3 items posted in the source code below. The Opacity must be a value between 0 and 1.0 in order to work properly
$Window.AllowsTransparency = $True $Window.Opacity = .5 $window.WindowStyle = 'None'
As you can see, it is transparent with no visible way to close it!
Background Color
Setting the background color of your window is simple! Just use the Backgroundcolor property and give it a color!
$Window.Background = 'Green'
Adding Text To Your Window
Besides adding a background color, you can add text to your Window via the Content property. Besides that, you can customize your text using a variety of methods listed below in the code.
$Window.FontSize = 24 $Window.FontStyle = 'Italic' #"Normal", "Italic", or "Oblique $Window.FontWeight = 'Bold' #http://msdn.microsoft.com/en-us/library/system.windows.fontweights $Window.Foreground = 'Red' $Window.Content = "This is a test!"
Events You May Find Useful
Events are designed to fire off when a certain action occurs. Whether it is a timed event that fires on a tick, or a mouse click or even if the Window is closing or opening. You can supply a script block to the action block of the event to perform whatever task it is you need done with the event. Be sure to include all of the events prior to the code that is opening the Window, otherwise you might be left wondering what is going on.
Click To Close
As seen in my demo of a transparent window, there will be a time when you might need an alternate way to close the window. Luckily, that can be done with your mouse just by clicking on the window with either your left or right mouse button and using the $Window object’s Close() method. In this case, I am going to close the Window using the Right mouse button.
$Window.Add_MouseRightButtonDown({ $Window.close() })
Click To Drag
Same issues with using transparency means that you have no real way to move your window around. We get around that by once again using the MouseRight/LeftButton event and then using the DragMove() method.
$Window.Add_MouseRightButtonDown({ $Window.DragMove() })
Actions To Perform On Close
When your window closes, you may need to perform some additional tasks such as saving to a config file, cleanup, etc… Luckily we can use the Closed event with whatever actions that need to be taken to accomplish this.
$Window.Add_Closed({ Write-Verbose "Performing cleanup" })
Actions To Perform On Open
When your Window first opens up, you may need to perform some initializations before presenting everything to the user. For this approach, I typically use the OnLoaded event.
$Window.Add_Loaded({ Write-Verbose "Starting up application" })
Timer Event
Sometimes you need a timer to handle certain actions on each tick. The approach I usually take is to initialize my timer when the window is loaded and then supply the code that that will run on each tick of the timer.
$Window.Add_Loaded({ $timer.Add_Tick({ [Windows.Input.InputEventHandler]{ $Global:Window.UpdateLayout() } #Write-Verbose "Updating Window" }) #Start timer Write-Verbose "Starting Timer" $timer.Start() })
Wrapping Up
That concludes the initial article on WPF and building your first Window. Like I said at the beginning, this is just 1 step on a multi-step process to really create something cool. If you have anything that you would like to see about a specific control that I talk about, feel free to leave something in the comments. If there is something that you would like to see me tackle, let me know and I will see what I can do and hopefully we will learn something new together!
Next WPF Topic
Buttons
Hi.I am total newbby in this. I used to start learning how to make hta files when i found out that that way is dropped and no one is doing anything this way any more. Can anyone explain me how it work. I mean what is the extension of file i put code into?
Does this have to be done in a powershell x86 window? I have created wpf apps in the past using powershell x86, today i copied your initial window code into powershellise x64 and keep getting object reference not set to an instance errors when trying to showdialog
Any chance you have an idea how to handle a XAML that has frames with Page elements?
So If i have this
MainWindow.xaml:
and this
Deployment Settings.xaml:
How do I load MainWindow.xaml and have it load ALL the XAML including the Pages
Thanks!
I love the pure PowerShell approach. I don’t want to learn techniques that will make me dependent on a third-party codebase that might become obsolete or unsupported ever again. (PowerGUI, PrimalScript community edition, etc.)
I’m wondering what that last bit with the timer is supposed to do, though. The code as-written does not seem to work in PowerShell v5:
PS> HelloWorld.ps1
You cannot call a method on a null-valued expression.
At C:\Users\me\HelloWorld.ps1:26 char:5
+ $timer.Add_Tick({
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
VERBOSE: Starting Timer
You cannot call a method on a null-valued expression.
At C:\Users\me\HelloWorld.ps1:32 char:5
+ $timer.Start()
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
VERBOSE: Performing cleanup
False
Interesting. I’ll have to run the code and see what might be going on with it.
Also getting this error in powershell v5 as well
Cant call a method on null valued expression
Missing line before 02. plz insert 01 line
01] $timer = New-Object System.Windows.Threading.DispatcherTimer
02] $timer.Add_Tick({
[Windows.Input.InputEventHandler] {$Global:Window.UpdateLayout()}
Write-Host “Updating Window”
})
Hi Boe!
I like to introduce my Asynchronous WPF GUI work to you.
My example show: How to create a non blocking Graphical User Interface (GUI) with Windows Presentation Foundation (WPF) and how to write Data with PowerShell to GUI controls correctly from a different thread (Runspace) over the Dispatcher.
Take a Look at: http://poshcode.org/6321
Greets
Peter Kriegel
Pingback: Getting started building GUIs for your PowerShell scripts - 4sysops
Hi, This tutorial was my base knowledge when making powershell + wpf application, thanks for this post it gives me a place to start learning it. Right now I am in the middle of creating an application (ps + wpf). I wanna turn my form into Metro theme style which i did when i was using singe xaml page. But how to do it when using resource dictionary? (External xaml source file) Here is my code:
#build the GUI
Clear-host
cd “D:\powershell\Lesson\metro”
Add-Type –assemblyName PresentationFramework
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName WindowsBase
[xml]$xaml = @”
“@
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$Window = [Windows.Markup.XamlReader]::Load($reader)
$Window.ShowDialog()
******i hope someone will email me Lumus_maxima@rocketmail.com
“Unable to find type [Windows.Markup.XamlReader]” – Any thoughts?
Launch Powershell -sta
Add [void][System.Reflection.Assembly]::LoadWithPartialName(‘presentationframework’) before creating the window. I was getting the same error until I performed those steps.
Hey Guys, I found an even easier way to load a XML-String:
$window = [Windows.Markup.XamlReader]::Parse( ([string] @”xamlcontent”@) )
Saves another few lines …
Excellent! Thanks for sharing!
Hello Stefan and hi everyone.
Could you please share an example? I have searched for the shorter version, but nothing found. Anyone?
Thank you
I have a third party application using xaml do open dialog windows. The dialofg windows require to be closed by ok or cancel buttons and can be customized to a large extent eg import xaml code.
BUT i need to close these windows upon external events e.g. a time point.
Can I use Power shell to close such a window :
based on the window tile?
Thanks, Gernot
Pingback: Episode 202 – Antoine Habert talks about PoshBoard « PowerScripting Podcast
Great post Boe. Just this first XAML post has convinced me to take another look at using XAML for some future projects instead of WinForms. Looking forward to see more in this series. When you started learning XAML, did you use a GUI-building app similar to PowerShell Studio for WinForms?
Thanks, Rich! I just starting looking at some other sites on working with XAML or that had examples that I could reference and just started to put things together. I know that you can use Visual Studio where you can build out the UI and then copy the XAML code (with a couple modifications) and start using that in your PowerShell code.
Boe,
Another great post. I too had tried the ShowUI after watching a James Brundage webcast.
The documentation was a little lite – but your explanations are helping to fill in the gaps.
Keep em coming please.
Peter
Thanks Peter! Glad you enjoyed the initial article. I have plans to work with a control in each article and show some basic things with each control.
Thanks for this great article. I already tried ShowUI but find it too difficult to start with. Your tips gave me a good start even for someone with no experience. Could you maybe show how to create a File menu or how to add controls like buttons,radio or check boxes. Thanks in advance.
Hi Gyz. Glad you enjoyed the article! Buttons are next on my list and I will be doing radio and check boxes at some point in the future as well. I will also touch on Menus and will show what I did for a File menu in one of my projects.