Custom commands in PowerShell ISE
In PowerShell V2 CTP3 (and possibly earlier CTPs but I didn’t try it), you can add a Custom menu to the PowerShell ISE that will run your own commands. Thanks to the object model that PowerShell ISE exposes, those commands can even modify the text files open in the editor.
One of the first things I missed when editing scripts in the PowerShell ISE is the ability to comment (or uncomment) a block of lines at once. It was surprisingly easy to write a function to do enough to make me happy. Yes, I know it misses a lot of edge cases but those aren’t worth the effort to me to handle. At least not yet….
There are surprisingly few things that are specific to the ISE object model that you need. The first is a command for the menu item to run. Here it is as the function named psISE_ToggleCommentCommand. I arbitrarily chose the "psISE_" prefix for all the functions I write that are specific to the ISE itself. This is one of those cases where I wish I could partition things off into namespaces but I can live with the function naming convention. And I might find that it’s not even necessary for the number of things I will be writing.
function psISE_ToggleCommentCommand { $curFile = $psISE.CurrentOpenedFile $selection = $curFile.Editor.SelectedText if ($selection.length -gt 0) { $curFile.Editor.InsertText((ToggleComment $selection)) } }
The first thing to notice is the $psISE variable. This is always available in the PowerShell ISE and is of type System.Management.Automation.Host.PSGHost. Everything that you would do with it is based on a set of five read-only properties: CurrentOpenedFile, CurrentOpenedRunSpace, CustomMenu, OpenedRunspaces, and Options.
For this script, we want to apply it to the CurrentOpenedFile (as opposed to any of the other opened files that you find through the $psISE.CurrentOpenedRunSpace.OpenedFiles collection). Any opened file has an Editor property that returns a Microsoft.Windows.PowerShell.Gui.Internal.ScriptEditor object with a set of interesting methods and properties. In this function, I make use of a property (SelectedText) and a method (InsertText).
The interesting stuff happens in the ToggleComment function, although it’s not interesting from the perspective of the PowerShell ISE because it just does basic text replacement that works in the command-line PowerShell as well. Here it is anyway, just so you have a sense of what it does:
function psISE_ToggleCommentText { <# .Synopsis Toggles the commented state of text passed in .Parameter text The text in which to toggle comments. #> param( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [string]$text ) Process { $returnedText = "" foreach ( $line in $text -split ` [System.Environment]::NewLine ) { if ( $line.length -gt 0) { if ( $line -match "^#" ) { $line = $line -replace "^#", "" } else { $line = $line -replace "^", "#" } $returnedText += "{0}{1}" -f $line, ` [System.Environment]::NewLine } #end line length check } #end foreach $returnedText } #end Process }
I put both of these into my $profile (this is different than the $profile for the "main" PowerShell host. See my post about the profiles for more details).
Now to set up the menu and that goes through the CustomMenu property of $psISE.
$psISE.CustomMenu.Submenus.Clear() $psIse.CustomMenu.Submenus.Add("_Toggle Comment", ` {psISE_ToggleCommentCommand}, ` "Ctrl+E")
Notice that I start out by calling the Clear method to empty out the Custom menu: as far as I can tell, there is no way to modify a menu item once it has been set up–so I clear it and start fresh, just in case.
Then there’s the Add method. The first parameter is the menu item name. Notice the underscore before the T as a keyboard accelerator. You might be used to using the ampersand ("&") in some languages. The second parameter is the script block to run. I could have put the entirety of the psISE_ToggleCommentCommand function into this script block but it makes a lot more sense to separate it. The final parameter is the keyboard shortcut.
I experimented with some different keyboard shortcuts and the object model will even let you set it to a Windows key combo (using "Win" as the name) but I couldn’t get it to respond to any of those (I even tried things like Ctrl+Win+E). If I’m missing something there, let me know.
The help file for the object model is complete but it’s sparse: it feels like there’s more work the writers have planned for this area.
One other thing: the menu’s name is "Custom" and it looks like–in CTP3 at least–that there’s nothing you can do about that.
For those few people (still) reading my blog: are these articles about PowerShell interesting?
Hallo Tommy,
I agree that such a function is a must.
I tried a solution more notepad++ compatible. See
http://pauerschell.blogspot.com/2008/12/ise-comment-out-block-of-text.html.
Which help file did you find about the object model ?
Happy new year
Bernd
They are interesting from a technical perspective. Personally I don’t a place to play with this tech.
I have only dabbled with Notepad++ in the past. I have used vim for years and so I wrote my function to be familiar to me. But you did a nice job getting rid of that extra comment at the end.
I found the help file through the Help menu in PowerShell ISE.
Have a look at this recent post from Jeffrey Snover about what he has in his PowerShell_ISE profile: http://bit.ly/jzZJ
And a Happy New Year to you as well.
Thanks for replying, Pat, even if you don’t mess around with Windows-based technologies.