[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でサーバー側フィルタリングを徹底することが重要です。
【運用上の落とし穴と対策】
PowerShell 5.1 vs 7:
ForEach-Object -Parallelは PowerShell 7 以降の機能です。Windows PowerShell 5.1 の場合は、WorkflowもしくはStart-Jobを検討するか、逐次処理に変更してください。
WinRMの有効化:
- リモート取得には
Enable-PSRemotingが必須です。ドメイン環境ではGPOによる一括有効化を推奨します。
- リモート取得には
文字コード問題:
- イベントログに日本語が含まれる場合、CIM接続のエンコーディングが不適切だと文字化けが発生します。
New-CimSessionOptionで明示的に指定してください。
- イベントログに日本語が含まれる場合、CIM接続のエンコーディングが不適切だと文字化けが発生します。
二重ホップ問題:
- 取得データをさらに別のサーバーの共有フォルダへ書き出す場合、認証の二重ホップ(Double Hop)問題が発生します。Kerberos委任の設定が必要です。
【まとめ】
CIMを優先する:
Get-WmiObjectは非推奨であり、速度・セキュリティ面でGet-CimInstanceが勝ります。フィルタリングはソース側で:
Get-WinEventは全件取得してから抽出するのではなく、必ず-FilterHashtableを使い、リモート側で絞り込みを行います。エラーハンドリングの徹底: リモート管理において「オフラインの端末」は必ず存在します。
try/catchでスクリプト全体の停止を防ぐ設計が不可欠です。

コメント