在程式中,我們常常會需要去檢查電腦的某些狀況,例如:目前某個服務的狀態或者磁碟空間剩餘多少等等。此外,要是這些狀態還可以自動回報,那就更好了。 沒錯,WMI 就是這樣一個好物。
Windows管理規範 (Windows Management Instrumentation, WMI) 是 Windows 作業系統的服務元件, 它提供系統管理員方便管理應用程式與資源的工具,同時可以透過程式去存取應用程式、服務和其他電腦元件的管理資訊 (例如,組態設定和屬性值)。 底下列表為WMI的幾個主要功能:
- 1. 在遠端電腦器上啟動一個工作。
- 2. 設定一個在特定日期和時間執行的工作。
- 3. 遠端啟動電腦。
- 4. 獲得本機或遠端電腦的已安裝程序列表。
- 5. 查詢本機或遠端電腦的 Windows 事件日誌。
使用WMI監測管理事件
System.Management 命名空間是 WMI 的核心, 透過 WMI 可以監測管理應用程式、裝置、系統所引發的事件。 下表是 System.Management 底下的幾個主要的物件:
- EventQuery :表示 WMI 事件查詢。
- ObjectQuery :表示傳回執行個體 (Instance) 或類別的管理查詢。
- ManagementObjectSearcher :根據指定的查詢擷取管理物件的集合。
- ManagementObjectCollection :表示經由 WMI 所擷取的各種管理物件集合。
- ManagementObject :表示 WMI 執行個體。
- ManagementBaseObject :包含管理物件的基本項目。
- ConnectionOptions :指定要進行 WMI 連接所需的所有設定。
- ManagementScope :表示管理作業的範圍 (命名空間)。
- ManagementEventWatcher :訂閱暫時性事件告知,該告知以指定的事件查詢為基礎。
- EventWatcherOptions :指定管理事件監看的選項。
如何存取 WMI 資訊
透過 WMI ,可以監測 Windows 裡各式各樣有用的資訊。底下是如何使用 WMI 進行監測的簡單步驟:
- 使用 ManagementScope 定義管理範圍
- 叫用 ManagementScope.Connect 方法,建立連線。
- 使用 ObjectQuery 宣告一個查詢語法。
- 使用 ManagementObjectSearcher 建立查詢物件。
- 叫用 ManagementObjectSearcher.Get 方法,取得 ManagementObjectCollection 型態的查詢結果。
//1.建立一個管理範圍 ManagementScope ManagementScope scope = new ManagementScope(@"\\localhost\root\cimv2"); //2.連上ManagementScope scope.Connect(); //3.使用 ObjectQuery 類別, 建立一個 WQL query (Wmi Query Language) ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem"); //4.建立一個查詢管理物件 ManagementObjectSearcher ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query); //傳入上面的 scope 和 query 當作參數 //5.透過 Get 方法, 取得查詢結果 ManagementObjectCollection searcherResult = searcher.Get(); //列舉結果 foreach (ManagementObject m in searcherResult) { this.listBox1.Items.Add(m.ToString()); Console.WriteLine(m.ToString()); //\\VITO-2011W7\root\cimv2:Win32_OperatingSystem=@ Console.WriteLine("Computer Name : {0}", m["csname"]); Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]); Console.WriteLine("Operating System: {0}", m["Caption"]); Console.WriteLine("Version: {0}", m["Version"]); Console.WriteLine("Manufacturer : {0}", m["Manufacturer"]); //Computer Name : VITO-2011W7 //Windows Directory : C:\Windows //Operating System: Microsoft Windows 7 旗艦版 //Version: 6.1.7601 //Manufacturer : Microsoft Corporation }
如何訂閱 WMI 事件
以同步模式訂閱管理事件
當 WMI 系統的內容被改變的時候,就會引發 WMI 事件。 所以若想主動要得知這些訊息,就可以透過 ManagementEventWatcher 物件來訂閱這些事件。 例如:當某個應用程式被啟動了,或者某個服務被終止了,我們都可以透過訂閱事件,來監控這些改變。 底下是如何訂閱 WMI 事件的簡單步驟:
- Create a new ManagementEventWatcher object.
- Associate an EventQuery object with it.
- Call the WaitForNextEvent method.
- Stop the notifications.
要監聽 WMI 事件,必須透過 ManagementEventWatcher 物件。再叫用 WaitForNextEvent 方法即可。這個方法使用同步作業模式。
// 建立查詢 WqlEventQuery query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 10), "TargetInstance isa \"Win32_Process\""); // 建立一個事件監控物件, 並且訂閱符合查詢語法的事件 ManagementEventWatcher watcher = new ManagementEventWatcher(query); // 等待下一個事件發生,timeout=10s ManagementBaseObject obj = watcher.WaitForNextEvent(); // 顯示事件回應的訊息 Console.WriteLine("Process {0} has been created, path is: {1}", ((ManagementBaseObject)obj["TargetInstance"])["Name"], ((ManagementBaseObject)obj["TargetInstance"])["ExecutablePath"]); // 停止監看 watcher.Stop();
以非同步模式訂閱管理事件
上面例子,透過叫用 WaitForNextEvent 方法,等待事件發生的回應,這個方法是同步作業的,程式會被 lock 住,直到回應發生,或 Timeout 為止。 另外也可以使用非同步方法,訂閱事件,步驟如下:
- Create a new ManagementEventWatcher object.
- Associate an EventQuery object with it.
- Subscribe the EventArrived event.
- Start the notifications.
- Stop the notifications.
使用非同步方式時,必須叫用 ManagementEventWatcher.Start 方法,才會開始監聽事件。 下面這個例子,就是以非同步方式來監測 USB 的插拔事件。 其回應事件的方法,必須接二個參數 Object 和 EventArrivedEventArgs 。
ManagementEventWatcher managementEventWatcher; //啟動偵測 private void btnStartMonitorUSB_Click(object sender, EventArgs e) { managementEventWatcher = new ManagementEventWatcher("Select * From __InstanceOperationEvent WITHIN 10 WHERE TargetInstance ISA \"Win32_DiskDrive\""); managementEventWatcher.Start(); managementEventWatcher.EventArrived += new EventArrivedEventHandler(managementEventWatcher_EventArrived); updateDelegate = new UpdateListBoxDelegate(UpdateListBox); } //偵測事件的回應方法 (object, EventArrivedEventArgs) private void managementEventWatcher_EventArrived(object sender, EventArrivedEventArgs e) { ManagementBaseObject newEvent = e.NewEvent, newEventTarget = (newEvent["TargetInstance"] as ManagementBaseObject); if (newEventTarget["InterfaceType"].ToString() == "USB") { switch (newEvent.ClassPath.ClassName) { case "__InstanceCreationEvent": this.Invoke(updateDelegate, new object[] { Convert.ToString(newEventTarget["Caption"]) + " has been plugged in" }); break; case "__InstanceDeletionEvent": this.Invoke(updateDelegate, new object[] { Convert.ToString(newEventTarget["Caption"]) + " has been plugged out" }); break; } } } //停止偵測 private void btnStopMonitorUSB_Click(object sender, EventArgs e) { managementEventWatcher.Stop(); }
範例演練
如何列舉磁碟機空間
//1.建立查詢語法 string sQuery = "SELECT Size, Name FROM Win32_LogicalDisk where DriveType=3"; //2.依據查詢語法,建立搜尋器 ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(sQuery); //3.透過搜尋器,取得搜尋結果 ManagementObjectCollection oReturnCollection = oSearcher.Get(); //4.列舉結果 foreach (ManagementObject oMObject in oReturnCollection) { Console.WriteLine("Resource Name: {0} , Size : {1}", oMObject["Name"].ToString(),oMObject["Size"].ToString()); }
如何列舉遠端電腦的磁碟機空間
//建立WMI連線 ConnectionOptions oConn = new ConnectionOptions(); oConn.Username = "Username"; oConn.Password = "Password"; oConn.EnablePrivileges = true; //建立連接到 WMI 的範圍物件 ManagementScope oMScope = new ManagementScope(@"\\192.168.0.168\root\cimv2", oConn); oMScope.Connect(); if (oMScope.IsConnected) { //建立查詢語法 ObjectQuery oQuery = new ObjectQuery("SELECT Size, Name FROM Win32_LogicalDisk WHERE DriveType=3"); //依據查詢語法,建立搜尋器 ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMScope, oQuery); //透過搜尋器,取得搜尋結果 ManagementObjectCollection oReturnCollection = oSearcher.Get(); //列舉結果 Console.WriteLine("Server : {0}", oMScope.Path.Server); foreach (ManagementObject oMObject in oReturnCollection) { Console.WriteLine("Disk {0} {1} GB ", oMObject["Name"].ToString(), Math.Round((double)System.UInt64.Parse(oMObject["Size"].ToString()) / 1024 / 1024 / 1024,2)); } } //Server : 192.168.0.168 //Disk C: 183.07 GB //Disk D: 49.81 GB
如何列舉網路介面卡
ManagementObjectSearcher oSearcher = new ManagementObjectSearcher( "SELECT * FROM Win32_NetworkAdapterConfiguration"); ManagementObjectCollection oReturnCollection = oSearcher.Get(); foreach (ManagementObject oMObject in oReturnCollection) { Console.WriteLine("Description : " + oMObject["Description"]); Console.WriteLine("MacAddress : " + oMObject["MacAddress"]); }
如何列舉已經停止的服務
ManagementObjectSearcher oSearcher = new ManagementObjectSearcher( "SELECT * FROM Win32_Service WHERE Started = FALSE"); ManagementObjectCollection oReturnCollection = oSearcher.Get(); foreach (ManagementObject oMObject in oReturnCollection) { Console.WriteLine("Service : " + oMObject["Caption"]); }
如何監看一個Win32程式被啟動執行
string sQuery = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'"; //this query string means send notification of the creation of Win32_Process instances, with a 2-second polling interval." //訂閱一個事件監控 ManagementEventWatcher oWatcher = new ManagementEventWatcher(sQuery); oWatcher.Options.Timeout = new TimeSpan(0, 0, 60); //設定Timeout=60s //開始監看啟動事件,並等待事件發生 ManagementBaseObject oEvent = oWatcher.WaitForNextEvent(); ManagementBaseObject oMBObject = (ManagementBaseObject)oEvent["TargetInstance"]; Console.WriteLine("程式 {0} 被啟動,程式來源路徑:{1}", oMBObject["Name"], oMBObject["ExecutablePath"]); oWatcher.Stop(); //Output: //程式 Notepad2.exe 被啟動,執行路徑:C:\Program Files\Notepad2\Notepad2.exe //程式 EWinnerStart.exe 被啟動,程式來源路徑:C:\TWEWinner\EWinnerStart.exe
如何監看一個Win32服務被暫停
EventQuery DemoQuery = new EventQuery(); string sQueryString = "SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Service' AND TargetInstance.State = 'Paused'"; //訂閱一個事件監控 ManagementEventWatcher oWatcher = new ManagementEventWatcher(sQueryString); oWatcher.Options.Timeout = new TimeSpan(0, 0, 60); //開始監看啟動事件,並等待事件發生 ManagementBaseObject oEvent = oWatcher.WaitForNextEvent(); ManagementBaseObject oMBObject = (ManagementBaseObject)oEvent["TargetInstance"]; Console.WriteLine("服務 {0} ( {1} ) 被暫停。", oMBObject["DisplayName"], oMBObject["Description"]); oWatcher.Stop(); //Output: //服務 TEST_WindowsService ( TEST WindowsService ) 被暫停。
沒有留言:
張貼留言