Summary: Learn how to use the Windows PowerShell history cmdlets to speed execution of repetitive commands.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I recently read that Windows PowerShell keeps a history of commands. I am not sure if this is true or not because I cannot seem to figure out how to get to that history. Even if I did get the history of my Windows PowerShell, I am not sure what I would have. It seems it might be useless, or am I wrong?

-- JB

 

Hey, Scripting Guy! AnswerHello JB, Microsoft Scripting Guy Ed Wilson here. The Scripting Wife and I are in one of the oldest places in the United States, St. Augustine, Florida. When I was a kid growing up in Florida, St. Augustine was my favorite place to visit because I have always been fascinated with history. The Spanish Castillo de San Marcos still maintains its fascination for me. Here is a picture I took today of Dr. Scripto hanging at the 300 year old fortress.

 

JB, there is also the story about Ponce de León looking for the fountain of youth but as you can see, Dr. Scripto has indeed found it for he has not aged a bit (no pun intended) in all the years I have known him. What is the fountain of youth you may ask? It is scripting! Yes, scripting is what keeps Dr. Scripto young and helps him to maintain his youthful appearance.

Speaking of history, there are four Windows PowerShell cmdlets that allow you to work with history. The cmdlets appear here.

PS C:\> Get-Command -Noun history

 

CommandType     Name                                      Definition

-----------     ----                                      ----------

Cmdlet          Add-History                               Add-History [[-InputObject] <PSObject[...

Cmdlet          Clear-History                             Clear-History [[-Id] <Int32[]>] [[-Cou...

Cmdlet          Get-History                               Get-History [[-Id] <Int64[]>] [[-Count...

Cmdlet          Invoke-History                            Invoke-History [[-Id] <String>] [-Verb...

 

 

PS C:\>

 

When I am looking for cmdlets that allow me to work with a particular thing, I use the Get-Command cmdlet and supply the thing I am looking for to the noun parameter. When I wish to obtain something, or to retrieve something, the verb is always get. Given this pattern, it is easy to discover that the command that allows me to get the history would be called Get-History. This intuitive pattern of naming is one of features that Windows PowerShell uses to aid in command discovery. When writing Windows PowerShell cmdlets or even when writing functions, one should always use approved verbs, and follow the verb-noun naming convention.

JB, one way I use the history is when I am experimenting with different commands, and I am attempting to work out a syntax that might be strange. I find that when I type more than a dozen different commands, I begin to forget what I have typed and I lose their position in the “up arrow” “down arrow” “recall a recent command” queue. Because several commands may, in fact, have very similar configurations, with only a single subtle difference amongst them, I find it hard to pick the command that works correctly. This is when I reach for the Get-History Windows PowerShell cmdlet. By displaying a history of my command attempts, in the order in which they were typed, I can easily pick out the one that works the way I wish. When I am working interactively like this, I use the alias h instead of typing Get-History.

To run a command from the history buffer, I could, of course, highlight the command with my mouse, press Enter to copy the command onto the clipboard, and then right-click on the Windows PowerShell console command line to paste the command onto a line. I then press Enter to run the command. It is a lot of mousing around, but is probably better than attempting to retype the command. However, there is a much shorter solution. I use the Invoke-History Windows PowerShell cmdlet to run the command. When working interactively, I use the alias r instead of typing Invoke-History. Therefore I have two really short aliases at my disposal: h for Get-History and r for Invoke-History. I think of r as standing for run as it helps me to remember the alias. In the following figure, I retrieve the history of 13 commands that were typed into the Windows PowerShell console by using the alias h instead of typing the complete Get-History command. Once I have a chance to review the 13 commands, I see that the one I am interested in running again is the 13 command. The command to run the 13 command uses the alias r for Invoke-History, and I specify that I want event ID 13 to execute.

 

Suppose I have typed several commands to check the status of the search service on my Windows 7 laptop. I make some changes, and then would like to run all of the commands a second time. This is a fresh Windows PowerShell console, and I have only typed the three commands that are listed here. I use the alias gps for the Get-Process cmdlet, and I use the alias gsv for the Get-Service cmdlet. The three commands are listed here.

Get-WinEvent -FilterHashtable @{"id"="3036";"logname"="application"} -maxevents 5

gps -Name *search*

gsv -Name *search*

 

The commands and their associated output appear in the following figure.

 

To run these three commands automatically, I use the Get-History cmdlet to retrieve a listing of the commands, I then pipeline them to the Foreach-Object cmdlet, and inside the scriptblock I call the Invoke-History cmdlet and pass it the id property of each command. The version of the command I run uses aliases as appears here.

h | % {r $_.id}

 

The command without using aliases appears here.

Get-History | Foreach-Object { Invoke-History –id $_.id }

 

The output from the command appears in the following figure.

 

The alias command is hard to read, but the worst thing is that the output from the Get-Process cmdlet (gps) and the output form the Get-Service cmdlet (gsv) does not display properly. After spending over an hour messing around, I arrive at the conclusion that when the Get-WinEvent cmdlet runs first, it messes up the output display in the console. The solution is to change the order. The cool thing about this is that it provides an opportunity to display running only selected commands, and in a different order.  

I use the command seen here to run the second, third, and the first commands in the history buffer.

Get-History 2,3,1 | Foreach-Object { Invoke-History -id $_.id }

 

The output of the history buffer and the command seen above appears in the following figure.

 

JB, that is all there is to using Get-History and Invoke-History. Neglected cmdlet week will continue tomorrow when I will talk about the Add-History cmdlet.

I invite you to follow me on Twitter or Facebook. If you have any questions, send email to me at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson, Microsoft Scripting Guy