PowerShell RunspacePoolで並列処理する ― 数百台管理でWaitAllを使う前に知っておくこと

PowerShellカテゴリを表すパンダのイラスト PowerShell

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Microsoft LearnのPowerShell並列実行資料と.NET WaitHandle仕様を確認し、旧コードの大量タスク待機と自動復旧に関する問題を修正しました。

検証ステータス:✅ Microsoft PowerShell / .NET公式仕様確認済み

PowerShellで多数の対象を並列処理する方法の一つがRunspacePoolです。PowerShell 7ならForEach-Object -Parallelの方が簡単な場面も多い一方、Windows PowerShell 5.1を含め、実行環境や初期セッション状態を細かく制御したい場合はRunspacePoolが候補になります。

RunspacePoolの基本構造

考え方は「実行枠を先に作り、その枠へ仕事を投入する」です。

  1. CreateRunspacePool()で最小・最大Runspace数を決める。
  2. Open()でPoolを開始する。
  3. 処理ごとにPowerShellインスタンスを作り、Poolへ割り当てる。
  4. BeginInvoke()で非同期実行する。
  5. 完了した処理をEndInvoke()で回収する。
  6. 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待ち中心の処理なら標準機能と実測比較してから選びます。

公式情報

この記事の更新履歴

  • 2026-09-14 追加:WaitAllの64ハンドル制限、完了タスクを逐次回収する考え方を追加。
  • 2026-09-14 変更:サービス自動再起動中心の例から、読み取り監視・承認付き復旧を分ける設計へ変更。
  • 2026-09-14 削除:内部メタデータ、本文H1、未検証ドラフト表記、擬似性能値、数百タスクをWaitAllで一括待機するコードを削除。

文書情報

記事タイトル
PowerShell RunspacePoolで並列処理する ― 数百台管理でWaitAllを使う前に知っておくこと
作成日
更新日
Source URL
https://papanda925.com/?p=5366

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました