So last week I covered how to create a prompt inside of PowerShell by recreating the action prompt for the Remove-Item cmdlet. While researching and writing that post, I came across an example of how to create a graphical prompt inside of PowerShell using .NET Framework form-building features available since PowerShell v3. In this post, I’ll continue with my custom Remove-MyItem function and creating a simple yes/no option to delete a file.
This time around, I’m going to display the entire code sample, then I’ll walk through each part and explain what is happening. Here I decided to split out into two functions: the code for Remove-MyItem is its own function and calls the New-YesNoPrompt function that actually creates the graphical prompt.
Creating the Form Window
Let’s start with the New-YesNoPrompt function. It takes in two parameters: PromptTitle and PromptMessage. The title is displayed at the top of the window in the title bar, and the message is displayed in the box to the user, ideally what action is about to be approved or denied. First, outside of my two functions at the top of my .ps1 file, I need to import two .NET Framework classes using Add-Type in order to create my form:
Back inside the function, I need to create the $form object to start adding controls to:
# Create the form title, size, and starting position $form = New-Object System.Windows.Forms.Form $form.Text = $PromptTitle $form.Size = New-Object System.Drawing.Size(300, 200) $form.StartPosition = 'CenterScreen'
This contains the basic information on displaying the form using different properties, such as:
– Text: the title goes here and is displayed in the title bar of the window
– Size: creates a new object using the System.Drawing.Size namespace; this is defined in an (x, y) format, or (width, height). The box created here is 300 pixels wide by 200 pixels tall.
– StartPosition: this determines where the window is displayed; currently set to CenterScreen to display in the middle, but other options include:
- CenterParent: the form is centered within its parent form
- Manual: position is determined by the Location property, which is the of the upper-left corner of the window
- WindowsDefaultBounds: the form is positioned at the Windows default location and has the bounds determined by Windows default
- WindowDefaultLocation: the form is positioned at the Windows default location and has the dimensions specified in the form’s size
With the basic windows form created, let’s move onto create action buttons for the user to respond to.
Creating the Buttons
For our form, I need options for the user to select from. These options will be presented as Yes and No buttons to indicate if I want to delete the file or not:
# Create the Yes button and its properties $yesButton = New-Object System.Windows.Forms.Button $yesButton.Location = New-Object System.Drawing.Point(60, 120) $yesButton.Size = New-Object System.Drawing.Size(75, 23) $yesButton.Text = 'Yes' $yesButton.DialogResult = [System.Windows.Forms.DialogResult]::Yes $form.AcceptButton = $yesButton $form.Controls.Add($yesButton) # Create the No button and its properties $noButton = New-Object System.Windows.Forms.Button $noButton.Location = New-Object System.Drawing.Point(165, 120) $noButton.Size = New-Object System.Drawing.Size(75, 23) $noButton.Text = 'No' $noButton.DialogResult = [System.Windows.Forms.DialogResult]::No $form.CancelButton = $noButton $form.Controls.Add($noButton)
First, I create an object based on the Button class of the Forms namespace. I then set the Location of the button within the form using (x,y) coordinates, or the distance from the upper left of the form window in pixels. This is the same idea as setting the Location of the form itself on the monitor. This will probably take some experimentation to get it just right.
Next, I set the Size of the button just like setting the size of the windows form using (width, height) in pixels. After the size is setting the Text of what will appear on the button, here the words Yes and No to indicate if I want to delete the file or not.
Notice the difference in each button’s Location property. The Y values are both the same at 120, meaning they will be horizontally aligned, but the X values are not. The Yes button is 60 pixels from the left while the No button is 165 pixels from the left, meaning they will be next to each other. You’ll see this later in our final screenshot.
The DialogResult property gets or sets the returned value when the button is clicked. The DialogResult property is set to an identifier that indicates the return value of the dialog box, and for each of our buttons this is Yes or No. Other options for DialogResults include: Abort, Cancel, Ignore, None, OK, and Retry.
Along with each button, I set the AcceptButton to $yesButton and CancelButton to $noButton for the form itself. The AcceptButton is activated when the user presses the Enter key on the form, and the CancelButton is activated when the user presses the Escape key. So for my form, if the user presses Enter to the prompt, this is the same as clicking the Yes button, and pressing Escape is the same as pressing the No button. Finally, I add the button to the form itself under the Controls property.
Finalizing the Form
At last, I need to display the value of the $PromptMessage parameter onto the form. This is going to be the question I ask the user to respond to, and this takes shape using a Label. Like our other objects so far, it has a Location, Size, and Text property to create how it looks. Also like the buttons, I add it to the Controls property of the form. The last property I set is TopMost, which just puts the form on top of all others when it is displayed. With the form created, I return the form object back to whatever called my form function.
By separating the logic to create the graphical prompt out of the Remove-MyItem function, the code here is greatly reduced. First I create a $params object with the window title and message that I want to display in the graphical prompt window. I pass this object to my prompt function using splatting (I always forget splatting exists, so I wanted to use it here) along with using the ShowDialog() method on my form. This will display the form to the user, and the result of which button is selected is saved to $response. Just like the examples from last week, I use a switch statement to perform different actions based on the option the user has chosen. The condition is use the System.Windows.Forms.DialogResult type we specified for each button in the other function. For this example, I just outputted text to show whether the action would remove the file or leave it alone.
So here is the final result of creating my graphical prompt to remove a file when calling my function Remove-MyFile and selecting the Yes button in the prompt:
The method above is not intended to replace other options for confirming changes or testing commands using ShouldProcess, which adds -WhatIf and -Confirm functionality to a function. I received some valid criticism from the previous post on creating console prompts. The article here is to simple show how it is possible to create a graphical prompt, not to replace this other important functionality. Please check out my repository for this on GitHub for the code used in this post plus any additional examples I come up with in the future.