Prof. Powershell
Retrieving Status Through PowerShell's Graphical Windows Form
Prof. PowerShell is back with another alternative for displaying status messages in PowerShell.
- By Jeffery Hicks
- 02/04/2014
In the last lesson I demonstrated how to use the title bar of the PowerShell console or the PowerShell ISE to display status messages. Another option is it use a graphical Windows form. Normally, when someone asks about creating graphical PowerShell scripts I direct them to SAPIEN's PowerShell Studio as it offers a great WYSIWYG form generator. But for something simple, like what I have in mind, you can create the elements you need right in your script.
For my demonstration I want to analyze how much space each top level folder is using for a given directory. I'll use a status window to display the progress.
$path = "C:\Scripts"
Before you can create a Windows form you needed to load the .NET class. You probably have seen lines like this:
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
In PowerShell 3 and later this is the better approach.
Add-Type -assembly System.Windows.Forms
Next, I'm going to set some variables to be used when I create the form. You might want to create a function to make the entire process easier.
$Title = "Directory Usage Analysis: $Path"
#winform dimensions
$height=100
$width=400
#winform background color
$color = "White"
Now to create the form using New-Object.
$form1 = New-Object System.Windows.Forms.Form
If you do this in the PowerShell ISE, you will get Intellisense for the object and you can pipe it to Get-Member to discover properties. I'm going to go ahead and define some properties that I think should be self-explanatory. The value of $Title will be used for the window title bar.
$form1.Text = $title
$form1.Height = $height
$form1.Width = $width
$form1.BackColor = $color
$form1.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle
I want my form to be positioned in the center of the screen so I can't miss it.
$form1.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
So far, all I've done is create an empty form object. Now to add something to it. I need something to display my status message. You could use a TextBox but I'm going to use a label.
$label1 = New-Object system.Windows.Forms.Label
$label1.Text = "not started"
$label1.Left=5
$label1.Top= 10
$label1.Width= $width - 20
$label1.Height=50
$label1.Font= "Verdana"
#optional to show border
#$label1.BorderStyle=1
You have to specify where to position the label on the form and its dimensions. To use it, you must add the label to the form.
$form1.controls.add($label1)
Now I'm ready to display the form:
$form1.Show()| out-null
I also want to give it focus so it pops to the top of all my other windows.
$form1.Focus() | out-null
Many of the methods write True or False to the pipeline which I don't want to see which is why I'm piping to Out-Null. To update the form, I can set a new value for the label's Text property and then refresh the form.
$label1.text="Preparing to analyze $path"
$form1.Refresh()
start-sleep -Seconds 1
I added the Start-Sleep command so I could see the label. Now to really use it.
#get top level folders
$top = Get-ChildItem -Path $path -Directory
foreach ($folder in $top) {
$label1.text="Measuring size: $($folder.Name)"
$form1.Refresh()
start-sleep -Milliseconds 100
$stats = Get-ChildItem -path $folder -Recurse -File |
Measure-Object -Property Length -Sum -Average
[pscustomobject]@{
Path=$folder.Name
Files = $stats.count
SizeKB = [math]::Round($stats.sum/1KB,2)
Avg = [math]::Round($stats.average,2)
}
} #foreach
After I get the top level folders, my code would require PowerShell 3.0 by the way, each folder is measured and I update the label text to indicate the folder I'm processing. The main PowerShell code creates a custom object for each folder.
When finished, I will close the form:
$form1.Close()
My output was written to the pipeline and the status box displayed what the script was doing. Here's a brief clip that shows my demo code in action.
Sure, you could use the form to display much more information, but that starts adding to the complexity and you'll quickly realize you don't want to do it manually. When you get to that point you need something like PowerShell Studio. But for a simple status box this should work just fine.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.