Windows event logのPowerShell取得で最初に求められるのはcommand暗記ではなく、何を正しい結果とするかの定義です。結論は「既存script互換でGet-EventLogを理解しつつ、新規調査はGet-WinEventのFilterHashtableでlog、ID、level、時間をprovider側に絞ります。大量logを全件pipeしてWhere-Objectで絞る方法は避けます。」。Get-EventLogはWindowsのclassic event log向けで、現行のchannelや効率的filterにはGet-WinEventを優先することを確認し、表示、加工、変更を混同しない順序で進めます。
classic logとmodern channelを使い分ける
Get-EventLogは従来形式のログ向けであり、詳細なXMLや新しいチャネルの調査にはGet-WinEventを優先します。開始・終了時刻、ログ名、Provider、ID、Levelを先に固定し、RecordIdとTimeCreatedを残します。同じ条件をサーバー側フィルターで再実行し、取得件数と並び順が再現することを確認します。
- Get-WinEvent -ListLogでlog名、record count、enabledを確認する
- timezoneと調査期間の境界を決める
- event IDだけでなくProviderNameとLogNameを組にする
- messageにuser dataが含まれるため保存先ACLを確認する
期間・ID・providerをserver側で絞る
classic logを少量取得
Get-EventLog -LogName System -Newest 20 |
Select-Object TimeGenerated,EntryType,Source,InstanceId,Message
旧scriptの確認用です。-Newestで上限を設け、InstanceIdはevent ID表示との扱いを実dataで確認します。
現行手順で期間とIDをfilter
$start = (Get-Date).AddHours(-2)
Get-WinEvent -FilterHashtable @{ LogName='System'; Id=7036; StartTime=$start } |
Select-Object TimeCreated,Id,ProviderName,LevelDisplayName,Message
FilterHashtableは取得元で絞るため効率的です。StartTimeはlocal DateTimeとして扱われるため記録のtimezoneを明記します。
Application errorを確認
Get-WinEvent -FilterHashtable @{ LogName='Application'; Level=2; StartTime=(Get-Date).AddDays(-1) } -MaxEvents 100
Level 2はerrorです。error全件が同じ障害ではないためprovider、ID、process、発生間隔を分類します。
利用可能logを探す
Get-WinEvent -ListLog '*PowerShell*' |
Select-Object LogName,IsEnabled,RecordCount,LastWriteTime
読むだけの一覧です。logを有効化・clearする操作は別の変更であり、調査中に実行しません。
evidenceをexport
Get-WinEvent -FilterHashtable @{LogName='System';StartTime=(Get-Date).AddHours(-1)} -MaxEvents 200 |
Export-Clixml -LiteralPath '.\system-events.xml'
CLIXMLはpropertyを保持しやすい形式です。機密情報を含み得るため新規file、限定ACL、保持期限を設定します。
LevelとEntryTypeの違いを理解する
同じevent IDでもproviderが違えば意味が異なります。LevelDisplayNameの言語表示よりLevel数値とproviderを記録します。TimeCreatedは表示timezoneの影響を受けるのでUTCへ正規化する場合は元値も保持します。Get-EventLogの-After/-BeforeとGet-WinEvent FilterHashtableの境界をsampleで確認し、欠損を避けます。
並び順とMaxEventsの上限を明示する
- Get-EventLogだけで全channelを扱えると思う
- 全件取得後Where-Objectで絞る
- IDだけでevent意味を断定する
- local timeとUTCを混ぜる
- 調査中にlogをclearする
event objectをCLIXMLへ保存する
event取得は読み取りですが、Security logやapplication messageにはaccount、path、IP等が含まれます。必要な期間・eventだけを出力し、ticket添付前にaccess権とmask方針を確認します。Clear-EventLogやlog無効化は証跡消失になるため行いません。export失敗時は入力logを変更せず、生成途中fileを破棄して別の安全な保存先へ再試行します。
権限不足と該当eventなしを分離する
Event Viewerの同じLogName、Provider、ID、時刻で数件を照合します。MaxEventsを外す前に件数を見積もり、期間の直前直後をsample確認します。exportをImport-Clixmlで読み戻し、Id、RecordId、TimeCreatedが保持されたことを確認します。
Count・時刻範囲・RecordIdで取得を確定する
Get-EventLogはclassic log向けの互換手段で、現行調査はGet-WinEventのFilterHashtableで期間・log・IDをsource側filterします。0件、log不存在、権限不足を分け、RecordIdとTimeCreatedを再取得のcursorにします。
直近System eventを上限付きで取得する
$start=(Get-Date).AddHours(-2)
$e=@(Get-WinEvent -FilterHashtable @{LogName='System';StartTime=$start} -MaxEvents 200 -ErrorAction Stop)
[pscustomobject]@{Count=$e.Count;Newest=$e[0].TimeCreated;Oldest=$e[-1].TimeCreated;MaxRecordId=($e.RecordId|Measure-Object -Maximum).Maximum}
eventあり・0件・channel errorを分類する
- eventを取得:指定期間のeventがRecordId降順で取得され、provider/ID/levelがfilter条件と一致する
- 期間内0件:正常な0件は空arrayとして期間とhostを記録し、障害なしとは断定しない
- channel・権限error:log名不正、channel無効、access denied、query errorは例外として検索0件から分離する
Message文字列はOS languageやprovider版で変わるため自動判定keyにしません。Get-EventLogのEntryTypeとGet-WinEventのLevelを混同せず、全logをclient-side Where-Objectで濾過しないよう件数上限を置きます。
存在しないlog名と空期間を試す
try { Get-WinEvent -LogName 'ittrip-log-that-does-not-exist' -MaxEvents 1 -ErrorAction Stop } catch { [pscustomobject]@{State='LogError';Category=$_.CategoryInfo.Category} }
0件、存在しないlog、権限不足、期間境界、同一timestamp複数eventをtestします。host、timezone、RecordId、ProviderName、Id、Level、取得queryを保存します。
Get-EventLogとGet-WinEventは対象channelとfilter能力が異なります。現在の調査ではGet-WinEventのFilterHashtableを基準にし、classic log互換が必要な場合だけGet-EventLogを選びます。

コメント