VBScriptを掌握せよ:WMIイベント駆動による「レジストリ監視・自動復旧」の極意
諸君、業務自動化の現場で「なぜか設定が元に戻ってしまう」「誰がいつ設定を変えたか分からない」という悪夢に直面したことはないだろうか。
多くのエンジニアは、ここで「定期実行スクリプト(ポーリング)」という愚策に走る。1分おきにレジストリを読み込み、差分を比較する。これではCPUを無駄に食う上に、変更から検知までの「空白の時間」に脆弱性が生まれる。
真のアーキテクトは、OSの深淵――WMI (Windows Management Instrumentation) を叩く。今回は、レジストリの変更をイベントとしてリアルタイムに検知し、瞬時にロールバックさせる「非同期監視アーキテクチャ」を伝授する。
—
1. なぜ「イベント駆動」でなければならないのか
ポーリング(定期監視)がなぜ悪なのか。それは「観測者効果」と「非効率なリソース消費」の二重苦だからだ。
WMIには `RegistryTreeChangeEvent` という、レジストリの特定の枝(Hive)を監視し、変更があった瞬間にイベントを発火させる強力なインターフェースが存在する。これを使えば、スクリプトは「待ち」の状態に入り、変更が発生した瞬間だけOSから叩き起こされる。これが、システム負荷を最小限に抑えつつ、即時性を担保する唯一の解だ。
—
2. 実装コード:堅牢な監視エージェント
このスクリプトは、指定したレジストリキーが改変された瞬間、即座に正しい値へと書き戻す「自己治癒型」のコードである。
‘ ==============================================================================
‘ RegistryGuardian.vbs
‘ 用途: 特定レジストリキーの改変を監視し、即座に元の値へ復旧させる
‘ ==============================================================================
Option Explicit
Dim strComputer, objWMIService, objEventSource, objEvent
strComputer = “.”
‘ 監視対象のパス(例: HKEY_CURRENT_USER\Software\MyApp)
‘ WMIの仕様上、Hiveは定数で指定する必要がある
Const HIVE = &H80000001 ‘ HKEY_CURRENT_USER
Const KEY_PATH = “Software\\MyApp”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\default”)
‘ RegistryTreeChangeEventをクエリで登録
‘ Hive: 監視対象ルート, RootPath: 監視対象サブキー
Set objEventSource = objWMIService.ExecNotificationQuery _
(“SELECT FROM RegistryTreeChangeEvent WHERE Hive='” & HIVE & “‘ AND RootPath='” & KEY_PATH & “‘”)
WScript.Echo “監視を開始しました: ” & KEY_PATH
Do
‘ イベントが発生するまで、この行でスレッドは待機(CPU消費ゼロ)
Set objEvent = objEventSource.NextEvent
‘ 変更を検知したら即座に復旧処理へ
Call RestoreRegistryValue()
WScript.Echo “不正な変更を検知:自動復旧を実行しました。”
Loop
Sub RestoreRegistryValue()
Dim objShell
Set objShell = CreateObject(“WScript.Shell”)
‘ 正しい値を再設定(ここでは例としてDWORD値)
objShell.RegWrite “HKCU\” & KEY_PATH & “\TargetValue”, 1, “REG_DWORD”
Set objShell = Nothing
End Sub
—
3. プロダクション環境で生き残るための設計思想
このスクリプトを「おもちゃ」で終わらせないために、以下の3点を徹底してほしい。
① WMIの「名前空間」への理解
`root\default` を使用していることに注目してほしい。レジストリ操作のためのWMIクラス `StdRegProv` はこの名前空間に属している。これを知らずに `root\cimv2` を叩いても何も起きない。基礎中の基礎だが、ここを間違えて「動かない」と嘆くエンジニアが後を絶たない。
② 無限ループとメモリリークの管理
WScript.Shellは強力だが、ループ内で闇雲に生成・破棄を繰り返すと、GC(ガベージコレクション)が追いつかない環境ではメモリリークの原因となる。本番環境では、監視対象が複数ある場合などは、イベント通知に対して適切なスレッド処理を行うか、エラーハンドリング(`On Error Resume Next`)を適切に配置し、監視プロセスがゾンビ化しないよう死活監視を別途設けるのがプロの流儀だ。
③ 権限と実行環境
このスクリプトは「管理者権限」で実行しなければならない。また、WSH(`wscript.exe`)で実行するとウィンドウが残るため、バックグラウンド実行を目的とするなら `cscript.exe //nologo` で実行し、タスクスケジューラに「ユーザーのログオンに関わらず実行」で登録するのが定石である。
—
4. 最後に:エンジニアへの提言
VBScriptは「古い」と言われる。しかし、OSの根幹にこれほど深く、かつ低コストでアクセスできる手段を、諸君は他に知らないはずだ。
自動化の本質は、言語の流行り廃りではない。「OSが提供しているAPIの意図をどれだけ汲み取り、いかに無駄なく処理を繋ぐか」という設計思想そのものである。
このスクリプトを、諸君の現場の「盾」として活用してほしい。もし改変を検知した際のログをデータベースやファイルに残したいのであれば、`RestoreRegistryValue` 関数の中に `Scripting.FileSystemObject` を使ったログ書き出し処理を一行追加するだけでいい。
設計さえ正しければ、VBScriptは今なお、最も信頼できる「現場の自動化エンジン」足り得るのだ。
