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