【Windows】イベントログをget-wineventで効率的に解析する方法

windows

今回は、PowerShellのGet-WinEventコマンドレットを使ってWindowsイベントログを効率的に解析する方法を、実際の運用シナリオとともに解説します。

Windows Serverの障害調査や監査対応において、イベントログの読み取りは避けて通れない作業です。GUIのイベントビューアーでも確認できますが、大量のログから目的のイベントを絞り込むには限界があります。Get-WinEventを使いこなすことで、数万件のログから必要な情報を瞬時に抽出できるようになります。


Get-WinEventとGet-EventLogの違い

Windowsのイベントログ取得コマンドにはGet-EventLogGet-WinEventの2種類があります。現場では今でもGet-EventLogを使っているケースを見かけますが、Windows Vista以降のログ形式(Evtx)にはGet-WinEventを使うべき理由があります。

比較項目 Get-EventLog Get-WinEvent
対応ログ形式 従来のクラシックログのみ クラシック + EVTXログ(全対応)
フィルタ速度 低速(全件取得後にフィルタ) 高速(カーネルレベルでフィルタ)
リモート対応 限定的 Invoke-Command併用で完全対応
廃止予定 あり(PowerShell 6以降非対応) 今後もサポート継続

Get-EventLogはPowerShell Core(6以降)では使用できません。将来性を考えてもGet-WinEventへの移行を推奨します。


基本的な使い方とフィルタリング

# システムログの最新100件を取得
Get-WinEvent -LogName System -MaxEvents 100

# セキュリティログからエラーと警告を取得
Get-WinEvent -LogName Security -MaxEvents 50 |
    Where-Object { $_.LevelDisplayName -in @("エラー", "警告") }

# 利用可能なログ名の一覧を確認
Get-WinEvent -ListLog * | Where-Object { $_.RecordCount -gt 0 } |
    Select-Object LogName, RecordCount | Sort-Object RecordCount -Descending

Where-Objectでのフィルタは全件取得後の絞り込みになるため、ログ量が多い場合は次に紹介するFilterHashtableを使いましょう。


FilterHashtableで高速絞り込み

-FilterHashtableパラメータを使うと、ログの読み込み時点でフィルタリングが行われるため、大幅に処理が高速化されます。

# 過去24時間のシステムエラーを取得
$filter = @{
    LogName   = 'System'
    Level     = 2          # 2=エラー, 3=警告, 4=情報
    StartTime = (Get-Date).AddHours(-24)
}
Get-WinEvent -FilterHashtable $filter

# 特定のイベントIDで絞り込む(ログオン失敗: 4625)
$secFilter = @{
    LogName = 'Security'
    Id      = 4625
    StartTime = (Get-Date).AddDays(-7)
}
Get-WinEvent -FilterHashtable $secFilter |
    Select-Object TimeCreated, Message |
    Format-List

Levelの対応表:

レベル
1 重大
2 エラー
3 警告
4 情報
5 詳細

XMLクエリによる高度なフィルタリング

さらに細かい条件で絞り込むには、-FilterXmlまたは-FilterXPathを使います。イベントビューアーのGUIでフィルタを作成し、XMLを確認してコピーする方法が実用的です。

# XPathクエリで特定ユーザーのログオン失敗を抽出
$xpath = @"
*[System[EventID=4625] and EventData[Data[@Name='TargetUserName']='administrator']]
"@

Get-WinEvent -LogName Security -FilterXPath $xpath |
    Select-Object TimeCreated, @{N='Message';E={$_.Message}} |
    Format-List

# 複数のイベントIDをOR条件で指定
$multiIdXPath = "*[System[(EventID=4624 or EventID=4625 or EventID=4634)]]"
Get-WinEvent -LogName Security -FilterXPath $multiIdXPath -MaxEvents 200

よく使う運用シナリオ別スクリプト

シナリオ1:ログオン失敗の連続発生を検出

