サービス依存関係の深淵:WMI再帰探索で描く「システム停止のドミノ倒し」可視化
システム運用において最も恐ろしいのは、たった一つのサービスを停止させた瞬間に、予期せぬ「ドミノ倒し」が発生し、業務システム全体が沈黙することだ。特にレガシーなWindows Server環境では、サービスの依存関係はブラックボックス化しがちである。
今日は、VBScriptとWMI(Windows Management Instrumentation)を駆使し、依存関係の深淵を再帰的にトレースする。単なるコードの羅列ではない。メモリ管理とオブジェクトのライフサイクルを制御し、大規模環境でも確実に動作する「システム構成マップ生成エンジン」の核心を解説する。
—
1. なぜWMIとVBScriptなのか?
現代のDevOps環境ではPowerShellが主流だが、閉鎖的なエンタープライズ環境や、軽量なエージェントレス運用を求められる現場では、依然としてWSH (Windows Script Host) が最強の武器となる。依存関係の解決には`Win32_Service`クラスの`Dependent`プロパティではなく、中間クラスである`Win32_DependentService`を叩く必要がある。ここを見誤ると、実行コストは指数関数的に増大する。
2. 依存関係再帰探索の極限アルゴリズム
以下のコードは、指定したサービスから「どのサービスが影響を受けるか(依存先)」を再帰的に掘り下げるためのエンジンの雛形だ。
‘ — System Service Dependency Mapper —
Option Explicit
Dim objWMIService, objFile, fso
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set objFile = fso.CreateTextFile(“ServiceMap.txt”, True)
‘ WMI接続:ローカルホストだが、必要に応じてIP指定可能
Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)
‘ 解析開始点(例:MSSQLSERVER)
Call MapDependency(“MSSQLSERVER”, 0)
objFile.Close
Set objFile = Nothing
Set objWMIService = Nothing
WScript.Echo “マップ生成完了。”
Sub MapDependency(strServiceName, intLevel)
Dim colDeps, objDep
Dim strIndent
strIndent = Space(intLevel 4)
‘ Win32_DependentServiceクラスを利用し、Dependent(依存側)を検索
‘ Antecedentは「前提となるサービス」
Set colDeps = objWMIService.ExecQuery _
(“SELECT FROM Win32_DependentService WHERE Antecedent = ‘Win32_Service.Name=””” & strServiceName & “””‘”)
For Each objDep In colDeps
Dim strDependentName
‘ 依存サービスのパスから名称を抽出
strDependentName = Split(Split(objDep.Dependent, “=”)(1), “”””)(1)
‘ 結果をファイルへ書き出し
objFile.WriteLine strIndent & “└─ ” & strDependentName
‘ 再帰呼出し:ここでスタックオーバーフローに注意する設計が必要
MapDependency strDependentName, intLevel + 1
Next
‘ 明示的なオブジェクト解放(VBScriptのGCを待たない)
Set colDeps = Nothing
End Sub
3. チーフアーキテクトからの「極限の知見」
このスクリプトを実戦に投入するにあたり、以下の3点を肝に銘じてほしい。
① オブジェクトのライフサイクル管理
VBScriptの`Set obj = Nothing`は、単なる気休めではない。WMIの`ExecQuery`は巨大なコレクションをメモリ上に展開する。再帰処理の中で生成されるコレクションを適切に破棄しないと、数百のサービスを持つサーバーではメモリリークが即座に発生し、スクリプトホストがハングアップする。`Set`をループの末尾で確実に呼ぶことは、この世界におけるエンジニアの作法だ。
② 循環参照(Circular Dependency)への耐性
稀に、AがBに依存し、BがAに依存するという「循環参照」が存在する。上のコードをそのまま回すと無限ループに陥る。実戦では、`Scripting.Dictionary`オブジェクトを使い、一度走査したサービス名をキーとして格納し、「すでに処理済みか?」をチェックするフラグ処理を必ず追加せよ。
③ パフォーマンスのボトルネック
`Win32_DependentService`へのクエリは、WMIリポジトリへの高コストなアクセスを伴う。もし対象が数千台のサーバーであれば、クエリを一度投げて全データをメモリ上の辞書(Dictionary)にキャッシュし、そのメモリ上で再帰処理を行うべきだ。WMIへのクエリ回数を減らすことこそが、パフォーマンス改善の唯一にして最短の道である。
結論:システムの「見えない線」を可視化せよ
システム管理者にとって、サービス構成マップは地図だ。地図を持たずに嵐(システム障害)の中を航海してはならない。
VBScriptは古びた言語と揶揄されることもあるが、OSの深部にダイレクトにアクセスし、複雑な依存関係を数行のコードで暴き出すその鋭利さは、今なお一級品だ。このコードをベースに、各環境のサービス構成に応じた最適化を施してほしい。
君たちが記述するその一行が、明日、現場の誰かの「停止ボタンを押す震える指」を救うかもしれないのだから。
