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から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)に変換する処理の詳細については、以下の記事を参照してください。
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のサイトなどを参照してください。
コメント