VBScriptで極めるイベント駆動:WMI非同期クエリによる「監視」の神髄
多くのエンジニアが「監視」と聞いて真っ先に思い浮かべるのは、`Do…Loop`の中に`WScript.Sleep`を仕込んだ、あの哀れなポーリング・ループだろう。
CPUサイクルを無駄に食いつぶし、イベント発生から検知までのタイムラグを許容するその実装は、もはや「自動化」ではなく「リソースの浪費」に過ぎない。真に洗練されたシステムは、OSの深層部で鳴り響くイベントを直接キャッチする。
今日は、WMI(Windows Management Instrumentation)の`ExecNotificationQuery`を使い、OSのイベントを直接購読(Subscribe)する「イベント駆動型VBScript」の極意を伝授する。
—
1. なぜ「ポーリング」を捨てなければならないのか
ポーリング方式の最大の問題は、「不確定なレイテンシ」と「計算資源の揮発」だ。
`Sleep 1000`を設定すれば、最小でも1秒の遅延が確定する。かといって短くすれば、CPU負荷は跳ね上がる。
対して、`ExecNotificationQuery`を用いた非同期クエリは、WMIリポジトリ内で発生したイベントをOS側が「通知」してくれる仕組みだ。スクリプト側は、イベントが届くまでスレッドを効率的に待機させることができる。これがアーキテクトが選ぶべき、本来の「監視」の姿である。
—
2. 実装:プロセスの起動をリアルタイムで検知する
以下のコードは、`Win32_ProcessStartTrace`を購読し、システム上でプロセスが起動した瞬間にその詳細をキャッチする実装だ。
‘ — WMI非同期クエリによるプロセス監視 —
Option Explicit
Dim objWMIService, objEventSource
Dim strComputer, strQuery
strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
‘ プロセス起動イベントを購読するクエリ
‘ 5秒間隔のポーリングではなく、イベント発生時に即座に通知が飛ぶ
strQuery = “SELECT FROM Win32_ProcessStartTrace”
‘ 非同期クエリの発行
Set objEventSource = objWMIService.ExecNotificationQuery(strQuery)
WScript.Echo “監視を開始しました… (Ctrl+C で終了)”
Do
‘ イベントが発生するまで、ここでスレッドがブロックされ待機する
‘ CPU負荷は極限までゼロに近い
Dim objEvent
Set objEvent = objEventSource.NextEvent
‘ イベント検知後の処理
WScript.Echo “プロセス起動検知: ” & objEvent.ProcessName & ” (PID: ” & objEvent.ProcessID & “)”
‘ メモリ最適化:不要なオブジェクトは即座に解放する
Set objEvent = Nothing
Loop
‘ 本来ここには到達しないが、クリーンアップの習慣を忘れてはならない
Set objEventSource = Nothing
Set objWMIService = Nothing
—
3. 実践的知見:メモリ管理とライフサイクル
VBScriptはガベージコレクションの挙動が不透明だ。長時間稼働する監視スクリプトにおいて、オブジェクトの解放(`Set obj = Nothing`)を怠ることは、確実にメモリリークへの道を歩むことを意味する。
特に`ExecNotificationQuery`のようなストリーム型のオブジェクトを扱う場合、以下のルールを徹底せよ。
- スコープの最小化: 監視ループ内部で生成するオブジェクトは、可能な限りループの末尾で明示的に`Nothing`を代入せよ。
- エラーハンドリングの注入: `On Error Resume Next`を多用するのは三流だ。WMIの接続が断たれた場合(WMIサービス再起動など)を想定し、エラー発生時にクエリを再接続する堅牢なループ構造を構築すること。
—
4. 応用:ファイル監視への転換
`Win32_ProcessStartTrace`を、`__InstanceCreationEvent`(`TargetInstance ISA ‘CIM_DataFile’`)に差し替えれば、特定のディレクトリにファイルが生成された瞬間にトリガーを引く監視システムへと変貌する。
ただし、注意が必要だ。`__InstanceCreationEvent`はシステムの全域を監視するため、クエリの`Within`句でポーリング間隔を適切に指定しないと、システム全体のWMIパフォーマンスに影響を及ぼす。
‘ ファイル生成監視のクエリ例
strQuery = “SELECT FROM __InstanceCreationEvent WITHIN 5 ” & _
“WHERE TargetInstance ISA ‘CIM_DataFile’ ” & _
“AND TargetInstance.Drive = ‘C:’ ” & _
“AND TargetInstance.Path = ‘\\temp\\'”
—
最後に:レガシーを「武器」にする
VBScriptは古臭い言語だと言われる。しかし、外部ライブラリのインストールを許されない強固なセキュリティ環境や、Windows Server 2003/2008といったレガシーOSが今なお現役で動く現場において、これほど軽く、パワフルな武器はない。
OSの機能をハックするように使いこなすこと。それが、真の業務自動化エンジニアの嗜みだ。
次に何かを「監視」する必要に迫られたとき、`Sleep`ループを書く手は止まるはずだ。それが、君が一段上のステージへ到達した証である。
