Excel VBA:Windowsのイベントログの一覧をExcelのワークシートに出力するVBAのサンプルプログラム

ExcelのVBAを使って指定したコンピュータのWindowsイベントログをワークシートのセルに出力させるサンプルプログラムを覚書。

WMIオブジェクトとExecQueryを使って指定したコンピュータのWindowsイベントログを条件を指定してExcelのワークシートに出力させます。

指定する条件は日付やログの種類(System、Application、セキュリティなど)、レベル(情報、警告、エラー)を指定したサンプルプログラムです。

Windowsイベントログにアクセスできる権限があれば、プログラムを実行しているコンピュータとは別のコンピュータ、例えばWindowsサーバーのイベントログを出力させることもできます。

記事の最後には複数のリモートコンピューター(サーバー)のイベントログをシートごとに分けて出力するサンプルプログラムを載せていますので参考にしてください。

スポンサーリンク

WindowsのイベントログをExcelのワークシートに出力させるプログラムの概要

WindowsのイベントログをExcelのワークシートに出力させるためには、「WMIサービスオブジェクト」と「ExecQuery 」メソッドを使用します。

また、条件に日付を使用する場合は、UTC日時値に変換するために「SWbemDateTime」オブジェクトを使います。

正しい表現かは別として、わかりやすいイメージで説明するとWindowsイベントログが保管されているデータベースにクエリーを投げてその結果をExcelのワークシートに書き出すという感じです。

プログラムのポイント

今回のプログラムの主なポイントを以下に記載します。

検索条件として日付を使う場合は、UTC日時値に変換が必要

VBAからWindowsのイベントログを取得する際に指定する条件に日付を指定する場合は、UTC日時値に変換する必要があります。

UTC日時値の変換の詳細については、以下の記事を参照してください。

VBA共通:VBAで日付時刻(日本の標準時:JST)をUTC日時値に変換するサンプルプログラム
これから書く予定の記事でVBAのプログラム中で通常の日付時刻(日本の標準時:JST)の値をUTC(Coordinated Universal Time:協定世界時)日時値に変換する処理が必要だったので、その方法について覚書きしておきます。逆...

取得したいイベントログの抽出条件の指定方法

VBAからWindowsのイベントログを取得する際は、SQLのSELECT文を使用します。

そのSELECT文のWHERE句で条件指定を行います。

AccessなどのRDBアプリケーションに慣れている方ならば特に問題はないと思います。

抽出条件として指定できる項目について

VBAからWindowsのイベントログを取得する際の抽出条件に指定できる項目とその内容を以下に記載します。

記載している項目以外にも指定できる項目がいくつかありますが、個人的に必要ないだろうと思ったものは省略しています。

項目名 内容
ComputerName イベントを生成したコンピューター名
EventCode イベントログを見た時の""イベントID""に該当する値
EventType Typeプロパティはイベントの種類(種類については後述)
Logfile ログファイル名(指定できる値については後述)
Message イベントのメッセージ
RecordNumber 各イベントごとに悪振られる一意の番号
SourceName イベントを発生させたアプリケーション(サービス)
TimeGenerated ソースがイベントを生成した時間
TimeWritten イベントがログファイルに書き込まれた時間
Type イベントの種類(種類については後述)
User イベントが発生したときにユーザーでログオンしたユーザー名 ユーザー名が不明な場合はNull値
EventTypeについて

EventTypeを検索条件に指定する場合は、各レベルを表す数値を指定します。 指定できる値と対応するレベルを以下に記載します。

EventType値 レベル
0 情報
1 エラー
2 警告
3 情報
4 成功の監査
5 失敗の監査
Logfileについて

Logfileに指定できる値は各ログ名を表す文字列です。

以下にLogfileに指定できる文字列値と対応するログファイル名を記載します。

Logfile 対応するログ
System システムログ
Application アプリケーションログ
Security セキュリティログ
Type値について

Type値は、イベントの種類を表す文字列です。

Type
情報
警告
エラー
成功の監査
失敗の監査

