Posts Tagged ‘GUI’

PowerShell Multi-Line Input Box Dialog, Open File Dialog, Folder Browser Dialog, Input Box, and Message Box

May 1st, 2013 41 comments

Updated May 17, 2013 to fix potential bug and add more parameters to some functions.

Updated Dec 5, 2013 to release COM object from Read-FolderBrowserDialog function.

I love PowerShell, and when prompting users for input I often prefer to use GUI controls rather than have them enter everything into the console, as some things like browsing for files or folders or entering multi-line text aren’t very pleasing to do directly in the PowerShell prompt window.  So I thought I’d share some PowerShell code that I often use for these purposes.  Below I give the code for creating each type of GUI control from a function, an example of calling the function, and a screen shot of what the resulting GUI control looks like.

Show a message box


# Show message box popup and return the button clicked by the user.
function Read-MessageBoxDialog([string]$Message, [string]$WindowTitle, [System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::None)
	Add-Type -AssemblyName System.Windows.Forms
	return [System.Windows.Forms.MessageBox]::Show($Message, $WindowTitle, $Buttons, $Icon)


$buttonClicked = Read-MessageBoxDialog -Message "Please press the OK button." -WindowTitle "Message Box Example" -Buttons OKCancel -Icon Exclamation
if ($buttonClicked -eq "OK") { Write-Host "Thanks for pressing OK" }
else { Write-Host "You clicked $buttonClicked" }

Message Box Example


Prompt for single-line user input


# Show input box popup and return the value entered by the user.
function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
	Add-Type -AssemblyName Microsoft.VisualBasic
	return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText)


$textEntered = Read-InputBoxDialog -Message "Please enter the word 'Banana'" -WindowTitle "Input Box Example" -DefaultText "Apple"
if ($textEntered -eq $null) { Write-Host "You clicked Cancel" }
elseif ($textEntered -eq "Banana") { Write-Host "Thanks for typing Banana" }
else { Write-Host "You entered $textEntered" }

Input Box Example


Prompt for a file (based on a post the Scripting Guy made)


# Show an Open File Dialog and return the file selected by the user.
function Read-OpenFileDialog([string]$WindowTitle, [string]$InitialDirectory, [string]$Filter = "All files (*.*)|*.*", [switch]$AllowMultiSelect)
	Add-Type -AssemblyName System.Windows.Forms
	$openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
	$openFileDialog.Title = $WindowTitle
	if (![string]::IsNullOrWhiteSpace($InitialDirectory)) { $openFileDialog.InitialDirectory = $InitialDirectory }
	$openFileDialog.Filter = $Filter
	if ($AllowMultiSelect) { $openFileDialog.MultiSelect = $true }
	$openFileDialog.ShowHelp = $true	# Without this line the ShowDialog() function may hang depending on system configuration and running from console vs. ISE.
	$openFileDialog.ShowDialog() > $null
	if ($AllowMultiSelect) { return $openFileDialog.Filenames } else { return $openFileDialog.Filename }


$filePath = Read-OpenFileDialog -WindowTitle "Select Text File Example" -InitialDirectory 'C:\' -Filter "Text files (*.txt)|*.txt"
if (![string]::IsNullOrEmpty($filePath)) { Write-Host "You selected the file: $filePath" }
else { "You did not select a file." }

Select Text File Example


Prompt for a directory (based on this post, as using System.Windows.Forms.FolderBrowserDialog may hang depending on system configuration and running from the console vs. PS ISE)


