利用 WMI 事件訂閱機制 (ExecNotificationQuery) 監聽網路介面卡連線/斷線狀態變化,基於 MSNdis_StatusMediaConnect 與 MSNdis_StatusMediaDisconnect 類別,實現無輪詢、即時響應的網路狀態監控。
一、監聽網路連線事件
' === NetConnectMonitor.vbs ===
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\wmi")
' 訂閱連線事件
Set colEvents = objWMI.ExecNotificationQuery("SELECT * FROM MSNdis_StatusMediaConnect")
WScript.Echo "Monitoring network CONNECT events... (Ctrl+C to stop)"
Do While True
' 同步阻塞等待下一事件
Set objEvent = colEvents.NextEvent
WScript.Echo "=== Network CONNECTED ==="
WScript.Echo "Adapter: " & objEvent.InstanceName
WScript.Echo "Time: " & Now
WScript.Echo ""
Loop
二、監聽網路斷線事件
' === NetDisconnectMonitor.vbs ===
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\wmi")
' 訂閱斷線事件
Set colEvents = objWMI.ExecNotificationQuery("SELECT * FROM MSNdis_StatusMediaDisconnect")
WScript.Echo "Monitoring network DISCONNECT events... (Ctrl+C to stop)"
Do While True
Set objEvent = colEvents.NextEvent
WScript.Echo "=== Network DISCONNECTED ==="
WScript.Echo "Adapter: " & objEvent.InstanceName
WScript.Echo "Time: " & Now
WScript.Echo ""
Loop
三、合併版:單一腳本雙向監聽
' === NetStatusMonitor.vbs ===
Option Explicit
Dim strComputer, objWMI, colConnect, colDisconnect, objEvent
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\wmi")
Set colConnect = objWMI.ExecNotificationQuery("SELECT * FROM MSNdis_StatusMediaConnect")
Set colDisconnect = objWMI.ExecNotificationQuery("SELECT * FROM MSNdis_StatusMediaDisconnect")
WScript.Echo "Network Status Monitor Started - " & Now
WScript.Echo "Listening on root\wmi for MediaConnect/Disconnect..."
WScript.Echo "Press Ctrl+C to stop."
WScript.Echo ""
' 使用非同步事件接收器 (SWbemSink) 實現並發監聽
Dim sinkConnect, sinkDisconnect
Set sinkConnect = WScript.CreateObject("WbemScripting.SWbemSink", "Connect_")
Set sinkDisconnect = WScript.CreateObject("WbemScripting.SWbemSink", "Disconnect_")
objWMI.ExecNotificationQueryAsync sinkConnect, "SELECT * FROM MSNdis_StatusMediaConnect"
objWMI.ExecNotificationQueryAsync sinkDisconnect, "SELECT * FROM MSNdis_StatusMediaDisconnect"
' 保持腳本運行
Do While True
WScript.Sleep 1000
Loop
' === 事件處理函數 ===
Sub Connect_OnObjectReady(objEvent, objAsyncContext)
LogEvent "CONNECTED", objEvent.InstanceName
End Sub
Sub Disconnect_OnObjectReady(objEvent, objAsyncContext)
LogEvent "DISCONNECTED", objEvent.InstanceName
End Sub
Sub LogEvent(action, adapter)
Dim logLine
logLine = "[" & FormatDateTime(Now, 2) & " " & FormatDateTime(Now, 4) & "] " & _
action & " - Adapter: " & adapter
WScript.Echo logLine
' 可擴展:寫入日誌檔、發送郵件、觸發 API 等
' Dim fso, logFile
' Set fso = CreateObject("Scripting.FileSystemObject")
' Set logFile = fso.OpenTextFile("net_monitor.log", 8, True)
' logFile.WriteLine logLine
' logFile.Close
End Sub
四、關鍵技術點解析
| 技術點 | 說明 | 注意事項 |
| 命名空間 | root\wmi (非標準 cimv2) | NDIS 狀態類別僅在 root\wmi 可用 |
| 事件類別 | MSNdis_StatusMediaConnect / Disconnect | 對應 NDIS_STATUS_MEDIA_CONNECT/DISCONNECT |
| 同步 vs 非同步 | NextEvent 阻塞 / ExecNotificationQueryAsync 回調 | 非同步支援並發多事件源 |
| 事件屬性 | InstanceName (網卡名稱)、Active (布林) | 可關聯 Win32_NetworkAdapter 獲取詳細資訊 |
| 權限需求 | 需管理員權限或 WMI 權限 | 標準用戶可能無法訂閱 root\wmi |
五、事件屬性擴展:關聯網卡詳細資訊
Sub LogEvent(action, instanceName)
Dim objWMI, colAdapters, adapter, desc, mac, speed
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
' 關聯 Win32_NetworkAdapter 獲取描述、MAC、速度
Set colAdapters = objWMI.ExecQuery("SELECT * FROM Win32_NetworkAdapter WHERE Name = '" & instanceName & "'")
For Each adapter In colAdapters
desc = adapter.Description
mac = adapter.MACAddress
speed = adapter.Speed
Next
WScript.Echo "[" & Now & "] " & action
WScript.Echo " Instance: " & instanceName
WScript.Echo " Description: " & desc
WScript.Echo " MAC: " & mac
WScript.Echo " Speed: " & FormatNumber(speed / 1000000, 0) & " Mbps"
WScript.Echo ""
End Sub
六、部署為 Windows 服務 (持續運行)
' === 安裝為服務 (需 SRVANY/Non-Sucking Service Manager) ===
' 1. 安裝 NSSM: nssm install NetMonitor
' 2. 設定:
' Path: C:\Windows\System32\wscript.exe
' Arguments: C:\Scripts\NetStatusMonitor.vbs
' Startup: Automatic
' 3. 啟動: nssm start NetMonitor
' === 或使用 Windows 任務排程器 ===
' 觸發器: 開機時 / 使用者登入時
' 動作: wscript.exe C:\Scripts\NetStatusMonitor.vbs
' 設定: 使用最高權限執行、不儲存密碼
七、PowerShell 現代化實現 (推薦)
# Register-WmiEvent 原生支援非同步事件訂閱
$action = {
$event = $Event.SourceEventArgs.NewEvent
$adapter = $event.InstanceName
$time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$type = if ($Event.SourceIdentifier -like "*Connect*") { "CONNECTED" } else { "DISCONNECTED" }
Write-Host "[$time] $type - Adapter: $adapter"
# 關聯網卡詳細資訊
$nic = Get-CimInstance Win32_NetworkAdapter -Filter "Name='$adapter'"
if ($nic) { Write-Host " Desc: $($nic.Description), MAC: $($nic.MACAddress), Speed: $($nic.Speed/1Mb) Mbps" }
}
Register-WmiEvent -Namespace "root\wmi" -Class "MSNdis_StatusMediaConnect" -SourceIdentifier "NetConnect" -Action $action
Register-WmiEvent -Namespace "root\wmi" -Class "MSNdis_StatusMediaDisconnect" -SourceIdentifier "NetDisconnect" -Action $action
Write-Host "Monitoring started. Press Ctrl+C to stop."
# 保持運行
while ($true) { Start-Sleep 10 }
# 清理
Get-EventSubscriber | Unregister-Event
八、適用場景與限制
| 適用場景 | 限制 |
| 伺服器網路斷線告警 | 需管理員權限,標準用戶受限 |
| 筆記本乾淨/接入網路觸發同步 | 虛擬網卡 (Hyper-V, VPN) 也會觸發事件 |
| 嵌入式裝置網路狀態上報 | WMI 服務異常時監聽失效 |
| 安全審計:未授權網卡啟用檢測 | 無法區分物理拔插 vs 軟體啟停 |
總結:WMI 事件訂閱提供了優雅的「推模式」網路監控,避免輪詢 CPU 佔用。VBScript 版適合輕量部署、無 PowerShell 環境;生產環境強烈建議使用 PowerShell Register-WmiEvent 或 C# ManagementEventWatcher,享受更豐富的事件處理管線、錯誤恢復與診斷能力。