【windows】PowerShellでWindowsイベントログを効率的に収集・分析する

業務効率化

今回は、Windows Server管理者やシステム運用担当者に向けて、PowerShellを使ったイベントログの効率的な収集と分析方法について解説します。

日々の運用業務やトラブルシューティングにおいて、膨大なイベントログから必要な情報を素早く抽出することは重要なスキルです。

本記事では、Get-WinEventコマンドを使った基本的な操作から実践的なフィルタリング技術、複数サーバーからの一括収集まで、実務で即座に活用できる方法を体系的にまとめました。

前提条件と対象環境

本記事で紹介するGet-WinEventコマンドは、Windows Server 2008以降のすべてのバージョンで利用可能です。Windows Server 2012以降の環境での使用を推奨します。Get-WinEventは従来のGet-EventLogコマンドの後継として開発され、より高速で詳細なログ取得が可能になっています。

基本的なGet-WinEventコマンドの使い方

PowerShellでイベントログを効率的に取得するにはGet-WinEventコマンドを使用します。このコマンドは高速かつ詳細なログ取得が可能で、すべてのイベントログに対応しています。

Get-WinEventの基本構文

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

# アプリケーションログを取得
Get-WinEvent -LogName Application -MaxEvents 100

# 特定のイベントIDを検索
Get-WinEvent -LogName Application | Where-Object {$_.Id -eq 1000}

# 複数のログソースを同時に取得
Get-WinEvent -LogName Application,System -MaxEvents 200

# リモートサーバーのログを取得
Get-WinEvent -ComputerName Server01 -LogName System -MaxEvents 50

利用可能なログの確認

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

主要パラメータ一覧

パラメータ 説明 使用例
-LogName ログの種類を指定 System, Application, Security
-MaxEvents 取得する最大イベント数 -MaxEvents 100
-FilterHashtable 効率的なフィルタリング(推奨) 後述の詳細参照
-ComputerName リモートサーバー指定 -ComputerName Server01
-Oldest 古いイベントから取得 -Oldest
-ListLog 利用可能なログを一覧表示 -ListLog *

大量のログを効率的にフィルタリングする方法

数万件のログから必要な情報を素早く抽出するには、-FilterHashtableパラメータを使用します。これはパイプラインでWhere-Objectを使うよりも大幅に高速に動作します。

FilterHashtableを使った高速フィルタリング

FilterHashtableは、ハッシュテーブル形式で複数の条件を指定できる強力な機能です。

# 過去24時間のエラーログを取得
$Filter = @{
    LogName = 'System'
    Level = 2  # Error
    StartTime = (Get-Date).AddDays(-1)
}
Get-WinEvent -FilterHashtable $Filter

# 特定のイベントIDとプロバイダーで絞り込み
$Filter = @{
    LogName = 'Application'
    ID = 1000, 1001, 1002
    ProviderName = 'MyApplication'
    StartTime = (Get-Date).AddHours(-6)
}
Get-WinEvent -FilterHashtable $Filter

# 期間を指定してエラーと警告を取得
$Filter = @{
    LogName = 'System'
    Level = 2, 3  # Error, Warning
    StartTime = (Get-Date).AddDays(-7)
    EndTime = Get-Date
}
Get-WinEvent -FilterHashtable $Filter

FilterHashtableで使用可能な主要キー

キー 説明
LogName ログ名(必須) ‘System’, ‘Application’
Level イベントレベル 1, 2, 3, 4
ID イベントID 1000, 1001, 1002
ProviderName イベントソース ‘Microsoft-Windows-Kernel-General’
StartTime 開始日時 (Get-Date).AddDays(-7)
EndTime 終了日時 Get-Date
Keywords イベントキーワード 0x8000000000000000

Level(レベル)の値

Level 意味
1 Critical(重大)
2 Error(エラー)
3 Warning(警告)
4 Information(情報)
5 Verbose(詳細)

複雑な条件でのフィルタリング

FilterHashtableとパイプラインを組み合わせることで、さらに詳細な条件指定が可能です。

# FilterHashtableで大まかに絞り、Where-Objectで詳細検索
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 1,2,3  # Critical, Error, Warning
    StartTime = (Get-Date).AddDays(-7)
} | Where-Object {$_.Message -like "*disk*"}

