PowerShell CIM/WMIによるリモートPC監視・イベントログ収集の自動化

Tech

[META] { “role”: “Senior PowerShell Engineer”, “focus”: “WMI/CIM Remote Monitoring”, “standard”: “Microsoft Learn (CIM over WMI)”, “vibe”: “Professional, Technical, Practical” } [/META]

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

PowerShell CIM/WMIによるリモートPC監視・イベントログ収集の自動化

【導入:解決する課題】 複数拠点のWindows端末におけるリソース枯渇や異常予兆を、WMI/CIMを通じてリモートから一括取得し、手動巡回点検の工数を劇的に削減します。

【設計方針と処理フロー】 本スクリプトでは、従来のDCOMベースであるGet-WmiObjectを避け、WS-Manプロトコルを利用するモダンなGet-CimInstanceを採用します。これにより、Firewallフレンドリーな通信と、New-CimSessionによるセッション再利用での高速化を実現します。

graph TD
A[Start] --> B["ターゲットリストの読み込み"]
B --> C["CIMセッションの確立"]
C --> D{"接続確認"}
D -- Success --> E["システム情報取得: OS/CPU/Disk"]
D -- Success --> F["イベントログ取得: Error/Warning"]
D -- Failure --> G["エラーログ記録"]
E --> H["結果の集約とオブジェクト出力"]
F --> H
G --> I["Next Computer"]
H --> I
I --> J["CSV/JSONレポート出力"]
J --> K[Finish]

【実装:コアスクリプト】 以下は、PowerShell 7の並列処理(-Parallel)を想定した、実戦的なリモート監視スクリプトです。

function Get-RemoteSystemStatus {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string[]]$ComputerNames,

        [Parameter(Mandatory = $false)]
        [pscredential]$Credential,

        [int]$MaxConcurrency = 5
    )

    $ComputerNames | ForEach-Object -Parallel {
        $computer = $_
        $result = [PSCustomObject]@{
            ComputerName = $computer
            Timestamp    = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            Status       = "Success"
            CPUUsage     = $null
            FreeMemoryGB = $null
            DiskFree     = $null
            RecentErrors = @()
            ErrorMessage = $null
        }

        try {
            $sessionOption = New-CimSessionOption -Protocol Wsman -Encoding Utf8
            $session = New-CimSession -ComputerName $computer -Option $sessionOption -ErrorAction Stop

            # 1. CPU使用率の取得 (Win32_Processor)

            $cpu = Get-CimInstance -CimSession $session -ClassName Win32_Processor | 
                   Measure-Object -Property LoadPercentage -Average
            $result.CPUUsage = "{0:N2}%" -f $cpu.Average

            # 2. メモリ情報の取得 (Win32_OperatingSystem)

            $os = Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem
            $result.FreeMemoryGB = "{0:N2} GB" -f ($os.FreePhysicalMemory / 1MB)

            # 3. ディスク空き容量 (Win32_LogicalDisk)

            $disks = Get-CimInstance -CimSession $session -ClassName Win32_LogicalDisk -Filter "DriveType=3"
            $result.DiskFree = $disks | ForEach-Object { "$($_.DeviceID) $([math]::Round($_.FreeSpace / 1GB, 2))GB" } -join " | "

            # 4. 直近1時間の重大なイベントログ (Get-WinEvent)


            # 注: Get-WinEventはCimSessionを直接取らないため、リモート取得

            $filterHash = @{
                LogName = 'System'
                Level   = 1, 2 # Critical, Error
                StartTime = (Get-Date).AddHours(-1)
            }
            $errors = Get-WinEvent -ComputerName $computer -FilterHashtable $filterHash -ErrorAction SilentlyContinue
            $result.RecentErrors = $errors.Message | Select-Object -First 3

            Remove-CimSession $session
        }
        catch {
            $result.Status = "Failed"
            $result.ErrorMessage = $_.Exception.Message
        }
        finally {
            $result
        }
    } -ThrottleLimit $MaxConcurrency
}

# 実行例


# $servers = Get-Content "./server_list.txt"


# $report = Get-RemoteSystemStatus -ComputerNames $servers


# $report | Export-Csv -Path "./HealthCheck_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding utf8

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

  • 計測例: Measure-Command { Get-RemoteSystemStatus -ComputerNames (1..10 | % { "PC$_" }) }

  • 期待値: 10台程度の同時実行であれば、CIMセッションのオーバーヘッドを含めても30〜60秒程度で完了します。

  • スケーラビリティ: ThrottleLimit を調整することで、100台規模の環境でもネットワーク帯域を圧迫せずにデータ収集が可能です。ただし、Get-WinEvent はログ量が多い場合に時間がかかるため、FilterHashtable でサーバー側フィルタリングを徹底することが重要です。

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

  1. PowerShell 5.1 vs 7:

    • ForEach-Object -Parallel は PowerShell 7 以降の機能です。Windows PowerShell 5.1 の場合は、Workflow もしくは Start-Job を検討するか、逐次処理に変更してください。
  2. WinRMの有効化:

    • リモート取得には Enable-PSRemoting が必須です。ドメイン環境ではGPOによる一括有効化を推奨します。
  3. 文字コード問題:

    • イベントログに日本語が含まれる場合、CIM接続のエンコーディングが不適切だと文字化けが発生します。New-CimSessionOption で明示的に指定してください。
  4. 二重ホップ問題:

    • 取得データをさらに別のサーバーの共有フォルダへ書き出す場合、認証の二重ホップ(Double Hop)問題が発生します。Kerberos委任の設定が必要です。

【まとめ】

  1. CIMを優先する: Get-WmiObject は非推奨であり、速度・セキュリティ面で Get-CimInstance が勝ります。

  2. フィルタリングはソース側で: Get-WinEvent は全件取得してから抽出するのではなく、必ず -FilterHashtable を使い、リモート側で絞り込みを行います。

  3. エラーハンドリングの徹底: リモート管理において「オフラインの端末」は必ず存在します。try/catch でスクリプト全体の停止を防ぐ設計が不可欠です。

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

コメント

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