取得したイベントログの日時を示す値はUTC日時値となっているので、日本の標準時(JST)に変換が必要

取得したイベントログの時刻はUTC日時値を表す文字列になっています。

従って日本の標準時(JST)に変換した上で出力させないとWindowsのイベントログビューワーで見た際の日時と違ってしまいます。

サンプルプログラム中にUTC日時値を日本の標準時(JST)に変換する処理部分が出てきますが、この記事では詳しくは説明しません。

UTC日時値を日本の標準時(JST)に変換する処理の詳細については、以下の記事を参照してください。

VBAでUTC日時値を表す文字列を日本の標準時(JST)に変換した上で日付型に変換するサンプルプログラム(ユーザー定義関数)
UTC(協定世界時)日時値を表す文字列、例えば「20150731055917.000000-000」を日本の標準時(JST)に直した上で日付型のデータに変換するユーザー定義関数を覚書。例えば「20150731055917.000000-00...

WindowsのイベントログをExcelのワークシートに出力するサンプルプログラム

以下にWindowsのイベントログをExcelのワークシートに出力するサンプルプログラムを記載します。

イベントログの抽出条件としては、日付のみを指定して「今日発生したイベント」という条件で抽出しています。

対象となるイベントログは全てです。

Sub GetEventLog()
Dim strTime As String, strYear As String, strMonth As String
Dim strDay As String, strHour As String, strMinute As String
Dim strSec As String, strComputer As String
Dim utcStartDate As Object, StartDate As Date
Dim objWMIService As Object, colEvents As Object
'ワークシートに出力している間の画面更新を停止
Application.ScreenUpdating = False
'アクティブワークシートのA1セルに画面を移動
Application.Goto Reference:=ActiveWindow.ActiveSheet.Range("A1"), Scroll:=True
'UTC日時値に変換するためのオブジェクトを作成
Set utcStartDate = CreateObject("WbemScripting.SWbemDateTime")
'今日の日付を変数に代入
StartDate = Date
'UTC日時に変換
utcStartDate.SetVarDate StartDate, True
'抽出したいコンピュータ名を変数に代入
'※権限があればサーバーなどのリモートコンピューターの指定も可
strComputer = "Computer01"
'WMIオブジェクトの参照
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!¥¥" & strComputer & "¥root¥cimv2")
'イベントログの抽出条件(日付指定のみ)を指定したSQLを実行
Set colEvents = objWMIService.ExecQuery _
    ("Select * from Win32_NTLogEvent Where TimeWritten >= '" & utcStartDate & "'")
    '項目名(ヘッダー)をワークシートに出力
    With ActiveCell
        .Offset(0, 0) = "レベル"
        .Offset(0, 1) = "イベントID"
        .Offset(0, 2) = "ソース"
        .Offset(0, 3) = "日付と時刻"
        .Offset(0, 4) = "メッセージ"
        .Offset(0, 5) = "ログ種別"
        .Offset(0, 6) = "コンピューター名"
        .Offset(0, 7) = "カテゴリ"
        .Offset(0, 8) = "レコード番号"
        .Offset(0, 9) = "ユーザー名"
        .Offset(1, 0).Select
    End With
    
    '抽出したイベントログをワークシートに出力
    For Each objEvent In colEvents
        With ActiveCell
            .Offset(0, 0).Value = objEvent.Type
            .Offset(0, 1).Value = objEvent.EventCode
            .Offset(0, 2).Value = objEvent.SourceName
                
                'UTC日時値を日本の標準時(JST)に変換
                strTime = Left(objEvent.TimeWritten, 14)
                strYear = Left(strTime, 4)
                strMonth = Mid(strTime, 5, 2)
                strDay = Mid(strTime, 7, 2)
                strHour = Mid(strTime, 9, 2)
                strMinute = Mid(strTime, 11, 2)
                strSec = Mid(strTime, 13, 2)
                
                dateUTC = CDate(strYear & "/" & strMonth & "/" & strDay & " " _
                          & strHour & ":" & strMinute & ":" & strSec) + TimeValue("9:00:00")
                          
            .Offset(0, 3).Value = dateUTC
            .Offset(0, 4).Value = objEvent.Message
            .Offset(0, 5).Value = objEvent.LogFile
            .Offset(0, 6).Value = objEvent.ComputerName
            .Offset(0, 7).Value = objEvent.Category
            .Offset(0, 8).Value = objEvent.RecordNumber
            .Offset(0, 9).Value = objEvent.User
            .Offset(1, 0).Select
        End With
        
    Next
    '出力したワークシートのA1セルに画面を移動
    Application.Goto Reference:=ActiveWindow.ActiveSheet.Range("A1"), Scroll:=True
    
    '画面更新を元に戻す(礼儀)
    Application.ScreenUpdating = True
