Tips for Searching for PowerShell History

In “Fishing for PowerShell: Leveraging Get-Command and Show-Command,” I offered some advice on a few PowerShell tools to help you find what you need. Naturally, PowerShell’s help system should be number one on your list, and I’m going to assume you already know how to use it. In this article, I want to focus on some commands you might not be aware of. Let’s look at command history.

Using Command Buffer to Find Command History

You can use the command buffer to grab a list of commands that you’ve previously used. This buffer only applies to the PowerShell console, not the ISE. You can access this buffer by pressing the F7 key.

Displaying Command Buffer with F7. (Image Credit: Jeff Hicks)
Displaying Command Buffer with F7. (Image Credit: Jeff Hicks)

You can scroll to find a command that’s been previously executed. If you hit Enter, PowerShell will run it. If you use the right arrow key, Windows will insert the command at the prompt where you can revise it if necessary. You can also type the first character of a command, and Windows will jump to the first previous command that starts with that character. If you know the item number, you can access it directly with F9.
Selecting a specific command with F9. (Image Credit: Jeff Hicks)
Selecting a specific command with F9. (Image Credit: Jeff Hicks)

Pressing Enter will insert the command at the prompt. If you don’t get any results or if you want to configure the settings, right-click on the system context menu and select Properties.
Configuring console properties. (Image Credit: Jeff Hicks)
Configuring console properties. (Image Credit: Jeff Hicks)

On the Options tab, you can configure Command History.
Configuring console options. (Image Credit: Jeff Hicks)
Configuring console options. (Image Credit: Jeff Hicks)

I’ve already changed the properties to increase the buffer size to 250, where the maximum value is 999. I’ve elected to use the Discard Old Duplicates setting so that any duplicate commands that I ran earlier are discarded. This ensures that the command buffer only contains unique commands. You should only have to configure the console window once.
Another interesting way to use the command buffer is with the F2 key. Let’s say I just executed this command.

get-vm chi-win81 -computer chi-hvr2 | select VMID | get-vhd -comp $hvr2

Now I want to re-run it with some modifications. I could press the up arrow key, use F3, or select using F7. I can also press F2.

Selecting a partial command with F2. (Image Credit: Jeff Hicks)
Selecting a partial command with F2. (Image Credit: Jeff Hicks)

I enter in the | character and Windows inserts the previous command up to that character.
Inserting a partial command. (Image Credit: Jeff Hicks)
Inserting a partial command. (Image Credit: Jeff Hicks)

All of these commands are using the command buffer that’s part of the CMD.EXE window. Don’t confuse them with PowerShell history.

Using PowerShell’s Get-History cmdlet

PowerShell also maintains a separate command history that works in both the console and the ISE. You can access this history with the Get-History cmdlet, which has an alias of h.

Accessing PowerShell's Command History. (Image Credit: Jeff Hicks)
Accessing PowerShell’s Command History. (Image Credit: Jeff Hicks)

The number of items is controlled by the $MaximumHistoryCount variable. Although the defaults have gone up over the years, you can set your own value, most often in a PowerShell profile script.

$MaximumHistoryCount = 2048

When you find a command you want to re-run use the Invoke-History cmdlet or its alias r. To run command history item 35, I can simply type:

r 35

You can also search history from the command prompt. Type the # character, immediately followed by whatever text you want, and then press tab:

#nslookup <tab>

PowerShell will search history for all commands that contain that word. Use the tab key to cycle through them until you find the command you want.
One feature missing from the cmdlet is the ability to filter out duplicates. One way is to run the command like this:

get-history | select -Unique

Getting unique history. (Image Credit: Jeff Hicks)
Getting unique history. (Image Credit: Jeff Hicks)

You can see that IDs 3, 4, 8, 9, and 10 have been eliminated. If you like this, it’s trivial to create a simple function.

function Get-MyHistory { get-history | select -Unique }

Or if you’d like something a bit more full featured, here’s a proxy version of Get-History that I created to not only allow you to get unique history items, but also to filter using simple or regular expression patterns.

