雖然標題提到 Java,但原文實際展示的是一段 **VBScript / WMI 腳本**,用於在 Windows 環境下啟動兩個程式(計算機與記事本),監聽第一個程式退出事件,隨即終止第二個程式。這類腳本常用於系統管理、測試環境編排或 CI/CD 前置腳本。本文將原始碼重構為可讀性更強的版本,並詳細解析核心 WMI 查詢與事件監聽機制。
calc.exe)與程式 B(如 notepad.exe)。' ===== 啟動兩個程式並取得 Process ID =====
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
' 啟動計算機
errResult = objWMIService.Create("calc.exe", Null, Null, intCalcID)
If errResult <> 0 Then WScript.Echo "啟動 calc.exe 失敗, 錯誤碼: " & errResult : WScript.Quit
' 啟動記事本
errResult = objWMIService.Create("notepad.exe", Null, Null, intNotepadID)
If errResult <> 0 Then WScript.Echo "啟動 notepad.exe 失敗, 錯誤碼: " & errResult : WScript.Quit
WScript.Echo "✅ 兩程式已啟動 | Calc PID: " & intCalcID & " | Notepad PID: " & intNotepadID
' ===== 重新連線至通用 WMI 命名空間以訂閱事件 =====
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
' 訂閱「進程刪除事件」:每 1 秒輪詢一次 __InstanceDeletionEvent
Set colProcesses = objWMIService.ExecNotificationQuery _
("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
WScript.Echo "👀 開始監聽進程退出事件... (關閉計算機將觸發關閉記事本)"
' ===== 事件迴圈:等待計算機退出 =====
Do Until i = 999 ' 永真迴圈,靠 Exit Do 跳出
Set objProcess = colProcesses.NextEvent ' 阻塞直到下一個刪除事件
If objProcess.TargetInstance.ProcessID = intCalcID Then
WScript.Echo "🎯 偵測到計算機 (PID " & intCalcID & ") 已退出"
Exit Do
End If
Loop
' ===== 終止記事本 =====
Set colProcesses = objWMIService.ExecQuery _
("Select * From Win32_Process Where ProcessID = " & intNotepadID)
For Each objProcess In colProcesses
objProcess.Terminate()
WScript.Echo "🛑 已終止記事本 (PID " & intNotepadID & ")"
Next
WScript.Echo "✅ 腳本任務完成,正常結束。"
Win32_Process.Create 啟動程式並獲取 PID0 表示成功,非零請查 MSDN 錯誤碼。intCalcID 為 **輸出參數**,接收新建進程的 ProcessID。Null)。__InstanceDeletionEvent 事件監聽__InstanceDeletionEvent,其 TargetInstance 屬性指向被刪除的實例(此處為 Win32_Process)。Within 1 表示輪詢間隔 1 秒(WMI 事件非即時推送,而是輪詢模擬)。ISA 'Win32_Process' 過濾只關心進程刪除事件。ExecNotificationQuery vs ExecQuery| 方法 | 用途 | 行為 |
|---|---|---|
ExecNotificationQuery | 事件訂閱 | 回傳事件集合,NextEvent 會**阻塞**直到下一個事件到達 |
ExecQuery | 靜態查詢 | 立即回傳符合條件的實例集合,可用 For Each 遍歷 |
將 strComputer = "." 改為目標電腦名稱或 IP(需管理員權限、RPC/WMI 通訊埠開放、防火牆允許)。注意:遠端啟動的 GUI 程式在 **Session 0 隔離** 下不可見,僅適合無互動的後台程式。
若需在 Java 中調用,可透過 Runtime.getRuntime().exec("wscript.exe /path/to/script.vbs") 或 ProcessBuilder 執行;更優雅的方式是使用 JNA 或 J-Interop 直接呼叫 WMI COM 介面,避免外部腳本依賴。
cmd.exe 再跑腳本,或檢查 WMI 安全性設定 (wmimgmt.msc)。Within 間隔過大,或 WMI 服務 (Winmgmt) 異常,重啟服務嘗試。Name 或 CommandLine 屬性。WMI 是 Windows 系統管理的瑞士刀。掌握 Win32_Process 生命週期操作(建立、查詢、終止)與 __InstanceDeletionEvent 事件訂閱模式,即可構建強大的自動化編排腳本。雖然 PowerShell 如今更主流,但 VBScript/WMI 組合在舊版 Windows (XP/Server 2003) 仍具相容性優勢,理解其原理有助於跨技術棧的問題排查。