【VBScript極意】WMIで実現する「イベントログ監視」の堅牢な設計論
システム管理の現場において、Windowsイベントログの海から「真に重要なエラー」だけを掬い上げることは、情シス担当者にとっての永遠の課題だ。GUIのイベントビューアを眺める時間は無駄である。
今回は、WMI(Windows Management Instrumentation)の`Win32_NTLogEvent`を叩き、特定のIDやソースをピンポイントで射抜く監査支援ツールを設計する。VBScriptはレガシーと言われるが、OSネイティブで動作し、追加インストール不要という点において、依然として「緊急時のレスキューツール」として最強の地位にある。
ただし、書き方を間違えればシステム負荷を爆上げする諸刃の剣であることを忘れてはならない。
—
1. なぜ「WMIクエリ」を直打ちしてはいけないのか
多くの初心者は、WQL(WMI Query Language)をループの中で何度も発行する愚を犯す。WMIは強力だが、クエリのたびにOS内部でプロバイダがイベントログをスキャンするため、重い。
設計の鉄則:
- フィルタリングはクエリ側で行う: `SELECT ` で全件取得し、VBScript側で `If` 文で回すのは絶対NG。WQLの `WHERE` 句で絞り込み、メモリ消費を最小限に抑えろ。
- 実行間隔の適正化: このスクリプトをタスクスケジューラで回す場合、過去ログとの重複を避けるための「タイムスタンプ管理」が必須だ。
—
2. プロダクションコード:高信頼性イベント監査ツール
このコードは、指定したイベントIDとソースを抽出し、CSVログへの追記と管理担当者への通知を行う雛形である。
‘ — 設定エリア —
Const EVENT_ID = 1000 ‘ 監視対象のイベントID
Const LOG_SOURCE = “Application” ‘ ログの種類 (System, Application等)
Const TARGET_SOURCE = “MyBusinessApp” ‘ 監視するソース名
Const LOG_FILE = “C:\Logs\Audit_Error.csv”
Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)
‘ 過去1時間以内に発生した特定エラーのみを抽出するWQL
‘ TimeGeneratedの比較はWMIの日付形式(YYYYMMDDHHMMSS)に変換が必要だが、
‘ 今回はシンプルに最新のものを取得する設計とする
strQuery = “SELECT FROM Win32_NTLogEvent WHERE Logfile='” & LOG_SOURCE & _
“‘ AND EventCode=” & EVENT_ID & _
” AND SourceName='” & TARGET_SOURCE & “‘”
Set colEvents = objWMIService.ExecQuery(strQuery)
If colEvents.Count > 0 Then
Set objFSO = CreateObject(“Scripting.FileSystemObject”)
Set objFile = objFSO.OpenTextFile(LOG_FILE, 8, True) ‘ 8: ForAppending
For Each objEvent In colEvents
‘ CSV形式でログ保存
strLine = Now & “,” & objEvent.EventCode & “,” & objEvent.Message
objFile.WriteLine(strLine)
Next
objFile.Close
‘ ここで必要に応じてCDO等を使用してメール通知をトリガーする
End If
Set colEvents = Nothing
Set objWMIService = Nothing
—
3. 実務で「詰まない」ための3つの知見
① メモリリークとオブジェクト解放の作法
VBScriptはガベージコレクションが強力ではない。`Set obj = Nothing` を省略するエンジニアがいるが、本番環境で長期間動作させるタスクにおいては、意図的にメモリを解放する癖をつけろ。複雑なループ内でのオブジェクト生成は避けるのが基本だ。
② WMIクエリの「日付」の壁
`Win32_NTLogEvent` の `TimeGenerated` は WMI形式(例:20231027120000.000000+540)である。単純な比較演算子ではうまく動かないことが多い。実務では「直近X件」を取得するロジックにするか、あるいは `WbemScripting.SWbemDateTime` オブジェクトを使って厳密にフィルタリングする設計を推奨する。
③ ファイルI/Oの競合回避
ログファイルへの書き込み時、複数のプロセスが同時にアクセスするとエラーになる。`OpenTextFile` を開く際は、エラーハンドリング(`On Error Resume Next` を活用し、`Err.Number` をチェックする)を必ず実装すること。
—
最後に:自動化の先にあるもの
このツールをタスクスケジューラに登録する際は、「実行アカウントの権限」に注意せよ。イベントログへのアクセスには管理権限が必要だ。
VBScriptは、コードが簡潔であるがゆえに「誰でも書ける」と思われがちだ。しかし、真のエンジニアは、その動作の裏側にあるWin32 APIの挙動や、WMIプロバイダの負荷までを想像してコードを書く。
この雛形をカスタマイズし、君の環境における「真の静寂」を守るための監視体制を構築してほしい。質問があればいつでも来い。現場からは以上だ。
