[CIM/WMI] リモートPCの状態監視とイベントログ一括取得の自動化

Tech

この回答は、エンタープライズ環境における大規模運用を想定した、実用的かつ堅牢なPowerShellスクリプト作成のベストプラクティスに従っています。標準コマンドレット(特にCIMモジュール)と.NETクラスの活用、並列処理によるパフォーマンス最適化、およびWinRM(WS-Management)プロトコルへの準拠を最優先事項として執筆しています。 本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

[CIM/WMI] リモートPCの状態監視とイベントログ一括取得の自動化

【導入:解決する課題】

管理対象となる複数台のリモートPCに対し、1台ずつログインしてイベントログやリソース状況を確認する非効率な運用を、CIMセッションと並列処理によって自動化・高速化します。

【設計方針と処理フロー】

モダンな運用環境(PowerShell 7+推奨)に合わせ、DCOMに依存する Get-WmiObject ではなく、WS-Managementプロトコルを使用する Get-CimInstance を主軸に据えます。また、複数台へのクエリを効率化するため ForEach-Object -Parallel によるスレッド並列化を採用します。

graph TD
A["Start: リストまたは範囲指定"] --> B{"WinRM 接続確認"}
B -->|Success| C["ForEach-Object -Parallel"]
B -->|Failure| G["Offlineログ記録"]
C --> D["CIM: CPU/RAM/Disk情報取得"]
D --> E["Get-WinEvent: 過去24hのエラー取得"]
E --> F["カスタムオブジェクトへ結合"]
F --> H["CSV/JSON 出力保存"]
G --> H
H --> I[Finish]

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

function Get-RemoteSystemStatus {
    <#
    .SYNOPSIS
        リモートPCからシステムリソース情報とエラーイベントログを取得します。
    .DESCRIPTION
        CIMセッションを使用してCPU、メモリ、ディスク情報を取得し、
        Get-WinEventを使用して直近24時間以内のCritical/Errorログを抽出します。
    #>

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

        [int]$ThrottleLimit = 10,

        [string]$OutputPath = ".\SystemReport_$(Get-Date -Format 'yyyyMMdd_HHmm').csv"
    )

    $results = $ComputerNames | ForEach-Object -Parallel {
        $computer = $_
        $report = [PSCustomObject]@{
            ComputerName = $computer
            Timestamp    = Get-Date
            Status       = "Success"
            CPU_Usage    = $null
            FreeMemoryGB = $null
            DiskStatus   = $null
            ErrorLogs    = $null
            ErrorMessage = ""
        }

        try {

            # WinRM接続テスト

            if (-not (Test-Connection -ComputerName $computer -Count 1 -Quiet)) {
                throw "Network unreachable"
            }

            # CIMセッションのオプション設定(タイムアウト等)

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

            # 1. システムリソースの取得 (CIM)

            $os = Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem
            $cpu = Get-CimInstance -CimSession $session -ClassName Win32_Processor | Measure-Object -Property LoadPercentage -Average
            $disk = Get-CimInstance -CimSession $session -ClassName Win32_LogicalDisk -Filter "DriveType=3" | 
                    Select-Object DeviceID, @{Name="FreeGB"; Expression={[math]::Round($_.FreeSpace / 1GB, 2)}}

            $report.CPU_Usage = $cpu.Average
            $report.FreeMemoryGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
            $report.DiskStatus = ($disk | ForEach-Object { "$($_.DeviceID) $($_.FreeGB)GB" }) -join " | "

            # 2. イベントログの取得 (直近24時間のError/Critical)

            $query = @{
                LogName = 'System','Application'
                Level   = 1,2 # 1:Critical, 2:Error
                StartTime = (Get-Date).AddDays(-1)
            }
            $events = Get-WinEvent -FilterHashtable $query -ComputerName $computer -ErrorAction SilentlyContinue
            $report.ErrorLogs = if ($events) { $events.Count } else { 0 }

            Remove-CimSession $session
        }
        catch {
            $report.Status = "Failed"
            $report.ErrorMessage = $_.Exception.Message
        }

        return $report
    } -ThrottleLimit $ThrottleLimit

    $results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding utf8
    Write-Host "レポートが保存されました: $OutputPath" -ForegroundColor Cyan
}

# 実行例


# $targets = Get-Content .\servers.txt


# Get-RemoteSystemStatus -ComputerNames $targets

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

  • 計測方法: Measure-Command { Get-RemoteSystemStatus -ComputerNames (1..50 | % { "Target-PC-$_" }) }

  • 期待値:

    • シーケンシャル処理(PS 5.1以前): 1台あたり平均5〜10秒(合計約4〜8分)。

    • パラレル処理(PS 7.x, Throttle 10): ネットワークレイテンシにもよるが、約1分〜1.5分程度で完了。

  • ボトルネック: イベントログの取得範囲(StartTime)を広げすぎると、リモート側でのインデックス検索に時間がかかり、メモリ消費量が増大します。

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

  1. WinRM (WS-Management) の構成:

    • リモートPC側で Enable-PSRemoting が必要。

    • ワークグループ環境では TrustedHosts の設定、あるいは証明書ベースのHTTPS接続が必要です。

  2. PowerShell バージョンの差異:

    • ForEach-Object -Parallel は PowerShell 7 固有の機能です。Windows PowerShell 5.1 を使用する場合は Start-Job または PoshRSJob(外部モジュール)への差し替えが必要です。
  3. イベントログのシリアライズ上限:

    • 大量のイベントを取得しようとすると、WinRMの MaxEnvelopeSize(デフォルト512KB程度)に抵触しエラーになります。本スクリプトでは Count のみを取得し、詳細は個別調査とする設計で回避しています。
  4. UACと権限:

    • Win32_OperatingSystemGet-WinEvent へのアクセスには管理者権限が必要です。

【まとめ】

  1. CIMへの移行: DCOMポート(RPC)を多用するWMIコマンドレットではなく、ポート固定(5985/5986)が容易なCIMコマンドレットを使用する。

  2. スロットリング制御: 同時実行数(ThrottleLimit)は環境の帯域やメモリに合わせて調整し、ターゲットPCへの過負荷を避ける。

  3. エラーハンドリングの徹底: ネットワーク断や権限不足を想定し、try/catchで「実行結果をオブジェクトとして返す」設計にすることで、出力後の分析を容易にする。

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

コメント

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