使用Python玩轉WMI進行Win32api/com進行Windows程式設計開發

天府雲創發表於2017-12-20

最近在網上搜尋Python和WMI相關資料時,發現大部分文章都千篇一律,並且基本上只說了很基礎的使用,並未深入說明如何使用WMI。本文打算更進一步,讓我們使用Python玩轉WMI。

1 什麼是WMI

具體請看微軟官網對WMI的介紹。這裡簡單說明下,WMI的全稱是Windows Management Instrumentation,即Windows管理規範。它是Windows作業系統上管理資料和操作的基礎設施。我們可以使用WMI指令碼或者應用自動化管理任務等。

Using WMI可以知道WMI支援如下語言:

Application language Topic
Scripts written in Microsoft ActiveX script hosting, including Visual Basic Scripting Edition (VBScript) and Perl Scripting API for WMI.

Start with Creating a WMI Script.

For script code examples, see WMI Tasks for Scripts and Applications and the TechNet ScriptCenterScript Repository.

Windows PowerShell Getting Started with Windows PowerShell

WMI PowerShell Cmdlets, such as Get-WmiObject.

Visual Basic applications Scripting API for WMI.
Active Server Pages Scripting API for WMI.

Start with Creating Active Server Pages for WMI.

C++ applications COM API for WMI.

Start with Creating a WMI Application Using C++ and WMI C++ Application Examples (contains examples).

.NET Framework applications written in C#, Visual Basic .NET, or J# Classes in the Microsoft.Management.Infrastructure namespace. (The System.Management namespace is no longer supported). For more information, see WMI .NET Overview.

很遺憾,WMI並不原生支援Python。不過沒有關係,它支援VB,而Python中的兩個第三方庫wmi和win32com,均能以類似VB的用法來使用。那麼接下來,我們來講講如何使用。

 

2 使用WMI

2.1 使用wmi庫操作WMI

以下是一個遍歷所有程式,所有服務的示例:

可以看到,使用起來非常簡單。但是有兩個問題:一是wmi庫實在是太慢了,能不能快點?二是如何知道例子中process和service有哪些屬性(比如ProcessId等)?由於wmi庫是動態生成底層執行語句,用dir(process)這種方式是獲取不到ProcessId這種屬性的。

針對第一個問題,我們可以使用win32com這個庫來解決,它相較於wmi的速度快了很多。而第二個問題,先賣個關子,後文會有介紹。

2.2 使用win32com庫操作WMI

win32com能模仿VB的行為,想了解如何使用win32com來操作WMI,最直接的方式是瞭解如何使用VB來操作WMI。在微軟的官網上提供了很多現成的例子:WMI Tasks: Processes, WMI Tasks: Services

其中一個例子關於程式是這樣的:

它做了這樣一件事:首先通過GetObject連線到Win32_Process所在的名稱空間,然後執行WQL語句(類似SQL的查詢語句)查到所有的程式,再把每一個程式的相關資訊列印出來。WQL的具體用法請見官網,這裡不詳細介紹。

那麼用win32com就可以這麼寫(例子中列印的屬性為了簡便,就不像上面那麼多啦):

看上去,VB和win32com的用法非常接近!那麼當我們想要使用win32com對WMI進行操作時,就可以參考微軟官網上VB的例子,然後比葫蘆畫瓢寫出Python版的程式碼。

上例中,我們使用了查詢函式ExecQuery來查詢符合條件的內容,不過如果我們僅僅是想要獲得所有的資料,而沒有特定的限定條件,就可以使用更簡單的方式——InstancesOf,那麼就可以寫成下面這樣:

有讀者可能會問,我們怎麼知道自己想要了解的內容在哪個名稱空間,我們應該獲取哪個例項,又該獲取例項中的哪些屬性呢?

 

3 WMI的名稱空間

使用下面的指令碼可以獲得當前計算機上的名稱空間:

獲得的內容大概是這樣的(…表示省略了一些輸出內容):

通用的名稱空間的簡單介紹:

root 是名稱空間層次結構的最高階。

CIMV2 名稱空間存放著和系統管理域相關(比如計算機以及它們的作業系統)的物件。

