Migration Guide

Upgrade Guide

How to adopt the new timeout API, what to watch out for, and what doesn't need to change.

No breaking changes Opt-in only
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.