PowerShell Command History and Buffers

When I teach PowerShell, there is always a little misunderstanding about where PowerShell stores its command history. It can get confusing because it looks like the same information is in different places, but the truth is a bit more complicated. This is especially true when you switch back and forth between the console and the PowerShell ISE.

PowerShell stores its command history for a given PowerShell session in memory. You can access this command history with the Get-History cmdlet, which has an alias of ‘h’. The number of commands stored is based on a built-in variable, MaximumHistoryCount, which I believe now has a default value of 4096.

The MaximumHistoryCount variable in Windows PowerShell. (Image Credit: Jeff Hicks)
The MaximumHistoryCount variable in Windows PowerShell. (Image Credit: Jeff Hicks)

 
As you run commands, they are added to the history. When I get to command 4095, the oldest command will be overwritten. If you would like a different value, simply assign a value to $MaximumHistoryCount in your PowerShell profile script. It shouldn’t matter what PowerShell host you use, but there should be command history. This potentially gets confusing with the PowerShell console host. This host sits atop the very old CMD.EXE command-line shell. This shell also has a command buffer, which you can access via the F7 key. Note that this only works in the PowerShell console. The PowrShell ISE doesn’t know anything about CMD.EXE, and thus there is no F7 functionality.
Back in my console, I press F7 and get this popup.
Using the F7 key command to bring up a pop-up in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the F7 key command to bring up a pop-up in Windows PowerShell. (Image Credit: Jeff Hicks)

 
I can use the arrow keys to move up and down the list. When I find a command I want to rerun, then all I have to do is press the enter key. The shell will paste the command and execute it. Or I can press the right arrow, which will insert the highlighted command but not execute it. This is very handy when you want to modify a previous command and save some typing.
This F7 command buffer is configured in the “Windows PowerShell” Properties and generally only needs to be set once.
The "Windows PowerShell" Properties. (Image Credit: Jeff Hicks)
The “Windows PowerShell” Properties. (Image Credit: Jeff Hicks)

 
The buffer size indicates how many commands the window will remember. The default is 50, and you can also modify it. I typically save a couple of hundred entries. This means that your PowerShell command history and this command buffer will be almost the same, but at some point they will start diverging. I also like using the Discard Old Duplicates feature so that the F7 buffer will eliminate duplicate and repeated commands. While you are at it, make sure that QuickEdit Mode is enabled. This allows you to select a block of text in the console window and press Enter to copy it. Or you can right-click at the prompt to paste any text from the clipboard into the console.

As I mentioned, you can select an item from the F7 buffer and run it only in the PowerShell console, which is why I generally get students used to using the history cmdlets. The easy way to re-invoke a previous command is to use Invoke-History, which has an alias of ‘r’. This makes it very easy to repeat commands with a minimum of effort.
Using the 'r' alias in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the ‘r’ alias in Windows PowerShell. (Image Credit: Jeff Hicks)

 
Note that even though you see the command listed, the output doesn’t include it:
The output of the 'r' alias. (Image Credit: Jeff Hicks)
The output of the ‘r’ alias. (Image Credit: Jeff Hicks)

 
The results in $a are the same as if I had typed the Get-Process command directly at the prompt.
One feature about the F7 buffer that I appreciate is the ability to insert a command back to the prompt and modify it before re-executing it. You can accomplish the same result with PowerShell history, although it takes a little work. Here is a function I wrote.

Function Set-InvokedCommand {
[cmdletbinding()]
Param(
[Parameter(Position=0,Mandatory,HelpMessage="Enter a command history ID number")]
[int]$ID
)
Add-Type -AssemblyName "microsoft.visualbasic" -ErrorAction Stop
$prompt = "Modify the command"
$title = "Run History"
Try {
$cmdText = (Get-History -Id $ID -ErrorAction Stop).CommandLine
[string]$cmd = [microsoft.visualbasic.interaction]::InputBox($Prompt,$Title,$CmdText)
if ($cmd) {
    Invoke-Expression -Command $cmd
}
}
Catch {
    Throw $_
}
} #end function

With the function loaded all I need to do is provide a history ID number. The command is inserted into a VB-style Inputbox.

Modifying the command with run history. (Image Credit: Jeff Hicks)
Modifying the command with run history. (Image Credit: Jeff Hicks)

 
I can modify the command and press OK, and PowerShell will run it. You can also search for command history from the prompt as well.

Type a # character and then start typing as much of the command as you remember. Pressing Enter should expand any matches, starting with the most recent. You can either run the command as is or modify it.
The typical philosophical warning is that those who don’t remember history are doomed to repeat it. In PowerShell if you don’t remember and reuse your history, then you are doomed to a life typing. Learn where PowerShell stores commands and how to take advantage of it. Read about_history for more details.