Function Get-MyHistory {
<#
.SYNOPSIS
Gets a list of the commands entered during the current session.
.DESCRIPTION
The Get-MyHistory cmdlet gets session history, that is, the list of commands entered during the current session. This is a modified version of Get-History. In addition to the parameters of the original command, this version allows you to select only unique history entries as well as filter by a regular expression pattern.
Windows PowerShell automatically maintains a history of each session. The number of entries in the session history is determined by the value of the $MaximumHistoryCount preference variable. Beginning in Windows PowerShell 3.0, the default value is 4096.
You can save the session history in XML or CSV format. By default, history files are saved in the home directory, but you can save the file in any location.
For more information about the history features in Windows PowerShell, see about_History (http://go.microsoft.com/fwlink/?LinkID=113233).
.PARAMETER Count
Displays the specified number of the most recent history entries. By, default, Get-MyHistory gets all entries in the session history. If you use both the Count and Id parameters in a command, the display ends with the command that is specified by the Id parameter.
In Windows PowerShell 2.0, by default, Get-MyHistory gets the 32 most recent entries.
.PARAMETER Id
Specifies the ID number of an entry in the session history. Get-MyHistory gets only the specified entry. If you use both the Id and Count parameters in a command, Get-MyHistory gets the most recent entries ending with the entry specified by the Id parameter.
.PARAMETER Pattern
A regular expression pattern to match something in the commandline.
.PARAMETER Unique
Only display command history items with a unique command.
.EXAMPLE
PS C:\>Get-MyHistory -unique
This command gets the unique entries in the session history. The default display shows each command and its ID, which indicates the order of execution as well as the command's start and stop time.
.EXAMPLE
PS C:\>Get-MyHistory -pattern "service"
This command gets entries in the command history that include "service".
.NOTES
The session history is a list of the commands entered during the session. The session history represents the order of execution, the status, and the start and end times of the command. As you enter each command, Windows PowerShell adds it to the history so that you can reuse it. For more information about the command history, see about_History (http://go.microsoft.com/fwlink/?LinkID=113233).
Beginning in Windows PowerShell 3.0, the default value of the $MaximumHistoryCount preference variable is 4096. In Windows PowerShell 2.0, the default value is 64. For more information about the $MaximumHistoryCount variable, see about_Preference_Variables (http://go.microsoft.com/fwlink/?LinkID=113248).
Learn more about PowerShell:
Essential PowerShell Learning Resources
**************************************************************** * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * **************************************************************** .INPUTS Int64 .OUTPUTS Microsoft.PowerShell.Commands.HistoryInfo .LINK Add-History Clear-History Invoke-History .LINK about_History #> [CmdletBinding()] Param( [Parameter(Position=0, ValueFromPipeline=$true)] [ValidateRange(1, 9223372036854775807)] [long[]]$Id, [Parameter(Position=1)] [ValidateRange(0, 32767)] [int]$Count, #parameters that I added [switch]$Unique, [regex]$Pattern ) Begin { #insert verbose messages to provide debugging and tracing information Write-Verbose "Starting $($MyInvocation.Mycommand)" Write-Verbose "Using parameter set $($PSCmdlet.ParameterSetName)" Write-Verbose ($PSBoundParameters | out-string) #remove Unique and Pattern parameters if used since they are not part of Get-History if ($Unique) { $PSBoundParameters.Remove("Unique") | Out-Null } if ($Pattern) { $PSBoundParameters.Remove("Pattern") | Out-Null } } #begin Process { #splat bound parameters to Get-History $all = Get-History @PSBoundParameters if ($Pattern) { #use v4 Where method for performance purposes Write-Verbose "Searching for commandlines matching $pattern" $all = $all.where({$_.commandline -match $pattern}) } if ($Unique) { Write-Verbose "Selecting unique items" $all = $all | Select-Object -Unique } #write results to pipeline and add a new property $all | Add-Member -MemberType ScriptProperty -Name "Runtime" -value {$this.EndExecutionTime - $this.StartExecutionTime} -PassThru -force } #process End { Write-Verbose "Ending $($MyInvocation.Mycommand)" } #end } #end function Get-MyHistory #define an optional alias Set-Alias -Name gmh -Value Get-MyHistory

With this tool, I can do things like this:

Using a proxy version of Get-History. (Image Credit: Jeff Hicks)
Using a proxy version of Get-History. (Image Credit: Jeff Hicks)

Finally, I’ve never had the need, but you can clear your history with the Clear-History cmdlet. You’ll get new history the next time you start a PowerShell session. I recommend taking a minute or two to read about the Clear-History cmdlet.

I’m hoping that having a few tools to help you find what you need will make your PowerShell work much more enjoyable and productive.