この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Microsoft LearnのPowerShell並列実行資料と.NET WaitHandle仕様を確認し、旧コードの大量タスク待機と自動復旧に関する問題を修正しました。検証ステータス:✅ Microsoft PowerShell / .NET公式仕様確認済み
PowerShellで多数の対象を並列処理する方法の一つがRunspacePoolです。PowerShell 7ならForEach-Object -Parallelの方が簡単な場面も多い一方、Windows PowerShell 5.1を含め、実行環境や初期セッション状態を細かく制御したい場合はRunspacePoolが候補になります。
RunspacePoolの基本構造
考え方は「実行枠を先に作り、その枠へ仕事を投入する」です。
CreateRunspacePool()で最小・最大Runspace数を決める。Open()でPoolを開始する。- 処理ごとに
PowerShellインスタンスを作り、Poolへ割り当てる。 BeginInvoke()で非同期実行する。- 完了した処理を
EndInvoke()で回収する。 Dispose()で各PowerShellインスタンスとPoolを解放する。
最大Runspace数が事実上の同時実行上限になります。大量のサーバーがあるからといって、同時実行数まで数百・数千にする必要はありません。
旧コードのWaitAllは数百台向けではない
旧記事では、すべての非同期処理のAsyncWaitHandleを配列へ入れ、[System.Threading.WaitHandle]::WaitAll()へ一括で渡していました。しかし.NETの公式仕様では、WaitAllへ64個を超えるWaitHandleを渡すとNotSupportedExceptionになります。
したがって「数百台管理」のコードで全ハンドルを一度にWaitAllする設計は成立しません。大量タスクでは、完了状態を小刻みに確認して結果を回収する、一定数ずつバッチ処理する、といった設計が必要です。
最小構成の考え方
$pool = [runspacefactory]::CreateRunspacePool(1, 10)
$pool.Open()
$jobs = @()
foreach ($name in $ComputerName) {
$ps = [powershell]::Create()
$ps.RunspacePool = $pool
[void]$ps.AddScript({
param($ComputerName)
[pscustomobject]@{
ComputerName = $ComputerName
Reachable = Test-Connection $ComputerName -Count 1 -Quiet -ErrorAction SilentlyContinue
}
}).AddArgument($name)
$jobs += [pscustomobject]@{
PowerShell = $ps
Handle = $ps.BeginInvoke()
}
}
while ($jobs.Count -gt 0) {
foreach ($job in @($jobs)) {
if ($job.Handle.IsCompleted) {
$job.PowerShell.EndInvoke($job.Handle)
$job.PowerShell.Dispose()
$jobs = @($jobs | Where-Object { $_ -ne $job })
}
}
Start-Sleep -Milliseconds 100
}
$pool.Close()
$pool.Dispose()
これは構造を示す最小例です。本番運用ではタイムアウト、例外、キャンセル、ログ、再試行上限を追加します。
監視と「自動復旧」を一つにしない
旧記事は停止サービスを検出するとそのまま再起動する構成でした。数百台規模では、誤判定や同時障害時に変更が一気に広がるため、監視と復旧を分ける方が安全です。
- 第1段階:疎通やサービス状態を読み取りのみで収集する。
- 第2段階:異常候補を対象リストへまとめる。
- 第3段階:承認済み対象だけ復旧処理へ渡す。
- 第4段階:変更後の再確認とログ保存を行う。
大量処理では、速度よりも「止められること」「どこまで終わったか分かること」「同じ対象へ重複実行しないこと」が重要です。
PowerShell 7ならまず標準機能も比較する
MicrosoftはPowerShell 7の並列処理としてForEach-Object -ParallelやStart-ThreadJobも案内しています。独自RunspacePoolは柔軟ですがコード量が増えるため、単純なI/O待ち中心の処理なら標準機能と実測比較してから選びます。
公式情報
- Microsoft Learn ― Optimize performance using parallel execution
- Microsoft Learn ― WaitHandle.WaitAll Method
- Microsoft Learn ― RunspaceFactory.CreateRunspacePool
この記事の更新履歴
- 2026-09-14 追加:WaitAllの64ハンドル制限、完了タスクを逐次回収する考え方を追加。
- 2026-09-14 変更:サービス自動再起動中心の例から、読み取り監視・承認付き復旧を分ける設計へ変更。
- 2026-09-14 削除:内部メタデータ、本文H1、未検証ドラフト表記、擬似性能値、数百タスクをWaitAllで一括待機するコードを削除。

