PoshBytes: Measure-Command For Optimizing Your Code

PoshBytes: Measure-Command For Optimizing Your Code

Measure-Command is the fastest way to find out how long a command actually takes, so you can stop guessing and start optimizing with receipts. We will time a few real scripts, compare approaches, and learn how to avoid misleading results.

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

Example: The basic “how long did that take”

Basic timing of a single command

$time = Measure-Command {
    Get-ChildItem -Path $env:TEMP -File -Recurse -ErrorAction SilentlyContinue | Out-Null
}
$time
"Seconds: {0:N3}" -f $time.TotalSeconds

Example: Compare two approaches like a tiny performance cage match

Compare two ways to build an array: += versus a generic list

$loops = 5000

$plusEquals = Measure-Command {
    $a = @()
    for ($i = 0; $i -lt $loops; $i++) {
        $a += $i
    }
}

$list = Measure-Command {
    $l = [System.Collections.Generic.List[int]]::new()
    for ($i = 0; $i -lt $loops; $i++) {
        $l.Add($i)
    }
}

[pscustomobject]@{
    Loops              = $loops
    PlusEqualsSeconds  = [math]::Round($plusEquals.TotalSeconds, 4)
    ListAddSeconds     = [math]::Round($list.TotalSeconds, 4)
    Winner             = if ($list.TotalSeconds -lt $plusEquals.TotalSeconds) { "List.Add()" } else { "+=" }
}

Example: Measure your code, not PowerShell

$rawTime = Measure-Command {
    1..200000 |
        Where-Object { $_ % 3 -eq 0 } |
        ForEach-Object { [math]::Sqrt($_) }
}
$rawTime.TotalSeconds

Measure a pipeline doing real work

$ftTime = Measure-Command {
    1..200000 |
        Where-Object { $_ % 3 -eq 0 } |
        ForEach-Object { [math]::Sqrt($_) } |
        Format-Table
}
$ftTime.TotalSeconds

Measure a pipeline doing real work

$nullTime = Measure-Command {
    1..200000 |
        Where-Object { $_ % 3 -eq 0 } |
        ForEach-Object { [math]::Sqrt($_) } |
        Out-Null
}
$nullTime.TotalSeconds

"Raw Output : {0:N3}`nPipeline   : {1:N3}`nOut-Null   : {2:N3}" -f $rawTime.TotalSeconds, $ftTime.TotalSeconds, $nullTime.TotalSeconds

Example 4:

Run multiple times and average the result

$runs = 5
$results = foreach ($n in 1..$runs) {
    Measure-Command {
        Start-Sleep -Milliseconds 120
    }
}

$avgMs = ($results | Measure-Object -Property TotalMilliseconds -Average).Average
$minMs = ($results | Measure-Object -Property TotalMilliseconds -Minimum).Minimum
$maxMs = ($results | Measure-Object -Property TotalMilliseconds -Maximum).Maximum

[pscustomobject]@{
    Runs      = $runs
    AverageMs = [math]::Round($avgMs, 2)
    MinMs     = [math]::Round($minMs, 2)
    MaxMs     = [math]::Round($maxMs, 2)
}

Wrap Up

• Measure-Command times anything you can put in a script block and returns a TimeSpan
• Use it to compare approaches, not just to confirm a command feels slow
• Run tests multiple times and summarize results to reduce “one run lies” syndrome
• Avoid adding formatting or extra output inside the measured block if you want clean numbers