# 特定のイベントIDを除外
Get-WinEvent -FilterHashtable @{
    LogName = 'Application'
    Level = 2
    StartTime = (Get-Date).AddDays(-1)
} | Where-Object {$_.Id -notin @(1000, 1001)}

複数サーバーからログを一括収集する方法

運用環境では複数のサーバーからログを集約する必要があります。リモート実行とループ処理を活用します。

複数サーバーから同時収集

# サーバーリストを定義
$Servers = @("Server01", "Server02", "Server03")

# 各サーバーからエラーログを収集
$AllLogs = foreach ($Server in $Servers) {
    try {
        Get-WinEvent -ComputerName $Server -FilterHashtable @{
            LogName = 'System'
            Level = 2
            StartTime = (Get-Date).AddDays(-1)
        } -ErrorAction Stop | 
        Select-Object @{Name='ServerName';Expression={$Server}}, 
                      TimeCreated, Id, LevelDisplayName, ProviderName, Message
    }
    catch {
        Write-Warning "Failed to retrieve logs from $Server : $_"
    }
}

# 結果を表示
$AllLogs | Format-Table -AutoSize

CSVファイルからサーバーリストを読み込む方法

# servers.csvから読み込み(列名: ServerName)
$Servers = Import-Csv -Path "C:\Scripts\servers.csv"

$Results = foreach ($Server in $Servers.ServerName) {
    Get-WinEvent -ComputerName $Server -FilterHashtable @{
        LogName = 'System'
        Level = 2
        StartTime = (Get-Date).AddDays(-1)
    } -ErrorAction SilentlyContinue
}

# サーバーごとにエラー件数を集計
$Results | Group-Object MachineName | 
Select-Object Name, Count | 
Sort-Object Count -Descending

並列処理で高速化

PowerShell 7以降では、ForEach-Object -Parallelを使用して並列処理が可能です。

# PowerShell 7以降
$Servers = @("Server01", "Server02", "Server03")

$AllLogs = $Servers | ForEach-Object -Parallel {
    Get-WinEvent -ComputerName $_ -FilterHashtable @{
        LogName = 'System'
        Level = 2
        StartTime = (Get-Date).AddDays(-1)
    } -ErrorAction SilentlyContinue
} -ThrottleLimit 5

トラブルシューティングでよく使うログ分析パターン

実務でよく遭遇するトラブルシューティングシナリオと対応するPowerShellコマンドを紹介します。

パターン1: サーバー再起動の履歴を確認

# システム起動・シャットダウンイベントを確認
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ID = 1074, 6005, 6006, 6008, 6009  # シャットダウン、起動関連
    StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, Message | 
Sort-Object TimeCreated -Descending | 
Format-Table -Wrap

主要なイベントID

  • 1074: ユーザーまたはアプリケーションによるシャットダウン/再起動
  • 6005: イベントログサービスの開始(起動)
  • 6006: イベントログサービスの停止(シャットダウン)
  • 6008: 予期しないシャットダウン
  • 6009: システム起動時のOSバージョン情報

パターン2: 特定のサービス障害を調査

# サービス停止・開始のイベントを検索
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ID = 7034, 7035, 7036, 7040  # サービス関連イベント
    StartTime = (Get-Date).AddDays(-7)
} | Where-Object {$_.Message -like "*SQL Server*"} | 
Select-Object TimeCreated, Id, Message

# サービスエラーを集計
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ID = 7034  # サービスの予期しない終了
    StartTime = (Get-Date).AddDays(-30)
} | Group-Object {$_.Message -replace '^(.+?)\s+service.*','$1'} | 
Select-Object Count, Name | 
Sort-Object Count -Descending

パターン3: ディスク関連エラーの検出

# ディスクエラーを検索
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ProviderName = 'Disk', 'Ntfs'
    Level = 1,2,3
    StartTime = (Get-Date).AddDays(-7)
} | Group-Object Id | 
Select-Object Count, Name, @{Name='Sample';Expression={$_.Group[0].Message}} | 
Sort-Object Count -Descending