# 過去1時間のログオン失敗を集計(ブルートフォース検知)
$startTime = (Get-Date).AddHours(-1)
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=$startTime} |
    ForEach-Object {
        $xml = [xml]$_.ToXml()
        [PSCustomObject]@{
            Time       = $_.TimeCreated
            UserName   = $xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TargetUserName'} | Select-Object -ExpandProperty '#text'
            SourceIP   = $xml.Event.EventData.Data | Where-Object {$_.Name -eq 'IpAddress'} | Select-Object -ExpandProperty '#text'
        }
    } |
    Group-Object SourceIP |
    Sort-Object Count -Descending |
    Select-Object Count, Name

シナリオ2:サービス停止イベントのCSV出力

# サービス停止(7034)と予期しない再起動(6008)を収集
$events = Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Id        = @(7034, 6008)
    StartTime = (Get-Date).AddDays(-30)
}

$events | Select-Object TimeCreated, Id, LevelDisplayName, Message |
    Export-Csv -Path "C:\work\ServiceEvents.csv" -Encoding UTF8 -NoTypeInformation

シナリオ3:リモートサーバーのログを一括収集

# 複数サーバーのシステムエラーを一括収集
$servers = @("SRV01", "SRV02", "SRV03")
$results = @()

foreach ($server in $servers) {
    try {
        $events = Get-WinEvent -ComputerName $server -FilterHashtable @{
            LogName   = 'System'
            Level     = 2
            StartTime = (Get-Date).AddDays(-1)
        } -ErrorAction Stop
        $results += $events | Select-Object @{N='Server';E={$server}}, TimeCreated, Id, Message
    }
    catch {
        Write-Warning "[$server] 取得失敗: $($_.Exception.Message)"
    }
}

$results | Export-Csv -Path "C:\work\AllServerErrors.csv" -Encoding UTF8 -NoTypeInformation

実務でハマりやすいポイント

① セキュリティログのアクセス権限
セキュリティログは管理者権限がないと読み取れません。Get-WinEvent -LogName Securityを実行して「アクセスが拒否されました」が出る場合は、PowerShellを「管理者として実行」してください。

② リモートアクセス時のWinRM設定
-ComputerNameオプションでリモートサーバーに接続するには、対象サーバーでWinRMが有効になっている必要があります。

# 対象サーバーでWinRMを有効化(管理者権限が必要)
Enable-PSRemoting -Force

③ 大量ログで処理が重い場合
-MaxEventsで取得件数を制限しつつ、FilterHashtableのStartTime/EndTimeで期間を絞ることが重要です。Where-Objectだけに頼ると全件取得になり、何万件ものログで数分待たされることがあります。


まとめ

Get-WinEventは、Windowsイベントログ解析の中核となる強力なコマンドレットです。本記事のポイントをまとめます。

  • Get-EventLogからの移行:EVTXログ対応・高速フィルタ・将来性の観点でGet-WinEventを使う
  • FilterHashtableの活用:ログ読み込み段階でフィルタして処理を高速化する
  • シナリオ別スクリプトの整備:ログオン失敗監視・サービス異常検知などを定型化しておく

イベントログの解析を自動化することで、障害対応のスピードが大幅に向上します。まずはFilterHashtableを使ったログ取得から始めて、XPathクエリへと段階的にスキルアップしていきましょう。

【注意】

このブログは技術に関する知識や経験を共有することを目的としており、情報の正確性に努めていますが、その内容の正確性や完全性を保証するものではありません。ブログの情報を利用する場合は、自己の責任において行動してください。ブログの内容に基づいて行った行動や決定によって生じた損害や被害について、筆者は一切の責任を負いません。

 

記事の内容の一部は、生成AIで作成しています。

windowsITナレッジ
この記事の作者
StarTeller

30歳で異業種からITエンジニアへ転身し、10年以上にわたりインフラエンジニアとして様々な現場でシステム構築・運用に携わってきました。
得意分野はLinux/Windowsのサーバー構築・運用で、ネットワークやAWSなども実務で活用しています。このブログでは、これまでの業務で培った経験を基に、日々の業務で遭遇した問題の解決方法や、システム構築の具体的な手順を解説。現場のエンジニアが実際に「困ったとき」に参照できる情報を意識して投稿していこうと思っています。
※サーバ運用費がかかっているので、広告を掲載させて頂いてます。

StarTellerをフォローする
シェアする
StarTellerをフォローする
タイトルとURLをコピーしました