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.
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- Stage 1$plan
Positional values or no named parameters - Stage 2Format-List
Positional 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-ListWhat 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
Try it
Illustrative output · values vary by environment
Example reader
Inspect this page's example
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