# Show an Open Folder Dialog and return the directory selected by the user.
function Read-FolderBrowserDialog([string]$Message, [string]$InitialDirectory, [switch]$NoNewFolderButton)
    $browseForFolderOptions = 0
    if ($NoNewFolderButton) { $browseForFolderOptions += 512 }

	$app = New-Object -ComObject Shell.Application
	$folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory)
	if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' }
	[System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null
	return $selectedDirectory


$directoryPath = Read-FolderBrowserDialog -Message "Please select a directory" -InitialDirectory 'C:\' -NoNewFolderButton
if (![string]::IsNullOrEmpty($directoryPath)) { Write-Host "You selected the directory: $directoryPath" }
else { "You did not select a directory." }

Browse For Folder


Prompt for multi-line user input (based on code shown in this TechNet article)


function Read-MultiLineInputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
	Prompts the user with a multi-line input box and returns the text they enter, or null if they cancelled the prompt.
	Prompts the user with a multi-line input box and returns the text they enter, or null if they cancelled the prompt.
	The message to display to the user explaining what text we are asking them to enter.
	.PARAMETER WindowTitle
	The text to display on the prompt window's title.
	.PARAMETER DefaultText
	The default text to show in the input box.
	$userText = Read-MultiLineInputDialog "Input some text please:" "Get User's Input"
	Shows how to create a simple prompt to get mutli-line input from a user.
	# Setup the default multi-line address to fill the input box with.
	$defaultAddress = @'
	John Doe
	123 St.
	Some Town, SK, Canada
	A1B 2C3
	$address = Read-MultiLineInputDialog "Please enter your full address, including name, street, city, and postal code:" "Get User's Address" $defaultAddress
	if ($address -eq $null)
		Write-Error "You pressed the Cancel button on the multi-line input box."
	Prompts the user for their address and stores it in a variable, pre-filling the input box with a default multi-line address.
	If the user pressed the Cancel button an error is written to the console.
	$inputText = Read-MultiLineInputDialog -Message "If you have a really long message you can break it apart`nover two lines with the powershell newline character:" -WindowTitle "Window Title" -DefaultText "Default text for the input box."
	Shows how to break the second parameter (Message) up onto two lines using the powershell newline character (`n).
	If you break the message up into more than two lines the extra lines will be hidden behind or show ontop of the TextBox.
	Name: Show-MultiLineInputDialog
	Author: Daniel Schroeder (originally based on the code shown at
	Version: 1.0
	Add-Type -AssemblyName System.Drawing
	Add-Type -AssemblyName System.Windows.Forms
	# Create the Label.
	$label = New-Object System.Windows.Forms.Label
	$label.Location = New-Object System.Drawing.Size(10,10) 
	$label.Size = New-Object System.Drawing.Size(280,20)
	$label.AutoSize = $true
	$label.Text = $Message
	# Create the TextBox used to capture the user's text.
	$textBox = New-Object System.Windows.Forms.TextBox 
	$textBox.Location = New-Object System.Drawing.Size(10,40) 
	$textBox.Size = New-Object System.Drawing.Size(575,200)
	$textBox.AcceptsReturn = $true
	$textBox.AcceptsTab = $false
	$textBox.Multiline = $true
	$textBox.ScrollBars = 'Both'
	$textBox.Text = $DefaultText
	# Create the OK button.
	$okButton = New-Object System.Windows.Forms.Button
	$okButton.Location = New-Object System.Drawing.Size(415,250)
	$okButton.Size = New-Object System.Drawing.Size(75,25)
	$okButton.Text = "OK"
	$okButton.Add_Click({ $form.Tag = $textBox.Text; $form.Close() })
	# Create the Cancel button.
	$cancelButton = New-Object System.Windows.Forms.Button
	$cancelButton.Location = New-Object System.Drawing.Size(510,250)
	$cancelButton.Size = New-Object System.Drawing.Size(75,25)
	$cancelButton.Text = "Cancel"
	$cancelButton.Add_Click({ $form.Tag = $null; $form.Close() })
	# Create the form.
	$form = New-Object System.Windows.Forms.Form 
	$form.Text = $WindowTitle
	$form.Size = New-Object System.Drawing.Size(610,320)
	$form.FormBorderStyle = 'FixedSingle'
	$form.StartPosition = "CenterScreen"
	$form.AutoSizeMode = 'GrowAndShrink'
	$form.Topmost = $True
	$form.AcceptButton = $okButton
	$form.CancelButton = $cancelButton
	$form.ShowInTaskbar = $true
	# Add all of the controls to the form.
	# Initialize and show the form.
	$form.ShowDialog() > $null	# Trash the text of the button that was clicked.
	# Return the text that the user entered.
	return $form.Tag


$multiLineText = Read-MultiLineInputBoxDialog -Message "Please enter some text. It can be multiple lines" -WindowTitle "Multi Line Example" -DefaultText "Enter some text here..."
if ($multiLineText -eq $null) { Write-Host "You clicked Cancel" }
else { Write-Host "You entered the following text: $multiLineText" }

Multi Line Example


All of these but the multi-line input box just use existing Windows Forms / Visual Basic controls.

I originally was using the Get verb to prefix the functions, then switched to the Show verb, but after reading through this page, I decided that the Read verb is probably the most appropriate (and it lines up with the Read-Host cmdlet).

Hopefully you find this useful.

Happy coding!

Too Many AutoHotkey Shortcuts To Remember? There’s An App For That!

January 19th, 2013 3 comments

I love AutoHotkey (AHK). Ever since I discovered it a little over a year ago I am constantly surprised and pleased with what I am able to accomplish with it.  And there in lied my problem.  Out of the box, AHK allows you to trigger your own scripts using hotkeys.  My problem was that I had so many of these little (and some large) scripts to do so many things, that i quickly ran out of hotkeys to use that wouldn’t interfere with other application’s shortcut keys (Visual Studio anyone); also even if I had more hotkeys available, trying to remember which ones did what was a nightmare. To remedy this, I created AHK Command Picker.

AHK Command Picker is really just a little UI that allows you to quickly run your scripts; so instead of using a hotkey, you just hit the Caps Lock key to bring up the UI, and then start typing for the script that you want to run.  It provides Camel Case filtering to still make launching scripts super fast, and also shows your scripts in a list, allowing you to browse through them. It also allows to you easily pass parameters into your scripts, which can be used to change a script’s behaviour.  Here’s a screenshot showing the UI and some of the many scripts that I have:


And here’s a screenshot showing it filter the list as you type:


One of my favourite things about AHK is the community. There are so many scripts out there that before you write your own code, you should just do a quick Google search and chances are you’ll find someone who has already written the script for you, or one that is close to your needs and can be quickly modified.  I assumed this would be the case for the type of tool I was looking for.  So I searched and came across HotKeyIt and Keyword Launcher, both of which were interesting and neat, but neither provided a GUI to quickly see your list of scripts so that you could launch it quickly.  They still relied on you to remember your specific hotkeys; I wanted a list that I could browse my scripts from to easily launch them.

I love programming and learning new languages, so I thought I’d give creating the type of picker that I wanted a shot. It’s still not perfect, and I have many ideas for new features that could make it better, but using it as it is today has improved my productivity so much.  I’ve shown it to some people at my work and many of them started using it and agree.

If all you are looking for is a program to quickly launch applications or open files, then I would recommend KeyBreeze.  It’s a great little free app written in C# and is very polished (and much better than Launchy in my opinion because you can add ANY file/app to it via the context menu). But if you use AHK and want to be able to quickly launch your own scripts, definitely check out AHK Command Picker. Like myself you will probably find that you go from using AHK to launch 10 – 20 scripts, to using it to launch hundreds or even thousands of scripts, saving you time and effort constantly throughout your day.  Those things that you maybe only do once or twice a month and didn’t want to dedicate a hotkey to will start showing up in your scripts list.

So go ahead and give AHK Command Picker a try, and be sure to let me know what you think of it and what improvements you would like to see by logging it on the Codeplex site.