How to Use PowerShell’s History Feature

Bill Kindle

Read more posts by this author.

Have you forgotten a command while in the command-line, or do you wish you had saved history, PowerShell history to the rescue!

In this tutorial, learn how to run prior commands, import and export, and clear history. By the end of the article, you won’t have to rely solely on the up and down arrow keys to retrieve history anymore!

Prerequisites

To follow along with this tutorial, be sure you Windows PowerShell on Windows 10 or PowerShell 7.x on any supported platform.

Retrieving Command History

If you have ever lost a command, you may want to save it to find later. If so, PowerShell saves time by saving your history for quick retrieval. To see your saved history, PowerShell has the Get-History cmdlet.

Before retrieving any history, you first need to build some, as the history is restarted on every console session. To do so, copy and run the code below to add history entries; any code will do. Commands need to exist before Get-History has anything to return!

Get-Service -ServiceName 'BITS'
Get-Service | Where-Object -Property Name -Like "Microsoft*"
Get-Service | Where-Object -FilterScript {($_.Status -eq 'Running') -and ($_.StartType -eq 'Manual')}

Now that you have run some commands, as shown below, you have history to work with.

Building PowerShell command history.
Building PowerShell command history.

Be mindful of sensitive commands that may contain info not meant for prying eyes. For example, if you do not use secure strings in your code, sensitive information such as a password or API secret will be visible as plain text in the history file!

Now use the Clear-Host command to tidy up the screen and further demonstrate the history features.

Clear-Host
Tidy up the screen with Clear-Host.
Tidy up the screen with Clear-Host.

Clearing the screen doesn’t mean that all history entries are gone. To find the commands previously cleared, hit the up ↑ or down ↓ arrows to quickly view the console hosts’ command history.

Using up ↑ and down ↓ arrow keys to view console hosts command history
Using up ↑ and down ↓ arrow keys to view console hosts command history

Using the up and down arrows is great when finding a single command you ran previously. But what about re-running more than one command? In that case, to display your full session history, type in the Get-History command as seen below, which presents a list of previously run commands.

As shown below, Get-History returns not only the commands that were run but also a command ID and how long that command took to execute. The command ID will come in handy later.

Get-History
Displaying the output of the Get-History command.
Displaying the output of the Get-History command.

The maximum default history entries are 4096 as stored in the MaximumHistoryCount variable. Change this value to allow up to 32767 entries with the command: Set-Variable MaximumHistoryCount 32767.

By default, the Get-History cmdlet doesn’t return all object properties. To return all object properties, pipe the history output to the Select-Object cmdlet. Piping the output to the Select-Object cmdlet returns the StartExecutionTime and EndExecutionTime properties and are referenced to determine the Duration.

Get-History | Select-Object -Property *
Viewing additional Get-History properties.
Viewing additional Get-History properties.

Running Previously Executed Commands

Now that you can retrieve older commands, what good is that? Most of the time, PowerShell users need to execute those commands. Luckily, you can do so without copying/pasting. Remembering a previous command or series of commands may be difficult. To run a previous command, execute the Invoke-History cmdlet.

If you have been following along, you will have a previous Get-Service command in your history. As mentioned earlier, each history entry has an associated ID.

Perhaps you need to re-run one of the Get-Service commands you ran earlier. In that case, copy and run the code below to re-run the second history entry, as shown in the below demonstration.

Invoke-History -Id 2

Your ID value may need to change depending on your personal command history.

Specifying a value of 2 for the ID parameter, the Invoke-History cmdlet immediately re-runs the command as if you had typed the command directly into the console.

Re-running a past command with Invoke-History.
Re-running a past command with Invoke-History.

In addition to a number, the ID parameter also accepts a pattern to match against. For example, running Invoke-History -Id 'Get-Service' will find all history entries starting with that value.

Exporting PowerShell Command History

After a long work session, you may want to save and export your commands. If so, you’re in luck. PowerShell can export nearly anything to a text file; command history is no different. When working with command history, common formats include CSV or XML.

Save your PowerShell history for future use, as shown below. Piping Get-History to the Export-CSV cmdlet allows you to save the history entries to a file. In this example, PowerShell saves the file to C:\Temp, but you can save the command history anywhere.

