PoshBytes: Stop Guessing and Start Measuring with Stopwatch

PoshBytes: Stop Guessing and Start Measuring with Stopwatch

Learn how to time PowerShell code with System.Diagnostics.Stopwatch and read TimeSpan output correctly, including a visible progress pause you can actually watch.

This post is a companion for the video embedded below. Scroll down to see the code from the video.

The Basic Stopwatch

Output elapsed time

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

Start-Sleep -Seconds 2

$sw.Stop()

$sw.Elapsed

Stopwatch Methods and What They Actually Do

Restart resets AND starts in one call

$sw = New-Object System.Diagnostics.Stopwatch

$sw.Start()
Start-Sleep -Milliseconds 500

$sw.Stop()
$sw.ElapsedMilliseconds
Start-Sleep -Milliseconds 500
$sw.ElapsedMilliseconds  # unchanged

$sw.Start()
$sw.ElapsedMilliseconds
Start-Sleep -Milliseconds 300
$sw.Stop()
$sw.ElapsedMilliseconds

$sw.Reset()
$sw.ElapsedMilliseconds  # 0

$sw.Restart()
$sw.ElapsedMilliseconds
Start-Sleep -Milliseconds 200
$sw.Stop()
$sw.ElapsedMilliseconds

A Visible Pause You Can Watch

pause the script for a set number of seconds while showing a progress bar and elapsed time

Function Start-WaitProgress {
    param (
        [int]$SecondsToWait = 30
    )

    $id = 2147483600
    $sw = [system.diagnostics.stopwatch]::StartNew()
    while ($sw.Elapsed.TotalSeconds -lt $SecondsToWait) {
        $elapsed = [int]$sw.Elapsed.TotalSeconds
        $remaining = $SecondsToWait - $elapsed

        $WriteProgressParam = @{
            Activity        = "Waiting $SecondsToWait seconds"
            Status          = "Elapsed: $elapsed s  Remaining: $remaining s"
            PercentComplete = $( ( $elapsed / $SecondsToWait ) * 100 )
            id              = $id
        }
        Write-Progress @WriteProgressParam
        Start-Sleep -Seconds 1
    }
    Write-Progress -Activity "Done" -Id $id -Completed
}

Start-WaitProgress 30

Breaking a While Loop Before It Ruins Your Day

Breaking a While Loop

$sw = [System.Diagnostics.Stopwatch]::StartNew()
$myExpectedResults = 2
while ($Results -ne $myExpectedResults -and $sw.Elapsed.TotalSeconds -lt 3) {
    $Results = Invoke-ExternalCallThatSometimesWorksRight
    Write-Host "Got result: $Results after $($sw.ElapsedMilliseconds) ms"
    Start-Sleep -Milliseconds 200
}

$sw.Stop()
$sw.Elapsed

Wrap Up

• Stopwatch gives you accurate timing without guessing
• TimeSpan Total* properties are full duration values, non total properties are just the component parts
• Use Restart() to time multiple sections cleanly
• Use elapsed time to build safe loop timeouts and visible waiting progress