End Sub

イベントログの抽出条件を変更してみる

私が普段イベントログを確認する際は、システムログとアプリケーションログです。 またイベントの種類も"警告"か"エラー"だけです。

場合によっては"情報"レベルのイベントなんかも確認しますが、とりあえずは普段見る分だけを抽出するように条件を指定してみます。

サンプルプログラムの32~33行名のコードを変更します。

変更前

抽出条件に指定されているのは日付のみ。

Set colEvents = objWMIService.ExecQuery _  
    ("Select * from Win32_NTLogEvent Where TimeWritten >= '" & utcStartDate & "'")

変更後

抽出するログはアプリケーションとシステムのみ、イベントの種類は"警告"と"エラー"のみという条件に書き換えた例です。

Set colEvents = objWMIService.ExecQuery _
    ("Select * from Win32_NTLogEvent Where TimeWritten >= '" & utcStartDate _
    & "' and (Logfile = 'System' or Logfile = 'Application') and (EventType = 1 or EventType = 2)")

複数のリモートコンピューター(サーバー)のイベントログをシートごとに分けて出力するVBAのサンプルプログラム

以下に1つのExcelファイルに複数のリモートコンピューターからイベントログを抽出して出力するサンプルプログラムを記載します。

設定シートに抽出したいイベントログの日付と採取したいコンピューター名を記載してプログラムを実行すれば、シートごとに各リモートコンピューターごとのイベントログが出力されます。

シート名にはリモートコンピューター名 + 日時(YYYYMMDDhhmmss)が付くようになっています。

設定シートのサンプル

設定シートに記載の画面ショットを参考に載せておきます。

設定シートに日付とイベントログを採取したいコンピューターを記述

サンプルプログラム

実行するプログラムを以下に記載します。

エラーが発生した時の処理は入れていませんし、私の環境での動作確認しかしていません。

使用については自己責任でお願いします。

また、うまく動作しなかったとしてもデバッグ等は個人で行ってください。

Sub GetEventLog()
Dim strTime As String, strYear As String, strMonth As String
Dim strDay As String, strHour As String, strMinute As String
Dim strSec As String, strComputer
Dim utcStartDate As Object, StartDate As Date
Dim objWMIService As Object, colEvents As Object
Dim setWks As Worksheet, i
'ワークシートに出力している間の画面更新を停止
Application.ScreenUpdating = False
Set setWks = ThisWorkbook.Worksheets("設定シート")
'UTC日時値に変換するためのオブジェクトを作成
Set utcStartDate = CreateObject("WbemScripting.SWbemDateTime")
    If setWks.Range("b2").Value = "" Then
        StartDate = Date
    Else
        StartDate = setWks.Range("b2").Value
    End If
'UTC日時に変換
utcStartDate.SetVarDate StartDate, True
'抽出対象のコンピューターを配列に代入
setWks.Range("a4").Select
    i = 0
    ReDim strComputer(i)
    Do Until ActiveCell.Value = ""
     strComputer(i) = ActiveCell.Value
        If ActiveCell.Offset(1, 0).Value = "" Then
            Exit Do
        Else
            i = i + 1
            ReDim Preserve strComputer(i)
            ActiveCell.Offset(1, 0).Select
        End If
    Loop
