WMI/CIMを活用したマルチノード並列ヘルスチェック・自動モニタリング

Tech

[META:STYLE_PS_ENGINEER] 本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

WMI/CIMを活用したマルチノード並列ヘルスチェック・自動モニタリング

【導入:解決する課題】 多数のリモートPCに対するOS状態確認とエラーログ収集を並列化し、管理者の巡回コストを最小化します。

【設計方針と処理フロー】 標準のCIMコマンドレット(WS-Managementプロトコル)を採用し、DCOM依存の古いWMIコマンドレットを排除します。処理の高速化のため、PowerShell 7の-Parallelパラメータを利用した並列実行設計を行います。

graph TD
A["PCリスト読み込み"] --> B["CIMセッションの確立"]
B --> C{"並列処理実行"}
C --> D["システム情報取得: Win32_OperatingSystem"]
C --> E["リソース監視: Win32_LogicalDisk"]
C --> F["イベントログ収集: Win32_NTLogEvent"]
D --> G["カスタムオブジェクト生成"]
E --> G
F --> G
G --> H["CSV/JSON出力・ログ記録"]

【実装:コアスクリプト】

function Get-RemoteSystemHealth {
    <#
    .SYNOPSIS
        複数のリモートPCからシステム状態とエラーイベントを取得します。
    .DESCRIPTION
        CIMセッションを使用して、CPU、メモリ、ディスク、直近のエラーログを並列で取得します。
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]]$ComputerNames,

        [int]$MaxConcurrency = 10,

        [int]$ErrorLogDays = 1
    )

    $results = $ComputerNames | ForEach-Object -Parallel {
        $computer = $_
        $logPath = "C:\Temp\HealthCheck_Log.txt" # 簡易ログパス

        try {

            # CIMオプションの設定(接続タイムアウト対策)

            $option = New-CimSessionOption -Protocol Wsman -ConnectTimeoutSec 5
            $session = New-CimSession -ComputerName $computer -SessionOption $option -ErrorAction Stop

            # 1. OS情報の取得 (ホスト名、OS、メモリ)

            $os = Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem

            # 2. ディスク空き容量の取得 (Cドライブ)

            $disk = Get-CimInstance -CimSession $session -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'"

            # 3. イベントログの取得 (直近X日のErrorレベルのみ)

            $filterDate = (Get-Date).AddDays(-$using:ErrorLogDays)
            $events = Get-CimInstance -CimSession $session -ClassName Win32_NTLogEvent `
                -Filter "Type='Error' AND TimeGenerated > '$($filterDate.ToString('yyyyMMddHHmmss.ffffff-000'))'"

            # 結果の集約

            [PSCustomObject]@{
                ComputerName = $computer
                Status       = "Online"
                OSCaption    = $os.Caption
                FreeMemoryGB = [Math]::Round($os.FreePhysicalMemory / 1MB, 2)
                DiskFreeGB   = [Math]::Round($disk.FreeSpace / 1GB, 2)
                ErrorCount   = ($events | Measure-Object).Count
                Timestamp    = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            }
        }
        catch {
            Write-Error "Failed to query $computer : $($_.Exception.Message)"
            [PSCustomObject]@{
                ComputerName = $computer
                Status       = "Offline/Error"
                OSCaption    = $null
                FreeMemoryGB = 0
                DiskFreeGB   = 0
                ErrorCount   = -1
                Timestamp    = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            }
        }
        finally {
            if ($session) { Remove-CimSession $session }
        }
    } -ThrottleLimit $MaxConcurrency

    return $results
}

# 実行例


# $targets = Get-Content "C:\nodes.txt"


# Get-RemoteSystemHealth -ComputerNames $targets | Export-Csv -Path "./HealthReport.csv" -NoTypeInformation -Encoding utf8

【検証とパフォーマンス評価】

  • 計測手法: Measure-Command { Get-RemoteSystemHealth -ComputerNames (1..50 | % { "PC-$_" }) } を使用。

  • 期待値:

    • 逐次処理(PS 5.1)の場合:1台あたり約3〜5秒(計150秒以上)。

    • 並列処理(PS 7.4)の場合:スロットル制限10並列で、ネットワーク遅延を含め約20〜30秒で完了。

  • リソース消費: CIMセッションはRPC/DCOMより軽量ですが、大量のイベントログ取得はリモート側のWMIサービスに負荷をかけるため、フィルタリング条件(Filter句)の最適化が必須です。

【運用上の落とし穴と対策】

  1. WinRMの有効化: リモートPC側で Enable-PSRemoting が実行されている必要があります。ワークグループ環境では TrustedHosts の設定も不可欠です。

  2. PS 5.1 vs 7 互換性: -Parallel スイッチは PowerShell 7 以降の機能です。Windows PowerShell 5.1 を維持する必要がある場合は、Workflow(非推奨)ではなく Start-JobRunspaces を検討してください。

  3. WMIクエリのタイムアウト: Win32_NTLogEvent は件数が多いと非常に低速です。必ず TimeGenerated によるフィルタリングを行い、取得件数を絞ってください。

  4. 文字コード: Export-Csv を行う際は、Excelでの閲覧を考慮して -Encoding utf8 (BOM付き) または unicode を指定してください。

【まとめ】

  1. CIMコマンドレットを優先: DCOM(135)ではなくWS-Man(5985)を使用し、モダンな管理インフラを構築する。

  2. サーバー側でフィルタリング: データを全取得してから抽出するのではなく、Filter 句を使用してリモート側で計算させる。

  3. 並列化による時短: ForEach-Object -Parallel を活用し、監視窓口のブロッキングを最小限に抑える。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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