Learn How to Customize the Windows PowerShell Script Editor


Summary: Learn how to customize the Windows PowerShell script editor by using readily available functions from the PowerShellPack.


Microsoft Scripting Guy Ed Wilson here. Even well-planned blogs often go astray. If you have been keeping up with our Weekend Scripter series, you know that today I am supposed to talk about adding a function to my Windows PowerShell ISE profile to retrieve stock quotes and weather forecasts. Unfortunately, one problem with web services is that if the web service is down, it is hard to troubleshoot your code. I have a really cool function I wrote, and it was working beautifully a few days ago, but then the web service I was using took a dirt nap. It has not came back up yet. In the meantime, James Brundage sent me a blog post about adding menu items to the Windows PowerShell ISE by using his IsePack. It actually makes a great follow-up to my series of articles about customizing the Windows PowerShell ISE.

James is the founder of Start-Automating (http://www.start-automating.com), a company dedicated to saving people time and money by helping them automate. Start-Automating offers Windows PowerShell training and custom Windows PowerShell and .NET Framework development. He is a former Microsoft employee from the Windows PowerShell team and is the author the PowerShellPack (http://code.msdn.microsoft.com/PowerShellPack), a collection of Windows PowerShell scripts that enable building user interfaces, interacting with RSS feeds, getting system information.

The floor is yours, James.


About a year ago, I released a module called IsePack, which has about 50 different add-on menu items for the Windows PowerShell Integrated Scripting Environment (ISE). IsePack has nested menus and shortcut keys for nearly everything. It also has some helper functions you can copy and reuse in your own projects. The IsePack is incorporated with the PowerShellPack.

Because IsePack has so many menus, it was important to find an easier way to structure the menus than writing each one out manually (as Ed Wilson discussed during an earlier Weekend Scripter article). In particular, I wanted to make sure my menus did the following things:

  • Provide the menu items in a convenient format.
  • Automatically replace a menu of the same name.
  • Allow for nested menus.
  • Alphabetize the menu items I had.
  • Allow for an easier way to add shortcut keys.

What I built was a nifty little function called Add-IseMenu. Go ahead, load IsePack and check it out

Import-Module IsePack

Get-Help Add-IseMenu -Full

Add-IseMenu takes the name of a menu and a hashtable that represents the menu, and optionally, a root level in which to put the menu.

It is a pretty well documented function, so you should not have any trouble using it on your own, but here is a quick example. This adds a menu called “Verb” with a nested menu for Get and Import. One of the items under Get, Get-Process, has a shortcut key (CTRL+ALT+SHIFT+P):

Add-IseMenu -Name “Verb” @{
Get = @{
Process = { Get-Process } | Add-Member NoteProperty ShortcutKey “CTRL+ALT+SHIFT+P” -PassThru
Service = { Get-Service }
Hotfix = { Get-Hotfix } 
Import = @{
Module = { Import-Module } 

As you can see, you can put a lot of menu structure in a fraction of the space as compared to writing out menu items the long way. Also, because the inputs for the menus are hashtables, it’s possible to build them up in script.

The previous posts in this series have helped customize the options screen. Let us see how much more we can do with Add-ISEMenu and a couple of helper functions.

$tokenColorMenu = @{}
$paneColorMenu = @{}
$outputColorMenu = @{}
function Edit-TokenColor($tokenType) {
$colorDialog = New-Object Windows.Forms.ColorDialog -Property @{
FullOpen = $true
Color = [Drawing.Color]::FromArgb($psise.Options.TokenColors[“$tokenType”].R,
if ($colorDialog.ShowDialog() -eq “OK”) {
$psise.Options.TokenColors[“$tokenType”] = [Windows.Media.Color]::FromArgb(


function Edit-OptionColor($option) {
$colorDialog = New-Object Windows.Forms.ColorDialog -Property @{
FullOpen = $true
Color = [Drawing.Color]::FromArgb($psise.Options.$option.R,
if ($colorDialog.ShowDialog() -eq “OK”) {
$psise.Options.$option = [Windows.Media.Color]::FromArgb(


foreach ($tokenType in $psise.Options.TokenColors.Keys) {
$menuAction = [ScriptBlock]::Create(“Edit-TokenColor $tokenType”)
$tokenColorMenu.$tokenType = $menuAction

$optionNames = $psise.Options | 
Get-Member *color* -MemberType Property |
Where-Object { $_.Definition -like “System.Windows.Media.Color*” }|
Select-Object -ExpandProperty Name

foreach ($optionName in $optionNames) {
$menuAction = [ScriptBlock]::Create(“Edit-OptionColor $optionName”)
if ($optionName -like “*pane*”) {
$paneColorMenu.$optionName = $menuAction
} else {
$outputColorMenu.$optionName = $menuAction

Add-IseMenu -Name “Set-IseOptions” -Menu @{
= {
$fontDialog = New-Object Windows.Forms.FontDialog
$fontDialog.Font = New-Object Drawing.Font $psise.Options.FontName, 
if ($fontDialog.ShowDialog() -eq “OK”) {
$psise.Options.FontName = $fontDialog.Font.Name
$psise.Options.FontSize = $fontDialog.Font.Size
# Reset options is a script block with an extra property added… a shortcut
# key. If the shortcut key is found on any menu item in Add-IseMenu, then a shortcut
# key will be registered.
= {
} | 
Add-Member NoteProperty ShortcutKey “CTRL + SHIFT + ALT + R” -PassThru
= @{
= { $psise.Options.RestoreDefaultTokenColors() }
= $outputColorMenu
= $paneColorMenu
= $tokenColorMenu
= @{