We have been spending a ton of time on the great stuff that is in the PSReadline module, which is now a default part of PowerShell. If you are just jumping in, take some time to get caught up on past articles or you will be a little lost.

Even though the module has been around for awhile, I never paid it much attention. Now that I have dug into it, I can see some terrific value. I think it will make my time at a PowerShell prompt more efficient and enjoyable. I spend most of my day with a PowerShell session running and other than a web browser and email, it is where I am most likely working. I thought I would share some of the things I am using with PSReadline. Some of these are drawn from the sample profile script I mentioned last time. But I have made a few modifications.

Graphical Command History

We already know that PSReadline maintains a historical record outside of PowerShell. You may also recall that in previous versions of PowerShell (and Windows) you used to be able to press F7 to get a graphical popup of recent commands. This was actually the command buffer from the CMD window that was running PowerShell. Regardless, I have a key handler assigned to F7 that uses Out-Gridview to display command history.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Set -PSReadlineKeyHandler -Key F7 -BriefDescription HistoryList -Description "Show command history with Out-Gridview. [$($env:username)]" -ScriptBlock { $pattern = $null [ Microsoft . PowerShell . PSConsoleReadLine ] :: GetBufferState ( [ ref ] $pattern , [ ref ] $null ) if ( $pattern ) { $pattern = [ regex ] :: Escape ( $pattern ) } $history = [ System . Collections . ArrayList ] @ ( $last = '' $lines = '' foreach ( $line in [ System . IO . File ] :: ReadLines ( ( Get-PSReadlineOption ) . HistorySavePath ) ) { if ( $line . EndsWith ( '`' ) ) { $line = $line . Substring ( 0 , $line . Length - 1 ) $lines = if ( $lines ) { "$lines`n$line" } else { $line } continue } if ( $lines ) { $line = "$lines`n$line" $lines = '' } if ( ( $line -cne $last ) -and ( ! $pattern -or ( $line -match $pattern ) ) ) { $last = $line $line } } ) $history . Reverse ( ) $command = $history | Select-Object -unique | Out-GridView -Title "PSReadline History - Select a command to insert at the prompt" -OutputMode Single if ( $command ) { [ Microsoft . PowerShell . PSConsoleReadLine ] :: RevertLine ( ) [ Microsoft . PowerShell . PSConsoleReadLine ] :: Insert ( ( $command -join "`n" ) ) } }



My version filters out duplicates. When I press F7 I get something like this:

If I select a command and press OK, the command is inserted at my prompt where I can modify and run it. Or if I type a string like ‘process’ and then press F7, the handler script block will filter commands that match the pattern.

Now, I have an easy way to find a previous command.

Jump Lists

The other set of handlers I am getting a ton of use from are those that provide “jump list” functionality. With a jump list, I can assign a keyboard marker or shortcut to a directory. I can then invoke the shortcut to rapidly change to that folder. For example, with my PSReadline tools, I can change to a folder like C:\scripts. I then press Ctrl+Alt+J and press the keyboard shortcut I want to assign such as ‘s’. It can be any single keyboard character. I can repeat the process for any folder I am likely to use throughout the day. The data is stored in a hashtable. I also wrote a handler for Alt+J that displays my current assignments in a popup.

To jump to any directory, I press Ctrl+J and the shortcut key. With this, I can very quickly jump between frequently used directories. Because I want to always have these handlers, I use this code in my PowerShell profile script.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 # Ctrl+Alt+j then type a key to mark the current directory. # Alt+J to show the current shortcuts in a popup # Ctrj+j then the same key will change back to that directory without # needing to type cd and won't change the command line. #pre-populate a global variable $global : PSReadlineMarks = @ { [ char ] "s" = "c:\scripts" [ char ] "d" = "c:\users\jeff\documents" } Set -PSReadlineKeyHandler -Key Ctrl + Alt + j -BriefDescription MarkDirectory -LongDescription "Mark the current directory. [$($env:username)]" -ScriptBlock { #press a single character to mark the current directory $key = [ Console ] :: ReadKey ( $true ) if ( $key . keychar -match "\w" ) { $global : PSReadlineMarks [ $key . KeyChar ] = $pwd } else { [ Microsoft . PowerShell . PSConsoleReadLine ] :: Ding ( ) Write-Warning "You entered an invalid character." [ Microsoft . PowerShell . PSConsoleReadLine ] :: AcceptLine ( ) } } Set -PSReadlineKeyHandler -Key Ctrl + j -BriefDescription JumpDirectory -LongDescription "Goto the marked directory.[$($env:username)]" -ScriptBlock { $key = [ Console ] :: ReadKey ( ) $dir = $global : PSReadlineMarks [ $key . KeyChar ] if ( $dir ) { cd $dir [ Microsoft . PowerShell . PSConsoleReadLine ] :: InvokePrompt ( ) } } Set -PSReadlineKeyHandler -Key Alt + j -BriefDescription ShowDirectoryMarks -LongDescription "Show the currently marked directories in a popup. [$($env:username)]" -ScriptBlock { $data = $global : PSReadlineMarks . GetEnumerator ( ) | Where { $_ . key } | Sort key $data | foreach -begin { $text = @" Key`tDirectory ---`t--------- "@ } -process { $text += "{0}`t{1}`n" -f $_ . key , $_ . value } $ws = New-Object -ComObject Wscript . Shell $ws . popup ( $text , 10 , "Use Ctrl+J to jump" ) | Out-Null [ Microsoft . PowerShell . PSConsoleReadLine ] :: InvokePrompt ( ) }



I am pre-populating the hashtable with some values I know I always want but you don’t have to. The bottom line, at least for me, is that PSReadline helps me work much smarter and more efficiently. Anything that saves a few keystrokes here and there or eliminates an error-prone activity like typing (!) is worth my time to learn and leverage.

I hope you found this series interesting. If you are doing anything fun and interesting with PSReadline I would love to hear about it.