PowerShell Genie

PowerShell Runspaces

Runspaces are the machinery underneath thread jobs and ForEach-Object -Parallel. Working with them directly means creating a RunspacePool, adding PowerShell instances to it, starting them asynchronously and collecting the results yourself.

Lesson 2 min read Windows PowerShell 5.1 and PowerShell 7

Documentation: Microsoft Learn

Overview

The honest answer about when to use them: rarely. ForEach-Object -Parallel and Start-ThreadJob cover almost every real case with a fraction of the code. Reach for raw runspaces when you need something they do not give you, such as precise control over the pool's lifetime, custom initial session state, or throughput across tens of thousands of items where the wrapper overhead actually shows up.

The cost is real. You manage disposal yourself, and a forgotten .Dispose() leaks memory across a long-running process. Errors surface inside each instance rather than in your error stream, so you have to collect them deliberately or they disappear. Debugging is genuinely harder.

Before writing runspace code, measure. People often assume concurrency is the bottleneck when the real problem is an unfiltered query pulling far too much data.

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.

$plan = [pscustomobject]@{ Approach = 'RunspacePool' MinRunspaces = 1 MaxRunspaces = 8 UseWhen = 'thousands of items, need full control' UseInstead = 'ForEach-Object -Parallel for most work' } $plan | Format-List
  1. Stage 1$planPositional values or no named parameters
  2. Stage 2Format-ListPositional values or no named parameters

    An example to inspect

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

    $plan = [pscustomobject]@{
      Approach = 'RunspacePool'
      MinRunspaces = 1
      MaxRunspaces = 8
      UseWhen = 'thousands of items, need full control'
      UseInstead = 'ForEach-Object -Parallel for most work'
    }
    $plan | Format-List

    What happens

    This prints a decision summary rather than building a pool, because a real pool needs disposal and this console does not persist. The MinRunspaces and MaxRunspaces values map to the arguments of RunspaceFactory.CreateRunspacePool, and the last two properties are the part worth remembering.

    Worth remembering

    • Runspaces sit under thread jobs and ForEach-Object -Parallel.
    • You manage disposal; a missed Dispose leaks memory.
    • Errors stay inside each instance unless you collect them.
    • Measure first. The bottleneck is often an unfiltered query.

    Primary documentation

    ForEach-Object reference

    Try it

    Illustrative output · values vary by environment

    1PS> $plan = [pscustomobject]@{
    2PS> Approach = 'RunspacePool'
    3PS> MinRunspaces = 1
    4PS> MaxRunspaces = 8
    5PS> UseWhen = 'thousands of items, need full control'
    6PS> UseInstead = 'ForEach-Object -Parallel for most work'
    7PS> }
    8PS> $plan | Format-List

    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.

      Prints when raw runspaces are worth the complexity and when they are not.

      Show reference output

      Illustrative output · values vary by environment

      Approach     : RunspacePool
      MinRunspaces : 1
      MaxRunspaces : 8
      UseWhen      : thousands of items, need full control
      UseInstead   : ForEach-Object -Parallel for most work

      Keep going

      Next: PowerShell Performance measurement
      Genie guidePowerShell Runspaces

      Runspaces are the machinery underneath thread jobs and ForEach-Object -Parallel. Working with them directly means creating a RunspacePool, adding PowerShell instances to it, starting them asynchronously and collecting the results yourself.