PowerShell Genie

PowerShell Performance measurement

Measure-Command tells you how long a block takes. Wrap the thing you suspect, run it a few times, and compare.

Lesson 2 min read Windows PowerShell 5.1 and PowerShell 7

Documentation: Microsoft Learn

Overview

There are two traps. First, Measure-Command discards output, so it is for timing rather than getting results. Second, one run is not a measurement. Startup effects, caching and other work on the machine move the number around, so run it several times and look at the spread.

The patterns that actually cost time in PowerShell are predictable. Appending to an array with += rebuilds the whole array on every iteration, which turns a loop into quadratic work; use a List or let the pipeline collect for you. Filtering after retrieval instead of at the source pulls data you throw away, which is why -Filter on a cmdlet beats Where-Object afterwards. And calling a remote command inside a loop pays connection setup on every pass.

A stopwatch is the alternative when you want both the timing and the results, or when you want to time part of a longer operation.

Inspect this example’s structure

Read the command and its supplied arguments. This example requires real PowerShell or its module; this diagram does not execute it.

$sw = [System.Diagnostics.Stopwatch]::StartNew() $sum = 0 foreach ($n in 1 .. 10000) { $sum += $n } $sw.Stop() [pscustomobject]@{ Sum = $sum Elapsed_ms = $sw.ElapsedMilliseconds }
  1. Stage 1$swPositional values or no named parameters

    An example to inspect

    Preview the example. Sign in for the full lesson and activities.

    $sw = [System.Diagnostics.Stopwatch]::StartNew()
    $sum = 0
    foreach ($n in 1 .. 10000) { $sum += $n }
    $sw.Stop()
    [pscustomobject]@{
      Sum = $sum
      Elapsed_ms = $sw.ElapsedMilliseconds }

    What happens

    A Stopwatch is started, the loop runs, then it is stopped. Building the result object gives you the answer and the timing together, which Measure-Command cannot do. Try the same loop with $list += $n against a growing array and the elapsed number climbs sharply, which is the += problem made visible.

    Worth remembering

    • Measure-Command times a block and throws away its output.
    • Run several times; a single measurement is noise.
    • Array += rebuilds the array each iteration. Use a List.
    • Filter at the source with -Filter rather than afterwards.

    Primary documentation

    PowerShell objects and pipelines documentation

    Try it

    Illustrative output · values vary by environment

    1PS> $sw = [System.Diagnostics.Stopwatch]::StartNew()
    2PS> $sum = 0
    3PS> foreach ($n in 1 .. 10000) { $sum += $n }
    4PS> $sw.Stop()
    5PS> [pscustomobject]@{
    6PS> Sum = $sum
    7PS> Elapsed_ms = $sw.ElapsedMilliseconds }

    Example reader

    Inspect this page's example

    Fictional browser data when supported

    Run supported commands against the practice data, or inspect the example without executing it.

    Ready to inspect.

      Times a loop with a stopwatch and returns the result and elapsed time together.

      Show reference output

      Illustrative output · values vary by environment

      Sum       Elapsed_ms
      ---       ----------
      50005000  3

      Keep going

      Next: PowerShell Scheduled Tasks
      Genie guidePowerShell Performance measurement

      Measure-Command tells you how long a block takes. Wrap the thing you suspect, run it a few times, and compare.