Even though PowerShell is a console-based shell, it is built on .NET. This means we have access to many of the .NET objects. For example, we can use .NET forms to create graphical interfaces for PowerShell scripts.
Advanced Stuff
Working with the Windows forms is beyond basic PowerShell. However, we want to give you a taste of the power behind PowerShell. Documentation for the System.Windows.Forms namespace can be found at: http://msdn2.microsoft.com/en-us/library/k50ex0x9(vs.80).aspx.
First let's look at a brief example in this script:
DemoMsgBox.ps1 #DemoMsgBox.ps1 [void][Reflection.Assembly]::LoadWithPartialName("` System.Windows.Forms") $MsgBox = [Windows.Forms.MessageBox] $button=[Windows.Forms.MessageBoxButtons]::OK $icon=[windows.forms.MessageBoxIcon]::Information $MsgBox::show("Hello world","Demo Msg Box",$button,$icon)
In order to work with system forms, we need to load the .NET assembly, which is done in the first line. The use of [void] prevents any information about the assembly from being displayed by PowerShell. At this point normally we would call New-Object to create the message box object, but PowerShell sometimes doesn't know everything. If you try to use New-Object, PowerShell will complain that it doesn't have a constructor for Windows.Forms.MessageBox or a System.Windows.Forms.MessageBox. It doesn't matter that this is a perfectly valid .NET object. However, we can manipulate the assembly directly to define a button and icon, and then display the message box shown in Figure 9-2.
Figure 9-2: PowerShell Message Box
To be honest, this is too much work. If you want to display a message box, it's a good idea to leverage the Windows Script Host object:
DemoPopup.ps1
#DemoPopup.ps1 $Shell=new-object -COM wscript.shell $msg="Hello World" $buttons=0+64 $shell.popup($msg,5,"Demo Popup",$buttons)
This script assumes you have some experience with VBScript. If this is true, you will recognize the Wscript.Shell popup that is essentially a message box with a timer. In this example, the popup will display for five seconds with the Information icon.
VBScript Alert
If you use this technique, you can't use references like VBOkOnly and VBExclamation. Instead, you need to use the actual values such as 0 and 64. You values can be found in the VBScript documentation.
If you want more control over your forms, you can use a script like this:
HelloForm.ps1
#HelloForm.ps1 [void][Reflection.Assembly]::LoadWithPartialName(` "System.Windows.Forms") $Form = New-Object System.Windows.Forms.Form #default form size is 300x300 pixels $Form.width=250 $form.height=200 $Label=new-object System.Windows.Forms.Label $Label.Text="Hello World" $Label.visible=$true $Form.Text = "PowerShell TFM" $Button = New-Object System.Windows.Forms.Button $Button.Text = "OK" #set button vertical button position $Button.Top=$Form.Height*.50 #default button width is 75 #Center button horizontally $Button.left=($Form.Width*.50)-75/2 $Button.Add_Click({$Form.Close()}) $Form.Controls.Add($Button) $Form.Controls.Add($Label) $Form.ShowDialog()
As you can see, you have to define everything when working with System forms. In this instance, PowerShell understands how to create a System.Windows.Forms.Form object, which makes our work a little easier. We define the form size, then add and define a text label and button. Be sure to add the controls to the form, otherwise you'll never see them. By the way, we've added _Click method for the button, which has the form close itself. Finally, we call the ShowDialog() method to display the form shown in Figure 9-3.
Figure 9-3: PowerShell Form
We'll wrap up this chapter with a script inspired by a blog posting on Abhishek's PowerShell Blog (http://spaces.msn.com/abhishek225/) that uses a DataGrid form to display information.
ServicesGrid.ps1
#ServicesGrid.ps1 [void][reflection.assembly]::LoadWithPartialName(` "System.Windows.Forms") [void][reflection.assembly]::LoadWithPartialName("System.Drawing") $form = new-object System.Windows.Forms.Form $form.Size = new-object System.Drawing.Size 400,500 $Form.Text = "PowerShell TFM" $DataGridView = new-object System.windows.forms.DataGridView $array= new-object System.Collections.ArrayList $data=@(get-service | write-output) $array.AddRange($data) $DataGridView.DataSource = $array $DataGridView.Dock = [System.Windows.Forms.DockStyle]::Fill $DataGridView.AllowUsertoResizeColumns=$True $form.Controls.Add($DataGridView) $form.topmost = $True $form.showdialog()
We won't go into detail on how the script works. In general you can see where new objects are created and properties are defined. After creating the form and datagrid, we take the output of the Get-Service cmdlet and turn it into a .NET array that can then be loaded into the grid. Figure 9-4 shows the resulting form.
Figure 9-4: PowerShell Grid Form