# 特定のディスクエラー(イベントID 7, 11, 15など)を抽出
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    ProviderName = 'Disk'
    ID = 7, 11, 15
    StartTime = (Get-Date).AddDays(-7)
}

パターン4: ログオン失敗の監査

# セキュリティログからログオン失敗を抽出
Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    ID = 4625  # ログオン失敗
    StartTime = (Get-Date).AddHours(-24)
} | Select-Object TimeCreated, 
    @{Name='Account';Expression={$_.Properties[5].Value}}, 
    @{Name='SourceIP';Expression={$_.Properties[19].Value}},
    @{Name='FailureReason';Expression={$_.Properties[8].Value}}

# ログオン失敗を集計
Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    ID = 4625
    StartTime = (Get-Date).AddDays(-7)
} | Group-Object {$_.Properties[5].Value} | 
Select-Object Count, Name | 
Sort-Object Count -Descending

パターン5: アプリケーションエラーの分析

# アプリケーションクラッシュを検出
Get-WinEvent -FilterHashtable @{
    LogName = 'Application'
    ProviderName = 'Application Error', 'Windows Error Reporting'
    Level = 2
    StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, ProviderName, Message | 
Format-List

# .NETランタイムエラーを検索
Get-WinEvent -FilterHashtable @{
    LogName = 'Application'
    ProviderName = '.NET Runtime'
    Level = 2
    StartTime = (Get-Date).AddDays(-7)
}

CSV/HTMLへのエクスポートと可視化

収集したログデータを共有可能な形式にエクスポートする方法です。

CSVファイルへのエクスポート

# システムエラーをCSVに出力
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 2
    StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message | 
Export-Csv -Path "C:\Logs\SystemErrors.csv" -NoTypeInformation -Encoding UTF8

# 複数サーバーのログを1つのCSVにまとめる
$Servers = @("Server01", "Server02", "Server03")
$AllErrors = foreach ($Server in $Servers) {
    Get-WinEvent -ComputerName $Server -FilterHashtable @{
        LogName = 'System'
        Level = 2
        StartTime = (Get-Date).AddDays(-1)
    } -ErrorAction SilentlyContinue | 
    Select-Object @{Name='Server';Expression={$Server}}, TimeCreated, Id, Message
}
$AllErrors | Export-Csv -Path "C:\Reports\AllServers_Errors.csv" -NoTypeInformation -Encoding UTF8

HTMLレポートの作成

# HTMLレポートを生成
$Logs = Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 1,2,3
    StartTime = (Get-Date).AddDays(-1)
} | Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message -First 100

$HTML = $Logs | ConvertTo-Html -Title "System Error Report" `
    -PreContent "<h1>過去24時間のシステムログレポート</h1><p>生成日時: $(Get-Date -Format 'yyyy/MM/dd HH:mm:ss')</p>" `
    -PostContent "<p>Total Events: $($Logs.Count)</p>"

$HTML | Out-File -FilePath "C:\Reports\SystemLog.html" -Encoding UTF8

グループ化して集計

# エラーをイベントID別に集計
Get-WinEvent -FilterHashtable @{
    LogName = 'Application'
    Level = 2
    StartTime = (Get-Date).AddDays(-30)
} | Group-Object Id | 
Select-Object Count, Name, @{Name='SampleMessage';Expression={$_.Group[0].Message}} | 
Sort-Object Count -Descending | 
Export-Csv -Path "C:\Reports\ErrorSummary.csv" -NoTypeInformation -Encoding UTF8

# 時間帯別に集計
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 2
    StartTime = (Get-Date).AddDays(-7)
} | Group-Object {$_.TimeCreated.ToString("yyyy-MM-dd HH")} | 
Select-Object @{Name='Hour';Expression={$_.Name}}, Count | 
Sort-Object Hour | 
Export-Csv -Path "C:\Reports\ErrorsByHour.csv" -NoTypeInformation -Encoding UTF8

よくあるエラーと対処法

PowerShellでイベントログを操作する際に遭遇しやすいエラーと解決方法をまとめました。

エラー1: アクセス拒否

エラーメッセージ:

Get-WinEvent : アクセスが拒否されました

原因:
セキュリティログなど、管理者権限が必要なログにアクセスしようとした。

