Fun With PowerShell – Elapsed Timers

Introduction

I’m still working on my documentation for my ArcaneBooks project, but wanted to have something for you to read this week, so decided to show you how to create an elapsed timer in PowerShell.

It can be helpful to determine how long a process runs in PowerShell. You can use it to determine what parts of code may need to be optimized, or gather metrics around your functions.

Creating and Using a Timer

The .NET framework has a class named System.Diagnostics.Stopwatch. It has a static function named StartNew that you can call which will create a new instance from the Stopwatch class.

$processTimer = [System.Diagnostics.Stopwatch]::StartNew()

So now you go off and do your code, routine, whatever it is you want to measure. When you are done, you call the Stop method of your timer.

$processTimer.Stop()

Now what? How do we get the time from this? Well to do that you can grab the Elapsed property of your timer.

$processTimer.Elapsed

This produces the following output:

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 20
Milliseconds      : 698
Ticks             : 206988710
TotalDays         : 0.000239570266203704
TotalHours        : 0.00574968638888889
TotalMinutes      : 0.344981183333333
TotalSeconds      : 20.698871
TotalMilliseconds : 20698.871

It’d be nice to have it in something more readable. So in this example I’ll capture the elapsed time into a variable, then use PowerShell’s string formatting technique to produce something easily understandable.

$ts = $processTimer.Elapsed
$elapsedTime = "{0:00}:{1:00}:{2:00}.{3:00}" -f $ts.Hours, $ts.Minutes, $ts.Seconds, ($ts.Milliseconds / 10)
Write-Host "All done - Elapsed Time $elapsedTime `r`n"

This produces:

All done - Elapsed Time 00:00:20.70

Alternatively you could use a string that expanded the time fields a bit. In this example I’ll also include the number of days. Since the timer shows days, milliseconds probably aren’t that important so I’ll omit them. If you needed it though it’d be easy enough to add.

$elapsedTime = "The process took $($ts.Days) days, $($ts.Hours) hours, $($ts.Minutes) minutes, and $($ts.Seconds) seconds."
Write-Host "All done - Elapsed Time $elapsedTime `r`n"

This will produce:

All done - Elapsed Time The process took 0 days, 0 hours, 0 minutes, and 20 seconds.

Multiple Timers

You may have a situation where you need multiple timers. For example, one for a full function, and a second to log the time of a loop in the function. Just create multiple process timer variables, for example $processTimer1 and $processTimer2.

There’s nothing special about the variable name either, you could use names like $myFunctionsTimer, $mainLoopTimer, and $loggingTimer.

See Also

If you want to learn more about the string formatting technique used in this post, see my Fun With PowerShell – String Formatting post.

Conclusion

Optimizing your PowerShell code is made much easier when you can measure the runtime of sections of code. It lets you know what sections are running slow, and when you make changes did you actually improve things or make it worse.

As you saw in this post, creating one or more timers is very simple. You can insert them into your code temporarily, or leave them there as part of your metrics logging strategy.

Advertisement