VBScriptを極める:WMIイベント監視で実現する「ゼロ遅延」のリアルタイム・システム監視
多くのエンジニアが「VBScriptはレガシーだ」と口にする。だが、OSにネイティブで搭載され、数キロバイトのメモリ消費でバックグラウンド常駐が可能なこの言語は、軽量な監視エージェントとしては依然として最強のツールの一つだ。
今日は、WMI(Windows Management Instrumentation)の真髄である `ExecNotificationQuery` を用い、Windowsイベントログを「ポーリング(定期監視)」ではなく「プッシュ型」で検知する、堅牢な監視モジュールの設計思想を伝授する。
なぜ「ポーリング」ではいけないのか?
初心者レベルの監視ツールは、`Sleep` を挟んだループでイベントログを定期的に読みに行く。これは最悪の悪手だ。
1. リソースの無駄: ログに変化がなくてもCPUを消費し続ける。
2. 検知の遅延: スリープ時間の間に発生したイベントは、次の実行タイミングまで闇に葬られる。
3. 競合リスク: ログファイルへのアクセスが重なることで、Windows側の書き込み処理と干渉する可能性がある。
今回解説する `ExecNotificationQuery` は、WMIのイベントサブシステムを利用する。OSがイベントを生成した瞬間にスクリプトが叩き起こされるため、遅延ゼロ、かつCPU負荷ゼロという理想的な環境が手に入る。
実装:イベントログ監視モジュールのプロダクションコード
このコードは、ログオン失敗(イベントID 4625)を検知し、即座にログファイルへ記録する堅牢な構造を持っている。
Option Explicit
‘ WMI接続情報の定義
Dim objWMIService, objEventQuery, objEvent
Dim strComputer, strQuery
strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
‘ 【重要】WQLクエリの設計
‘ “__InstanceCreationEvent” をターゲットにすることで、ログ生成の瞬間をフックする
‘ TargetInstance ISA ‘Win32_NTLogEvent’ でイベントログのみを監視対象に絞る
strQuery = “SELECT FROM __InstanceCreationEvent WITHIN 5 WHERE ” & _
“TargetInstance ISA ‘Win32_NTLogEvent’ AND ” & _
“TargetInstance.EventCode = 4625”
Set objEventQuery = objWMIService.ExecNotificationQuery(strQuery)
WScript.Echo “監視システムが起動しました…”
‘ 無限ループによる常駐(リソース消費はOS側のWMIに依存するため極小)
Do
‘ イベントが発生するまでここでスレッドが待機(ブロッキング)
Set objEvent = objEventQuery.NextEvent
‘ 検知後の処理(ログ出力等の関数を呼び出す)
Call LogAlert(objEvent.TargetInstance)
Loop
‘ 検知後のログ記録用関数
Sub LogAlert(evt)
Dim fso, ts
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 追記モードでログを開く(共有違反を防ぐため都度開閉)
Set ts = fso.OpenTextFile(“C:\Logs\SecurityAlert.log”, 8, True)
ts.WriteLine Now & ” | EventID: ” & evt.EventCode & ” | Message: ” & evt.Message
ts.Close
End Sub
運用で死なないための「3つの極意」
1. 例外処理と堅牢性
上記のコードはシンプルだが、本番環境では `On Error Resume Next` を適切に配置し、万が一のアクセス拒否やログファイルのロック時にスクリプトがクラッシュしないようガードする必要がある。特に `OpenTextFile` は、他のプロセスがログを掴んでいるとエラーを吐く。エラーハンドリングは「エラーを隠すため」ではなく「プロセスを止めないため」にある。
2. クエリの最適化(WITHIN句の意味)
クエリ内の `WITHIN 5` は重要だ。これは「最低でも5秒に1回はポーリングを行う」という内部的なタイマーを指定している。WMIイベントが即座に飛んでこない場合でも、このインターバルによって整合性が保たれる。パフォーマンスと即時性のバランスを、環境に応じて調整してほしい。
3. オブジェクトのライフサイクル
VBScriptはメモリ管理が甘い。常駐監視スクリプトでは、ループ内で生成するオブジェクトを必ず `Set obj = Nothing` で解放し、メモリリークを未然に防ぐのがプロの流儀だ。特に今回のスクリプトを長時間動かす場合は、メモリ使用量をタスクマネージャーで監視し、必要であれば数日おきにタスクスケジューラでプロセスを再起動する設計も検討すべきである。
結論:VBScriptはまだ終わっていない
高機能な監視ソリューションが普及した現代においても、特定のローカルサーバーで「軽量・高速・依存なし」で動くこのスクリプトは、インフラエンジニアの最強の武器であり続ける。
「とりあえず動く」から「止まらないコード」へ。この設計思想をインストールした君なら、どのような監視要件でも確実に仕留められるはずだ。健闘を祈る。