'コンピューターごとにシートを作成してイベントログを出力
For i = 0 To UBound(strComputer)
    Sheets.Add After:=ActiveSheet
    Worksheets(Sheets.Count).Name = strComputer(i) & "_" & Format(Date, "yyyymmddhhmmss")
    'WMIオブジェクトの参照
    Set objWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!¥¥" & strComputer(i) & "¥root¥cimv2")
    'イベントログの抽出条件を指定したSQLを実行
    Set colEvents = objWMIService.ExecQuery _
        ("Select * from Win32_NTLogEvent Where TimeWritten >= '" & utcStartDate _
            & "' and (Logfile = 'System' or Logfile = 'Application')" _
            & "and (EventType = 1 or EventType = 2)")
    
        '項目名(ヘッダー)をワークシートに出力
        With ActiveCell
            .Offset(0, 0) = "レベル"
            .Offset(0, 1) = "イベントID"
            .Offset(0, 2) = "ソース"
            .Offset(0, 3) = "日付と時刻"
            .Offset(0, 4) = "メッセージ"
            .Offset(0, 5) = "ログ種別"
            .Offset(0, 6) = "コンピューター名"
            .Offset(0, 7) = "カテゴリ"
            .Offset(0, 8) = "レコード番号"
            .Offset(0, 9) = "ユーザー名"
            .Offset(1, 0).Select
        End With
        
        '抽出したイベントログをワークシートに出力
        For Each objEvent In colEvents
            With ActiveCell
                .Offset(0, 0).Value = objEvent.Type
                .Offset(0, 1).Value = objEvent.EventCode
                .Offset(0, 2).Value = objEvent.SourceName
                    
                    'UTC日時値を日本の標準時(JST)に変換
                    strTime = Left(objEvent.TimeWritten, 14)
                    strYear = Left(strTime, 4)
                    strMonth = Mid(strTime, 5, 2)
                    strDay = Mid(strTime, 7, 2)
                    strHour = Mid(strTime, 9, 2)
                    strMinute = Mid(strTime, 11, 2)
                    strSec = Mid(strTime, 13, 2)
                    
                    dateUTC = CDate(strYear & "/" & strMonth & "/" & strDay & " " _
                              & strHour & ":" & strMinute & ":" & strSec) + TimeValue("9:00:00")
                              
                .Offset(0, 3).Value = dateUTC
                .Offset(0, 4).Value = objEvent.Message
                .Offset(0, 5).Value = objEvent.LogFile
                .Offset(0, 6).Value = objEvent.ComputerName
                .Offset(0, 7).Value = objEvent.Category
                .Offset(0, 8).Value = objEvent.RecordNumber
                .Offset(0, 9).Value = objEvent.User
                .Offset(1, 0).Select
            End With
            
        Next objEvent
    Next i
    '出力したワークシートのA1セルに画面を移動
    Application.Goto Reference:=ActiveWindow.ActiveSheet.Range("A1"), Scroll:=True
    
    '画面更新を元に戻す(礼儀)
    Application.ScreenUpdating = True
End Sub

対象のリモートコンピューターの台数が不確定なので Redim Preserve を使って動的配列で処理していたりもいますが、サンプルプログラムの詳細な説明は省きます。

サンプルプログラムのダウンロード

上記のサンプルプログラムと設定シートを含んだExcelのマクロ付きファイルをダウンロードできるようにしました。

使用にあたっては自己責任、再配布は行わないでください。

サンプルプログラムをダウンロード

Windowsのイベントログの一覧をExcelのワークシートに出力するVBAのサンプルプログラムのまとめ

VBAで「WMIサービスオブジェクト」を操作してWindowsのイベントログを抽出、ワークシートに出力するサンプルプログラムについて説明しました。

説明の中では個人的に必要がないと思ったことは省略していたりもするので、詳細についてはMSDNのサイトなどを参照してください。

コメント

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