Migration Guide
Upgrade Guide
How to adopt the new timeout API, what to watch out for, and what doesn't need to change.
01
No Action Required for Existing Code
All existing code continues to work unchanged.
The default value of
PSInvocationSettings.Timeout is Timeout.InfiniteTimeSpan.
Any code that does not touch Timeout takes the same code path as before — including
a fast-path in Invoke() that runs on the calling thread with zero overhead.
02
Opt-In: Bounded Invoke()
To get a timeout on a synchronous Invoke() call:
var settings = new PSInvocationSettings
{
Timeout = TimeSpan.FromSeconds(30)
};
var ps = PowerShell.Create();
ps.AddScript("Get-Process | Where-Object CPU -gt 100");
try
{
var results = ps.Invoke(null, settings);
// process results
}
catch (TimeoutException ex)
{
// timed out — log and move on
logger.Warn(ex.Message);
}
finally
{
ps.Dispose();
} STA COM caveat.
When
Timeout is finite, Invoke() uses Task.Run internally,
dispatching to a ThreadPool MTA thread.
If your script depends on STA COM apartment state, keep Timeout at its
default InfiniteTimeSpan.
03
Opt-In: Bounded Stop()
To stop a running pipeline with a time bound:
try
{
ps.Stop(TimeSpan.FromSeconds(10));
// ps.InvocationStateInfo.State == Stopped
}
catch (TimeoutException)
{
// Pipeline didn't stop in 10s
// May still be stopping in background
} The original Stop() (no argument) is unchanged. Stop(TimeSpan) is a new overload, not a replacement.
04
Runspace Reuse After Timeout
After an Invoke() throws TimeoutException, the runspace can be reused —
but allow a brief drain period (~500ms) for the background worker to finish stopping:
try { ps.Invoke(null, settings); }
catch (TimeoutException) { }
// Brief drain — let background stop thread finish
Thread.Sleep(500);
// Now safe to use same runspace
var ps2 = PowerShell.Create();
ps2.Runspace = runspace;
ps2.AddScript("'alive'");
var r = ps2.Invoke(); 05
Known Limitations
KL-01 · STA COM
Finite Timeout Uses MTA Thread
Scripts relying on STA COM apartment state must use
InfiniteTimeSpan.
KL-02 · CancellationToken
No CancellationToken Integration
Cooperative cancellation via
CancellationToken is not supported in this PR.
A follow-up RFC will address this.
KL-03 · Drain Delay
Runspace Reuse Needs ~500ms After Timeout
The background worker thread may still be alive when
TimeoutException is thrown.
Pause briefly before reusing the same runspace.
KL-04 · Internal Caps
Internal 30-Second Bounds Are Not Configurable
The 30s caps on
StopPipelines, LocalPipeline.Stop, etc.
are compile-time constants. Configurability is out of scope.