ネットワークの迷宮を制する:WMIを用いた動的メトリック制御の深淵
ネットワーク管理において、マルチホーム環境(有線/無線混在)のルーティング制御は、多くのシステム管理者が避けて通る「鬼門」だ。OSの自動メトリックに任せれば、大抵は不安定なWi-Fiが優先され、基幹システムへの接続が瞬断する。
現代のモダンな言語であればライブラリが解決してくれるかもしれない。だが、我々が守り抜くべきレガシーなオンプレミス環境や、軽量なエッジ端末において、VBScriptとWMI(Windows Management Instrumentation)ほど、低コストかつ強力な武器はない。
今日は、ルーティングテーブルの「メトリック」をVBScriptから動的に操作し、ネットワークの通信路を力技で掌握する極限の知見を授ける。
—
1. WMIの深淵とWin32_IP4RouteTableの罠
ルーティングテーブルを操作する際、多くのエンジニアは`route.exe`を`WScript.Shell`経由で叩く。だが、それは素人のやり方だ。実行結果のパース(文字列解析)は非効率であり、エラーハンドリングも極めて脆弱だ。
我々は `Win32_IP4RouteTable` を直接叩く。ただし、このクラスはデータ取得専用だ。メトリックの変更には `SetDynamicParameter` 等のメソッドを駆使するか、あるいはWMI経由でプロキシオブジェクトを操作する必要がある。しかし、最も確実で移植性が高いのは、WMI経由で「どのインターフェースを優先させるか」というメトリック値を、OSの管理層に直接書き込むことだ。
—
2. 実装:動的メトリック制御スクリプト
以下に、対象となるインターフェースのインデックスを特定し、メトリックを書き換えるための高信頼性スクリプトを示す。
‘ ==============================================================================
‘ NetworkRouteController.vbs
‘ 目的: 指定したインターフェースのメトリックを動的に更新し、経路を強制制御する
‘ 著者: Chief Architect
‘ ==============================================================================
Option Explicit
Dim objWMIService, colRoutes, objRoute
Dim strTargetInterfaceIndex, intNewMetric
‘ 設定値:対象のインターフェースインデックスと、設定したいメトリック値
strTargetInterfaceIndex = “11” ‘ ipconfig /all で確認可能なIFインデックス
intNewMetric = 10 ‘ 低い値ほど優先度が高い
Set objWMIService = GetObject(“winmgmts:\\.\root\cimv2”)
‘ Win32_IP4RouteTable は実行時にシステム負荷をかけるため、必要最低限の絞り込みを行う
Set colRoutes = objWMIService.ExecQuery _
(“SELECT FROM Win32_IP4RouteTable WHERE InterfaceIndex = ‘” & strTargetInterfaceIndex & “‘”)
If colRoutes.Count = 0 Then
WScript.Echo “Target interface not found.”
WScript.Quit
End If
For Each objRoute In colRoutes
‘ ここで重要なのは、オブジェクトのプロパティを直接操作するのではなく、
‘ Win32_NetworkAdapterConfiguration を介したIP設定の更新を行うことである。
‘ ルートテーブルのメトリック直接書き込みはOS再起動で消失するため、
‘ 恒久的な設定にはアダプタのメトリック値を強制する。
UpdateMetric strTargetInterfaceIndex, intNewMetric
Next
‘ オブジェクトの明示的解放(メモリリークは許されない)
Set colRoutes = Nothing
Set objWMIService = Nothing
Sub UpdateMetric(ifIndex, metricValue)
Dim objConfig, colConfigs, objNetAdapter
Set colConfigs = GetObject(“winmgmts:\\.\root\cimv2”).ExecQuery _
(“SELECT FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True”)
For Each objConfig In colConfigs
‘ インデックスが一致するアダプタのメトリックを設定
If objConfig.InterfaceIndex = CInt(ifIndex) Then
‘ SetIPConnectionMetric メソッドを呼び出し、メトリックを書き込む
If objConfig.SetIPConnectionMetric(metricValue) = 0 Then
WScript.Echo “Success: Interface ” & ifIndex & ” metric set to ” & metricValue
Else
WScript.Echo “Failed: Access Denied or Invalid Index”
End If
End If
Next
Set colConfigs = Nothing
End Sub
—
3. シニアエンジニアが意識すべき「メモリと実行コスト」
このスクリプトを運用する上で、留意すべきポイントは以下の通りだ。
1. オブジェクトのライフサイクル管理:
VBScriptのガベージコレクションは頼りにならない。ループ内で生成される `GetObject` や `ExecQuery` の結果セットは、必ず `Set obj = Nothing` で明示的に破棄せよ。特に監視サイクル(数秒置きのループ)を組む場合、解放を忘れるとメモリ消費が肥大化し、数日でプロセスが死ぬ。
2. 実行権限の壁:
`SetIPConnectionMetric` はネットワーク設定を変更するため、当然ながら管理者権限(UAC昇格)が必須だ。タスクスケジューラで「最上位の権限で実行」オプションを必ず有効にすること。
3. レガシー環境の保守性:
WMIクエリは、OSのマイナーバージョンアップでプロパティ名が変わることは稀だが、NICのドライバが独自仕様を実装している場合、値が取得できないことがある。必ず `If IsNull(…)` 等のチェックを行い、防衛的プログラミングを徹底せよ。
結論:自動化は「静寂」でなければならない
ネットワークの切り替えを自動化する理由は、ユーザーに「今、経路が切り替わりました」と意識させないためだ。ログは最小限に、しかし異常時は詳細に。
このWMIによるメトリック制御は、レガシーなWindows環境における「最後の切り札」となる。モダンなクラウドネイティブな世界へ移行するまでの間、この堅牢なアーキテクチャが諸君の現場を守る盾となることを確信している。
もし君が真のエンジニアなら、コードをコピペする前に、そのNICのバッファリング特性と、OSがメトリックを再計算するタイミングを理解した上で実装してほしい。健闘を祈る。