対処法:
PowerShellを「管理者として実行」で起動してください。リモートサーバーの場合は、適切な権限を持つアカウントでログインする必要があります。

# 権限確認
$CurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object Security.Principal.WindowsPrincipal($CurrentUser)
$IsAdmin = $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $IsAdmin) {
    Write-Warning "管理者権限で実行してください"
}

エラー2: ログ名が見つからない

エラーメッセージ:

Get-WinEvent : 指定されたログ名が存在しません

原因:
存在しないログ名を指定した、またはログが無効化されている。

対処法:
利用可能なログ名を確認します。

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

# 特定のキーワードでログを検索
Get-WinEvent -ListLog * | Where-Object {$_.LogName -like "*application*"}

エラー3: リモートサーバーへの接続失敗

エラーメッセージ:

Get-WinEvent : RPC サーバーを利用できません

原因:
ファイアウォールでRPCがブロックされている、またはWinRMサービスが停止している。

対処法:

  1. WinRMサービスが起動しているか確認
  2. ファイアウォールでRPC(TCP 135)とダイナミックポートが許可されているか確認
  3. 以下のコマンドでWinRMを有効化
# リモートサーバー上で実行(管理者権限必要)
Enable-PSRemoting -Force

# サービス状態を確認
Get-Service WinRM

# ファイアウォールルールを確認
Get-NetFirewallRule -DisplayName "*Remote Event Log*" | Select-Object DisplayName, Enabled

# 接続テスト
Test-WSMan -ComputerName Server01

エラー4: メモリ不足エラー

エラーメッセージ:

Get-WinEvent : メモリが不足しています

原因:
大量のログを一度に取得しようとした。

対処法:
MaxEventsパラメータで件数を制限するか、FilterHashtableで期間を絞り込みます。

# 件数を制限して取得
Get-WinEvent -LogName System -MaxEvents 1000

# 期間を絞り込む
Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    StartTime = (Get-Date).AddHours(-6)
}

# ページング処理で少しずつ取得
$MaxEvents = 1000
$Skip = 0
do {
    $Events = Get-WinEvent -LogName System -MaxEvents $MaxEvents -Oldest |
              Select-Object -Skip $Skip -First 1000
    $Events | Export-Csv -Path "C:\Logs\System_$Skip.csv" -Append
    $Skip += 1000
} while ($Events.Count -gt 0)

エラー5: FilterHashtableの構文エラー

エラーメッセージ:

Get-WinEvent : パラメーター 'FilterHashtable' にバインドできません

原因:
FilterHashtableの構文が正しくない、またはサポートされていないキーを使用している。

対処法:
ハッシュテーブルの構文を確認し、正しいキーを使用します。

# 正しい構文
$Filter = @{
    LogName = 'System'
    Level = 2
    StartTime = (Get-Date).AddDays(-1)
}
Get-WinEvent -FilterHashtable $Filter

# 間違った構文(カンマ区切りはNG)
# $Filter = @{LogName='System', Level=2}  # これはエラー

# 正しいキー名を確認
# 使用可能: LogName, ProviderName, Path, Keywords, ID, Level, StartTime, EndTime, UserID, Data

まとめ

PowerShellのGet-WinEventコマンドを使ったイベントログの収集・分析は、Windows Server運用において欠かせない技術です。本記事で紹介した以下のポイントを押さえることで、日々のトラブルシューティングが格段に効率化されます。

  • Get-WinEventとFilterHashtableを使った高速なログ取得
  • 複数サーバーからの一括収集で運用効率の向上
  • 実践的なフィルタリングパターンで必要な情報を素早く抽出
  • CSV/HTMLエクスポートによる可視化と共有
  • よくあるエラーへの対処法の理解

Get-WinEventはWindows Server 2008以降で利用可能ですが、FilterHashtableの全機能を活用するには、Windows Server 2012以降の環境を推奨します。これらの技術を組み合わせることで、障害発生時の迅速な原因究明や、定期的なシステム監査を効率的に実施できます。ぜひ実務環境で活用してください。

 

【注意】

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

 

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

業務効率化windowsITナレッジ
この記事の作者
StarTeller

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

StarTellerをフォローする
シェアする
StarTellerをフォローする

コメント

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