Press "Enter" to skip to content

Month: April 2018

How long did that last PowerShell command take?

Today Thomas Rayner’s post on Get-History reminded me of a one liner I use to calculate time spent on the last command.

(Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 87
Ticks             : 870022
TotalDays         : 1.00696990740741E-06
TotalHours        : 2.41672777777778E-05
TotalMinutes      : 0.00145003666666667
TotalSeconds      : 0.0870022
TotalMilliseconds : 87.0022


You can select any property from the output and get just the TotalSeconds, but I like this simple output for when I have to leave some work in progress and I need to come back and check some time in the future.

If you are confused by this code and want further explanations, keep reading!

A typical Get-History call returns the following to Get-Member.

PS C:\temp> Get-History | Get-Member

   TypeName: Microsoft.PowerShell.Commands.HistoryInfo

Name               MemberType Definition
----               ---------- ----------
Clone              Method     Microsoft.PowerShell.Commands.HistoryInfo Clone()
Equals             Method     bool Equals(System.Object obj)
GetHashCode        Method     int GetHashCode()
GetType            Method     type GetType()
ToString           Method     string ToString()
CommandLine        Property   string CommandLine {get;}
EndExecutionTime   Property   datetime EndExecutionTime {get;}
ExecutionStatus    Property   System.Management.Automation.Runspaces.PipelineState ExecutionStatus {get;}
Id                 Property   long Id {get;}
StartExecutionTime Property   datetime StartExecutionTime {get;}

Ignoring the methods (as they are common) we see we have access to some useful properties:

  • The CommandLine which contains the text typed in the console.
  • The ExecutionStatus which tells you if your command was successful.
  • The StartExecutionTime and EndExecutionTime, which store the start time and end time of your running command.
  • The Id, which is just a sequential integer indicating its order in the history.

As is common in PowerShell, even though we see the list of members and properties the information actually only represents one item in the list of objects the command returns, one for each history row.

If you want to see an example this, we can use PowerShell’s comma/unary operator to roll our multiple elements into one bag of elements.

PS C:\temp> $many = Get-History # Assign all our Get-History rows to $many
PS C:\temp> $one = , (Get-History) # Prevent unrolling the items with the , 

PS C:\temp> $many.Count # I ran 18 previous commands when this was assigned
PS C:\temp> $one.count # This is a bag holding 18 items

This technique was new to me when I first started PowerShell, but a useful trick if you want to write a function that returns an object representing the entire list, instead of returning a series of elements. If you want to learn more about the Comma operator, check the documentation in about_Operators.

The next step is to ask for the first element of a list, which PowerShell supports with bracket notation (list)[element_number], with 0 being the first number (as all sane programming languages choose.)

We use dot notation to access the properties of EndExecutionTime and StartExecutionTime, once each for our specific list item, (list)[element_number].property.

Lastly, we subtract the properties from one another (list)[element_number].property – (list)[element_number].property, which PowerShell determines behind the scenes is two dates being subtracted, performs the required math, and usefully returns a useful System.TimeSpan type representing the time between the two dates.

Special thanks to Contributing Editor John G Hohengarten for his thoughtful additions to this post.