<p><!--
[STYLE_PROMPT_CONVENTION]</p>
<ul>
<li><p>Role: Senior PowerShell Engineer</p></li>
<li><p>Language: Japanese</p></li>
<li><p>Formatting: Markdown, Mermaid</p></li>
<li><p>Naming: Verb-Noun (PascalCase)</p></li>
<li><p>Principles: Standard Cmdlets, Error Handling, Parallelism, .NET Integration
-->
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">WMI/CIMを活用したリモートPC一括監視とイベントログ抽出の自動化</h1>
<h3 class="wp-block-heading">【導入:解決する課題】</h3>
<p>数百台規模のリモートPCに対する手動のヘルスチェックを廃止し、OSの状態と特定エラーログをエージェントレスで高速に自動収集します。</p>
<h3 class="wp-block-heading">【設計方針と処理フロー】</h3>
<p>通信効率とセキュリティの観点から、レガシーなDCOM(WMI)ではなく、WS-Managementプロトコルを使用するCIMコマンドレット(<code>Get-CimInstance</code>)をベースに構築します。また、大規模環境での実行速度を確保するため、PowerShell 7.xの並列処理(<code>ForEach-Object -Parallel</code>)を採用します。</p>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A[Start] --> B["コンピューターリストの読み込み"]
B --> C{"並列処理開始"}
C --> D["CIMセッションの確立試行"]
D -->|Success| E["OS情報/稼働時間の取得"]
E --> F["特定イベントログの抽出"]
F --> G["CIMセッションの破棄"]
D -->|Failure| H["エラーログ記録"]
G --> I["結果をカスタムオブジェクトに統合"]
H --> I
I --> J{"全ホスト終了?"}
J -->|Yes| K["CSV/JSONレポート出力"]
K --> L[Finish]
</pre></div>
<h3 class="wp-block-heading">【実装:コアスクリプト】</h3>
<p>以下は、リモート端末からOS情報(稼働時間含む)と、直近24時間のSystemログから「Error」を抽出する実戦的なスクリプトです。</p>
<div class="codehilite">
<pre data-enlighter-language="generic">function Get-RemoteSystemHealth {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]$ComputerNames,
[Parameter()]
[int]$MaxConcurrency = 10
)
# 並列処理によるデータ収集(PowerShell 7+ 推奨)
$Results = $ComputerNames | ForEach-Object -Parallel {
$Computer = $_
$ErrorActionPreference = "Stop"
$Report = [PSCustomObject]@{
Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
ComputerName = $Computer
OSCaption = $null
LastBootUp = $null
UptimeDays = $null
ErrorLogs = $null
Status = "Success"
ErrorMessage = $null
}
try {
# CIMオプションの設定(DCOMフォールバックが必要な場合はここで定義)
$Option = New-CimSessionOption -Protocol Wsman -ConnectTimeoutSec 10
$Session = New-CimSession -ComputerName $Computer -Option $Option
# 1. OS基本情報と稼働時間の取得
$OsInfo = Get-CimInstance -CimSession $Session -ClassName Win32_OperatingSystem
$Report.OSCaption = $OsInfo.Caption
$Report.LastBootUp = $OsInfo.LastBootUpTime
$Report.UptimeDays = [Math]::Round(((Get-Date) - $OsInfo.LastBootUpTime).TotalDays, 2)
# 2. 直近24時間のエラーイベント取得(Systemログ)
$FilterTime = (Get-Date).AddDays(-1)
$Events = Get-CimInstance -CimSession $Session -ClassName Win32_NTLogEvent `
-Filter "Logfile='System' AND Type='Error' AND TimeGenerated >= '$($FilterTime.ToString('yyyyMMddHHmmss.000000-000'))'"
$Report.ErrorLogs = ($Events | ForEach-Object { "ID:$($_.EventCode) Source:$($_.SourceName)" }) -join " | "
Remove-CimSession $Session
}
catch {
$Report.Status = "Failed"
$Report.ErrorMessage = $_.Exception.Message
}
finally {
$Report
}
} -ThrottleLimit $MaxConcurrency
return $Results
}
# --- 実行例 ---
# $TargetList = Get-Content "C:\temp\PCList.txt"
# $HealthReport = Get-RemoteSystemHealth -ComputerNames $TargetList
# $HealthReport | Export-Csv -Path "./SystemHealthReport.csv" -NoTypeInformation -Encoding utf8
</pre>
</div>
<h3 class="wp-block-heading">【検証とパフォーマンス評価】</h3>
<p>100台のリモートPCに対して実行する場合、逐次処理(Sequential)ではネットワークタイムアウト待ちを含め数十分を要しますが、上記スクリプトの並列処理(<code>-Parallel</code>)を用いることで大幅に短縮可能です。</p>
<ul class="wp-block-list">
<li><p><strong>計測例</strong>: <code>Measure-Command { Get-RemoteSystemHealth -ComputerNames $testList }</code></p></li>
<li><p><strong>期待値</strong>: スロットル制限(<code>MaxConcurrency</code>)を適切に設定することで、逐次処理比で<strong>3倍〜5倍の高速化</strong>が期待できます。ただし、送信元PCのメモリ消費量と、ネットワーク帯域の飽和に注意が必要です。</p></li>
</ul>
<h3 class="wp-block-heading">【運用上の落とし穴と対策】</h3>
<ol class="wp-block-list">
<li><p><strong>WinRMの有効化とFirewall</strong>:
リモートPC側で <code>Enable-PSRemoting</code> が実行されており、TCP 5985 (HTTP) / 5986 (HTTPS) が許可されている必要があります。</p></li>
<li><p><strong>PowerShell 5.1 vs 7</strong>:
<code>ForEach-Object -Parallel</code> は PowerShell 7 固有の機能です。Windows PowerShell 5.1 環境では <code>Start-Job</code> や <code>Runspaces</code> を使用した書き換えが必要になります。</p></li>
<li><p><strong>ダブルホップ問題</strong>:
リモートPCからさらに別のサーバーのリソースにアクセスする場合、Kerberos認証の委任設定(CredSSP等)が必要になります。今回のCIM取得のみであれば通常は不要です。</p></li>
<li><p><strong>WMIクエリのタイムアウト</strong>:
イベントログが肥大化している場合、<code>Win32_NTLogEvent</code> へのクエリがタイムアウトすることがあります。<code>-Filter</code> 句で <code>TimeGenerated</code> をインデックスに基づき絞り込むことが必須です。</p></li>
</ol>
<h3 class="wp-block-heading">【まとめ】</h3>
<ol class="wp-block-list">
<li><p><strong>CIMコマンドレットを優先</strong>: DCOMに依存する <code>Get-WmiObject</code> ではなく、Firewallフレンドリーな <code>Get-CimInstance</code> を使用すること。</p></li>
<li><p><strong>並列処理の最適化</strong>: ネットワークの遅延時間を吸収するため、<code>ForEach-Object -Parallel</code> で同時接続数を制御しながら実行すること。</p></li>
<li><p><strong>例外処理の徹底</strong>: 接続失敗やタイムアウトを <code>Try-Catch</code> で捕捉し、処理全体を止めないロギング戦略を構築すること。</p></li>
</ol>
<!--
[STYLE_PROMPT_CONVENTION]
Role: Senior PowerShell Engineer
Language: Japanese
Formatting: Markdown, Mermaid
Naming: Verb-Noun (PascalCase)
Principles: Standard Cmdlets, Error Handling, Parallelism, .NET Integration
-->
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
WMI/CIMを活用したリモートPC一括監視とイベントログ抽出の自動化
【導入:解決する課題】
数百台規模のリモートPCに対する手動のヘルスチェックを廃止し、OSの状態と特定エラーログをエージェントレスで高速に自動収集します。
【設計方針と処理フロー】
通信効率とセキュリティの観点から、レガシーなDCOM(WMI)ではなく、WS-Managementプロトコルを使用するCIMコマンドレット(Get-CimInstance)をベースに構築します。また、大規模環境での実行速度を確保するため、PowerShell 7.xの並列処理(ForEach-Object -Parallel)を採用します。
graph TD
A[Start] --> B["コンピューターリストの読み込み"]
B --> C{"並列処理開始"}
C --> D["CIMセッションの確立試行"]
D -->|Success| E["OS情報/稼働時間の取得"]
E --> F["特定イベントログの抽出"]
F --> G["CIMセッションの破棄"]
D -->|Failure| H["エラーログ記録"]
G --> I["結果をカスタムオブジェクトに統合"]
H --> I
I --> J{"全ホスト終了?"}
J -->|Yes| K["CSV/JSONレポート出力"]
K --> L[Finish]
【実装:コアスクリプト】
以下は、リモート端末からOS情報(稼働時間含む)と、直近24時間のSystemログから「Error」を抽出する実戦的なスクリプトです。
function Get-RemoteSystemHealth {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]$ComputerNames,
[Parameter()]
[int]$MaxConcurrency = 10
)
# 並列処理によるデータ収集(PowerShell 7+ 推奨)
$Results = $ComputerNames | ForEach-Object -Parallel {
$Computer = $_
$ErrorActionPreference = "Stop"
$Report = [PSCustomObject]@{
Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
ComputerName = $Computer
OSCaption = $null
LastBootUp = $null
UptimeDays = $null
ErrorLogs = $null
Status = "Success"
ErrorMessage = $null
}
try {
# CIMオプションの設定(DCOMフォールバックが必要な場合はここで定義)
$Option = New-CimSessionOption -Protocol Wsman -ConnectTimeoutSec 10
$Session = New-CimSession -ComputerName $Computer -Option $Option
# 1. OS基本情報と稼働時間の取得
$OsInfo = Get-CimInstance -CimSession $Session -ClassName Win32_OperatingSystem
$Report.OSCaption = $OsInfo.Caption
$Report.LastBootUp = $OsInfo.LastBootUpTime
$Report.UptimeDays = [Math]::Round(((Get-Date) - $OsInfo.LastBootUpTime).TotalDays, 2)
# 2. 直近24時間のエラーイベント取得(Systemログ)
$FilterTime = (Get-Date).AddDays(-1)
$Events = Get-CimInstance -CimSession $Session -ClassName Win32_NTLogEvent `
-Filter "Logfile='System' AND Type='Error' AND TimeGenerated >= '$($FilterTime.ToString('yyyyMMddHHmmss.000000-000'))'"
$Report.ErrorLogs = ($Events | ForEach-Object { "ID:$($_.EventCode) Source:$($_.SourceName)" }) -join " | "
Remove-CimSession $Session
}
catch {
$Report.Status = "Failed"
$Report.ErrorMessage = $_.Exception.Message
}
finally {
$Report
}
} -ThrottleLimit $MaxConcurrency
return $Results
}
# --- 実行例 ---
# $TargetList = Get-Content "C:\temp\PCList.txt"
# $HealthReport = Get-RemoteSystemHealth -ComputerNames $TargetList
# $HealthReport | Export-Csv -Path "./SystemHealthReport.csv" -NoTypeInformation -Encoding utf8
【検証とパフォーマンス評価】
100台のリモートPCに対して実行する場合、逐次処理(Sequential)ではネットワークタイムアウト待ちを含め数十分を要しますが、上記スクリプトの並列処理(-Parallel)を用いることで大幅に短縮可能です。
【運用上の落とし穴と対策】
WinRMの有効化とFirewall:
リモートPC側で Enable-PSRemoting が実行されており、TCP 5985 (HTTP) / 5986 (HTTPS) が許可されている必要があります。
PowerShell 5.1 vs 7:
ForEach-Object -Parallel は PowerShell 7 固有の機能です。Windows PowerShell 5.1 環境では Start-Job や Runspaces を使用した書き換えが必要になります。
ダブルホップ問題:
リモートPCからさらに別のサーバーのリソースにアクセスする場合、Kerberos認証の委任設定(CredSSP等)が必要になります。今回のCIM取得のみであれば通常は不要です。
WMIクエリのタイムアウト:
イベントログが肥大化している場合、Win32_NTLogEvent へのクエリがタイムアウトすることがあります。-Filter 句で TimeGenerated をインデックスに基づき絞り込むことが必須です。
【まとめ】
CIMコマンドレットを優先: DCOMに依存する Get-WmiObject ではなく、Firewallフレンドリーな Get-CimInstance を使用すること。
並列処理の最適化: ネットワークの遅延時間を吸収するため、ForEach-Object -Parallel で同時接続数を制御しながら実行すること。
例外処理の徹底: 接続失敗やタイムアウトを Try-Catch で捕捉し、処理全体を止めないロギング戦略を構築すること。
ライセンス:本記事のテキスト/コードは特記なき限り
CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。
コメント