DEFAULT 名稱空間存放著預設被建立而不指定名稱空間的類。

directory 目錄服務的通用名稱空間,WMI 建立了名為LDAP的子名稱空間。

SECURITY 用來支援Windows 9x計算機上的WMI的名稱空間。

WMI 使用Windows Driver Model providers的類所在的名稱空間。這是為了避免和CIMV2名稱空間中類名衝突。

其中,root/CIMV2可以說是最為基本和常用的名稱空間了。它的作用主要是提供關於計算機、磁碟、外圍裝置、檔案、資料夾、檔案系統、網路元件、作業系統、印表機、程式、安全性、服務、共享、SAM 使用者及組,以及更多資源的資訊;管理 Windows 事件日誌,如讀取、備份、清除、複製、刪除、監視、重新命名、壓縮、解壓縮和更改事件日誌設定。

 

4 類/例項和屬性/值

瞭解了名稱空間的獲取,每個名稱空間的主要功能,那麼如何獲取特定名稱空間下所有的類,以及它們的屬性和值呢?

Windows提供了一個WMI測試器,使得查詢這些內容變得尤為方便。按下”win+R”,輸入wbemtest,從而開啟WMI測試器。開啟後的介面如下:1

點選“連線”,輸入想要查詢的名稱空間,再點選“連線”即可連到特定名稱空間。

然後點選“列舉類”,在彈出的介面中選擇“遞迴”,然後點選“確定”,就會得到這個名稱空間下所有的類:

2

3

從上圖可以看到,之前舉例中提到的Win32_Process位列其中,我們不妨雙擊它,看看關於它的具體內容:

4

我們可以很容易地找到Win32_Process的屬性和方法。除了使用wbemtest檢視特定名稱空間下的所有類,我們還可以在WMI/MI/OMI Providers中找到所有的類。我們依次在這個頁面中點選CIMWin32, Win32, Power Management EventsWin32 ProviderOperating System ClassesWin32_Process 最終找到Win32_Process的屬性和方法:

5

對比上面兩張圖,裡面的方法都是一致的。

 

那麼如何獲得例項和它的值呢?我們繼續在剛剛開啟的wbemtest介面中點選右邊的“例項”按鈕,就會顯示所有的程式例項。雙擊某個具體的例項,然後在彈出的介面中點選右側的“顯示MOF”按鈕就會顯示這個例項中具體屬性的值。6

7

通過上述定位名稱空間、類、屬性的方法,我們就可以愉快地使用Python來玩耍WMI。

 

5 實戰,以IIS為例

瞭解了這麼多內容,我們們就拿個物件練練手。現在有這麼個需求,我們想要獲取IIS的版本號以及它所有的站點名稱,怎麼辦?

在微軟官網上比較容易的找到IIS WMI的說明,根據直覺,我們要查詢的資訊可能會是在類名中包含setting的類中,那麼看起來比較有可能的有IIsSetting (WMI)IIsWebServerSetting (WMI)IIsWebInfoSetting (WMI)

對這些類都分別看一看,發現IIsSetting中提供了一個例子:

從這個例子中,我們可以知道iis的名稱空間是‘/root/microsoftiisv2’,然後我們可以直接在這個空間中查詢各種相關類,比如說“IIsWebServerSetting”。

結合wbemtest和IIS管理器,我們可以看出IIsWebServerSetting例項中的ServerComment屬性值和網站名稱一致:8

而版本資訊則在類名包含setting的類中無法找到,那再去類名包含info的類中瞧一瞧。果然,在IIsWebInfo (WMI)中找到了MajorIIsVersionNumber和MinorIIsVersionNumber屬性,分別表示大版本和小版本。那麼我們就能比較輕鬆地寫出下面的Python程式碼來獲得版本和站點名稱:

6 總結

使用Python操作WMI,最大的難點並不在於如何編寫Python語句,而在於如果獲知想要查詢的內容在哪個名稱空間以及對應的類和屬性。而這些內容則需要查閱官方文件以及使用wbemtest進行探索。獲得了這些必要的資訊後,再去編寫Python程式碼就是一件非常輕鬆的事情。

相關文章