Get-History | Export-CSV -Path 'C:\Temp\CommandHistory.Csv'
Exporting command history.
Exporting command history.

To export the history as XML: Get-History | Export-CliXml -Path ‘C:\Temp\CommandHistory.xml’

Clearing Command History

Over time your history may become cluttered or you may have run a command with a sensitive value that is now saved to history. In either case, you probably want to remove those entries from your command history. To do that, to clear the console history, with the Clear-History cmdlet.

By default, the Clear-History command removes all console history. But, what if you don’t want to delete all history? In that case, selectively clear history with a specific entry ID, a specified Count of entries, or only the Newest set of entries.

If you don’t want to type in or locate a specific set of entries, pass an array of wildcard patterns to the CommandLine parameter to remove all matched commands.

Clear-History -CommandLine *Help*, *Syntax

There is another type of history, which is saved to disk via the PSReadLine module. The Clear-History cmdlet only clears the current in-memory console history, but you may also want to clear all saved disk history entries.

To clear all history except for the last run command, use the PSReadline method by running: [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()

Before clearing the disk history, you must find where it is saved. To do that, copy and run the following command to retrieve the history file disk location.

$History = (Get-PSReadLineOption).HistorySavePath
$History
Locating the history file save path.
Locating the history file save path.

The default PSReadLine Windows path is stored in the HistorySavePath variable and is: %userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

Now open the history file in notepad, similar to what is shown below. Each history entry is added below the last saved command.

History File in Notepad
History File in Notepad

Now that you have seen where and what is in the history file, remove the history file with the Remove-Item cmdlet, as shown below.

Remove-Item -Path $History -Verbose
Removing the history file.
Removing the history file.

Upon running another command, the history file will be regenerated.

Importing Command History

If you have opened a new console session or have previously saved a complicated series of commands, you may want to import them into your current history. To import those commands into your current console history, leverage the Add-History command.

To import prior history, you first need an exported history file. In a previous section, you saved a series of commands in a CSV file, and perhaps you need to import those saved commands. To import the previous CSV file and add history entries to the current session, run the below code, adjusting your CSV path as necessary.

$O$OldHistory = Import-Csv -Path 'C:\Temp\CommandHistory.Csv'
 
Add-History -InputObject $OldHistory -Passthru

As shown below, PowerShell imported the previous commands into console history and displayed them with the PassThru parameter.

Not all commands return the original objects passed in. By adding the PassThru parameter, available on some cmdlets, the original object is returned.

Importing exported PowerShell command history.
Importing exported PowerShell command history.

Considering Security and PowerShell History

Despite the usefulness of PowerShell history, there are security considerations to be aware of. You will want to be mindful when entering sensitive commands, as those commands are saved to the plaintext command history file, subject to scrutiny.

Pretend for a moment you are a ‘Red Teamer‘. You want to do some recon on a target user. You may be interested in commands they run, passwords and API keys they may be passing through the session during a normal day.

Here’s a sample of what you could see looking at a target’s history file in real time, by just reloading the text file in Notepad++:

Reloading Text File in Notepad
Reloading Text File in Notepad

Now you have a password that the target is using. Just watching the rest of the session history and you’ll more than likely see where that password is being used.

Don’t be alarmed by what you’ve seen. Knowing what you know now, you can make better decisions.

How do you securely handle secrets? By retrieving credentials from disk or keyboard input with the Get-Credential cmdlet. Secure those API keys and other secrets by converting to a secure string with the ConvertTo-SecureString cmdlet. Both cmdlets will not display the secret itself in history. PowerShell Secrets Management is also a good choice.

In any environment, turning on ScriptBlock and Module logging is prudent. With this logging, PowerShell is a poor choice for an attacker to use, as every run of code is stored for later retrieval.

What’s Next?

You should now know how the PowerShell history commands work. Now the next time you lose an important command or need to save your session’s history, you have no excuse!

If you need to clear all history except for the last run command, use the PSReadline method by running

Subscribe to Stay in Touch

Never miss out on your favorite ATA posts and our latest announcements!

Looks like you're offline!