One of the most important tools for any IT professional or service desk technician that works in a Windows environment is without a doubt Powershell. Not only is it extremely powerful but it is also very fun to work with if you ask me.
One of the great features of Powershell that I feel doesn't get enough love from the Powershell community is the ability to write scripts with graphical user interfaces. Yeah, yeah, I know, you want to be able to do a quick change in the script and then rerun it inside ISE and anyone that doesn't know how to use a console shouldn't be in IT anyway, right? Wrong!
It is my firm belief that a clear and easy to use interface is just as important as the logic itself when you write a script that is going to be used by someone else. For most people, that means the interface needs to be graphical. I base this belief on having worked in an IT department at a large company for several years as well as maintained the Booksonic project since the start in late 2015. If you want to change my mind, feel free to try and do so in the comments below.
Now with that out of the
When I first started writing powershell I noticed that most examples of people writing powershell UIs get really messy real fast.
A typical example you may find online looks something like this
Add-Type -AssemblyName System.Windows.Forms Add-Type -Name Window -Namespace Console -MemberDefinition ' [DllImport("Kernel32.dll")] public static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); [Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0) ' $font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Bold) $label = New-Object System.Windows.Forms.Label $label.Cursor = [System.Windows.Forms.Cursors]::Hand $label.Text = "Click me to open popeen.com" $label.BackColor = "Transparent" $label.ForeColor = "Blue" $label.AutoSize = $true $label.Location.X = 15 $label.Location.Y = 15 $label.Add_Click = { Start-Process -FilePath iexplore -ArgumentList "https://popeen.com" } $form = New-Object system.Windows.Forms.Form $form.Width = 600 $form.Height = 200 $form.Text = "Example form" $form.Font = $font $form.Controls.Add($label) $form.ShowDialog()
Now functionally speaking there is nothing wrong with that script and in fact it may not look that bad either but remember, all we have done is created a window and added one label to it. Imagine how cluttered this would become once you started doing some more advanced UIs. A better way to write the above that I have actually never seen anyone use other than me and some of my colleages would be using -Properties like this.
Add-Type -AssemblyName System.Windows.Forms Add-Type -Name Window -Namespace Console -MemberDefinition ' [DllImport("Kernel32.dll")] public static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); [Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0) $label = New-Object System.Windows.Forms.Label -Properties @{ Cursor = [System.Windows.Forms.Cursors]::Hand Text = "Click me to open popeen.com" BackColor = "Transparent" ForeColor = "Blue" AutoSize = $true Location = "15, 15" Add_Click = { Start-Process -FilePath iexplore -ArgumentList "https://popeen.com" } } $form = New-Object system.Windows.Forms.Form -Properties @{ Size = "600, 200" Text = "Example form" Font = New-Object System.Drawing.Font("Times New Roman", 24, [System.Drawing.FontStyle]::Bold) } $form.Controls.Add($label) $form.ShowDialog()
While this takes up about the same space it looks much better right? This way a quick glance at the code gives you a much better understanding of what it is you are looking at.
If you choose to stop reading here and start writing your UIs in this way I beleive you will have a much easier time maintaining that script then you had before. However, I have taken it a step further in my scripts.
When I write a script I use a specific framework that makes the code even quicker to read and also includes some other nice features that I won't go in to in this post but might make future posts about. One of the most important parts of this framework is a module I call EasyGUI and that you can download at https://gitlab.com/Popeen/EasyGUI
This module builds on the second example above and simplifies it even more. It also includes some other cool stuff that I also won't go in to here but again, might make another post about. If we decided to use EasyGUI to write the example above it would look like this
Import-Module EasyGUI Initialize-EasyGUI Hide-Console $form = New-Form @{ Size = "600, 200" Text = "Example form" Font = New-Font -Font "Times New Roman" -Size 24 -Style $FONTSTYLE.Bold } $label = New-Label @{ Cursor = $CURSOR.Hand Text = "Click me to open popeen.com" BackColor = "Transparent" ForeColor = "Blue" AutoSize = $true Location = "15, 15" Add_Click = { Start-Process -FilePath iexplore -ArgumentList "https://popeen.com" } } $form.Controls.Add($label) Show-Form $form Stop-Console
I dont know about you but I find that to be much more readable then the first example we looked at, especially when you are working with a lot more then just a label.
It should be noted that not every forms object is in EasyGUI yet as I add them when I need them but adding them yourself should be very easy even for someone new to Powershell and if not just post a comment below and let me know what object you would like added.
I would love to hear your thoughts on this, is it something you would ever use or do you think I'm just talking rubbish when I say that UIs are this important or that a simple module like this can make it a lot more quick, fun and easy to code and maintain UIs.