Windows PowerShell: Those Who Forget History

One way or the other, Windows PowerShell can recall your most recently used commands, which can be a huge help.

Don Jones

“Those who forget history,” the old saying goes, “are doomed to repeat it.” In the case of Windows PowerShell, however, you’ll want to repeat history, so you’ll need to remember it precisely. Windows PowerShell automatically remembers commands you’ve recently run, and holds them in a buffer—or history—so you can more easily recall and run them again.

Historical Choices

When you’re using the Windows PowerShell console, you can actually work with two kinds of command history. The two are completely independent and have nothing to do with each other.

The first is the command-line buffer, with which you’re probably familiar. This is what comes up when you hit the Up Arrow key to recall a previously run command. You can also press F7 to get a menu of previously run commands. Once you see the menu, use the arrow keys to select a command and press Enter, and it will run.

The command-line buffer retains the last 50 commands by default. You can increase or decrease that setting by editing the properties of the console window itself. Click on the window’s control box and select Properties. Change the size of the “Command History buffer size” on the Options tab.

This command history is actually separate from Windows PowerShell itself. It’s maintained by the console-hosting application. Windows PowerShell isn’t even aware this exists.

A History You Can Use

The history Windows PowerShell itself maintains is more useful. Run Get-Command –noun history to see the four built-in cmdlets that deal with this extended history log:

  • Add-History
  • Clear-History
  • Get-History
  • Invoke-History

There’s also a built-in variable: $MaximumHistoryCount. This sets the size of the Windows PowerShell internal command history buffer. It’s set to 64 by default. If you want to change it, simply set the variable to a new value. Any changes you make will only be active for the current shell session. If you want to make the change more permanent, add something like the following to your profile script:

$MaximumHistoryCount = 100

That might go into a file named [My ]Documents\WindowsPowerShell\profile.ps1, which is one of the four automatically executed profile scripts for which the shell searches.

Get-History is the main cmdlet we’ll look at, as it’s probably the most useful of the four. It produces objects of the HistoryInfo type. Those objects contain four properties you’ll find interesting:

  • CommandLine: the actual command that was run
  • StartExecutionTime: the time the command started
  • EndExecutionTime: the time the command ended
  • ExecutionStatus: the status of the command after completion; this will be something like “Completed” or “Stopped”

Combining these objects with other Windows PowerShell commands is where the cool stuff really begins. For example, suppose you open a brand-new shell window and laboriously run several specific commands to complete a complex task. Want to turn those commands into a script, so you can run them in that exact order over and over? Just do this:

Get-History | Select –Expand CommandLine | Out-File script.ps1

The trick here is the –ExpandProperty parameter of Select-Object. It causes Select-Object to only output the contents of the specified property. In this case, it’s the CommandLine property of the HistoryInfo objects. These contain the text of the commands you just ran. Then you can edit the resulting Script.ps1 file in the Windows PowerShell ISE or another script editor to tweak the commands, turn hardcoded values into parameters, remove any commands that you don’t want and so on.

Suppose you did this trick and wound up with the following Script.ps1 file:

Import-Module ActiveDirectory
Import-CSV users.csv
Import-CSV users.csv | New-ADUser –path "ou=sales,dc=company,dc=com"

That may be a pretty short example, but by interactively running those commands, you can verify they’ll work—one step at a time. In fact, you can see where the second command was just a test import of the CSV file. This simply ensures it has the expected data. Then you can clean the script up and add parameters:

Param(
  [string]$filename = &(Read-Host "Specify input CSV filename"),
  [string]$path = "cn=Users,dc=company,dc=com"
)
Import-Module ActiveDirectory
Import-CSV $filename | New-ADUser –path $path

The “test import” command and the added parameters collect the CSV filename and destination OU. This is a better approach than leaving those values hardcoded. Make sure whoever runs this script will be prompted for a filename if they forget to specify one (this is kind of an ugly way to do that prompting—an advanced function would provide a cleaner, more consistent means of doing so). For the second parameter, specify a default that will suffice if someone doesn’t specify an alternate value.

This is an easy way to take a process you’ve manually completed once, and quickly turn it into a repeatable sequence of actions that even someone else could use.

More History Tricks

The ability to “get” the command-line history offers numerous other neat tricks:

  • Run Get-History | Export-CliXMLfilename to export commands to an XML file. Send the XML file to a colleague, and they can quickly repeat those commands by running Import-CliXMLfilename | Invoke-History.
  • Use the StartExecutionTime and EndExecutionTime properties to measure the time it took to complete a command. For example: get-history | select commandline,executionstatus,startexecutiontime,endexecutiontime,@{n='ExecutionDuration';e={$_.EndExecutionTime - $_.StartExecutionTime}}
  • Quickly locate past commands without having to scroll through with the Up Arrow key. For example, if you know you ran a command that used “Select,” try this to find it: get-history | where { $_.CommandLine -like '*select*' }

As always, Windows PowerShell treats everything as an object rather than a mass of text. This makes this kind of searching and filtering much more practical than if you were scanning through a text log file or something equally cumbersome.

Don Jones

Don Jones is a Microsoft MVP Award recipient and author of “Learn Windows PowerShell in a Month of Lunches” (Manning Publications Co., 2010), a book designed to help any administrator become effective with Windows PowerShell. Jones also offers public and on-site Windows PowerShell training. Contact him through his Web site at ConcentratedTech.com.