使用Python玩轉WMI進行Win32api/com進行Windows程式設計開發
最近在網上搜尋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
以下是一個遍歷所有程式,所有服務的示例:
1 2 3 4 5 6 7 8 9 | import wmi c = wmi.WMI () # 遍歷程式 for process in c.Win32_Process (): print process.ProcessId, process.Name # 遍歷服務 for service in c.Win32_Service (): print service.ProcessId, service.Name |
可以看到,使用起來非常簡單。但是有兩個問題:一是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。
其中一個例子關於程式是這樣的:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
strComputer
=
"."
Set
objWMIService
=
GetObject("winmgmts:"
&
"{impersonationLevel=impersonate}!\\"
&
strComputer
&
"\root\cimv2")
Set
colProcesses
=
objWMIService.ExecQuery("Select
* from Win32_Process")
For
Each
objProcess
in
colProcesses
Wscript.Echo
"Process: "
&
objProcess.Name
sngProcessTime
=
(CSng(objProcess.KernelModeTime)
+
CSng(objProcess.UserModeTime))
/
10000000
Wscript.Echo
"Processor Time: "
&
sngProcessTime
Wscript.Echo
"Process ID: "
&
objProcess.ProcessID
Wscript.Echo
"Working Set Size: "
&
objProcess.WorkingSetSize
Wscript.Echo
"Page File Size: "
&
objProcess.PageFileUsage
Wscript.Echo
"Page Faults: "
&
objProcess.PageFaults
Next
|
它做了這樣一件事:首先通過GetObject連線到Win32_Process所在的名稱空間,然後執行WQL語句(類似SQL的查詢語句)查到所有的程式,再把每一個程式的相關資訊列印出來。WQL的具體用法請見官網,這裡不詳細介紹。
那麼用win32com就可以這麼寫(例子中列印的屬性為了簡便,就不像上面那麼多啦):
1 2 3 4 5 6 7 | from win32com.client import GetObject wmi = GetObject('winmgmts:/root/cimv2') # wmi = GetObject('winmgmts:') #更簡單的寫法 processes = wmi.ExecQuery('Select * from Win32_Process') for process in processes: print(process.ProcessID, process.Name) |
看上去,VB和win32com的用法非常接近!那麼當我們想要使用win32com對WMI進行操作時,就可以參考微軟官網上VB的例子,然後比葫蘆畫瓢寫出Python版的程式碼。
上例中,我們使用了查詢函式ExecQuery來查詢符合條件的內容,不過如果我們僅僅是想要獲得所有的資料,而沒有特定的限定條件,就可以使用更簡單的方式——InstancesOf,那麼就可以寫成下面這樣:
1
2
3
4
5
6
|
from
win32com.client
import
GetObject
wmi
=
GetObject('winmgmts:/root/cimv2')
processes
=
wmi.InstancesOf('Win32_Process')
for
process
in
processes:
print(process.ProcessID,
process.Name)
|
有讀者可能會問,我們怎麼知道自己想要了解的內容在哪個名稱空間,我們應該獲取哪個例項,又該獲取例項中的哪些屬性呢?
3 WMI的名稱空間
使用下面的指令碼可以獲得當前計算機上的名稱空間:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from win32com.client import GetObject import pywintypes def enum_namespace(name): try: wmi = GetObject('winmgmts:/' + name) namespaces = wmi.InstancesOf('__Namespace') for namespace in namespaces: enum_namespace('{name}/{subname}'.format(name=name, subname=namespace.Name)) except pywintypes.com_error: print(name, 'limit of authority') else: print(name) enum_namespace('root') |
獲得的內容大概是這樣的(…表示省略了一些輸出內容):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
root
root/subscription
root/subscription/ms_409
root/DEFAULT
root/DEFAULT/ms_409
root/CIMV2
root/CIMV2/Security
...
root/Cli
root/Cli/MS_409
root/SECURITY
...
root/WMI
root/WMI/ms_409
root/directory
root/directory/LDAP
root/directory/LDAP/ms_409
root/Interop
root/Interop/ms_409
root/ServiceModel
root/SecurityCenter
root/MSAPPS12
root/Microsoft
...
|
通用的名稱空間的簡單介紹:
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測試器。開啟後的介面如下:
點選“連線”,輸入想要查詢的名稱空間,再點選“連線”即可連到特定名稱空間。
然後點選“列舉類”,在彈出的介面中選擇“遞迴”,然後點選“確定”,就會得到這個名稱空間下所有的類:
從上圖可以看到,之前舉例中提到的Win32_Process位列其中,我們不妨雙擊它,看看關於它的具體內容:
我們可以很容易地找到Win32_Process的屬性和方法。除了使用wbemtest檢視特定名稱空間下的所有類,我們還可以在WMI/MI/OMI Providers中找到所有的類。我們依次在這個頁面中點選CIMWin32, Win32, Power Management Events,Win32 Provider,Operating System Classes,Win32_Process 最終找到Win32_Process的屬性和方法:
對比上面兩張圖,裡面的方法都是一致的。
那麼如何獲得例項和它的值呢?我們繼續在剛剛開啟的wbemtest介面中點選右邊的“例項”按鈕,就會顯示所有的程式例項。雙擊某個具體的例項,然後在彈出的介面中點選右側的“顯示MOF”按鈕就會顯示這個例項中具體屬性的值。
通過上述定位名稱空間、類、屬性的方法,我們就可以愉快地使用Python來玩耍WMI。
5 實戰,以IIS為例
瞭解了這麼多內容,我們們就拿個物件練練手。現在有這麼個需求,我們想要獲取IIS的版本號以及它所有的站點名稱,怎麼辦?
在微軟官網上比較容易的找到IIS WMI的說明,根據直覺,我們要查詢的資訊可能會是在類名中包含setting的類中,那麼看起來比較有可能的有IIsSetting (WMI), IIsWebServerSetting (WMI), IIsWebInfoSetting (WMI)。
對這些類都分別看一看,發現IIsSetting中提供了一個例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | o = getobj("winmgmts:/root/microsoftiisv2") nodes = o.ExecQuery("select * from IIsWebServerSetting where name='w3svc/1'") e = new Enumerator(nodes) for(; ! e.atEnd(); e.moveNext()) { WScript.Echo(e.item().Name + " (" + e.item().Path_.Class + ")") } // The output should be: // w3svc/1 (IIsWebServerSetting) nodes = o.ExecQuery("select * from IIsSetting where name='w3svc/1'") e = new Enumerator(nodes) for(; ! e.atEnd(); e.moveNext()) { WScript.Echo(e.item().Name + " (" + e.item().Path_.Class + ")") } // The output should be: // w3svc/1 (IIsIPSecuritySetting) // w3svc/1 (IIsWebServerSetting) |
從這個例子中,我們可以知道iis的名稱空間是‘/root/microsoftiisv2’,然後我們可以直接在這個空間中查詢各種相關類,比如說“IIsWebServerSetting”。
結合wbemtest和IIS管理器,我們可以看出IIsWebServerSetting例項中的ServerComment屬性值和網站名稱一致:
而版本資訊則在類名包含setting的類中無法找到,那再去類名包含info的類中瞧一瞧。果然,在IIsWebInfo (WMI)中找到了MajorIIsVersionNumber和MinorIIsVersionNumber屬性,分別表示大版本和小版本。那麼我們就能比較輕鬆地寫出下面的Python程式碼來獲得版本和站點名稱:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# coding:utf-8
from
win32com.client
import
GetObject
wmi
=
GetObject('winmgmts:/root/microsoftiisv2')
# 版本
webinfo
=
wmi.execquery('select
* from IIsWebInfo ')[0]
version
=
'{major}.{min}'.format(major=webinfo.MajorIIsVersionNumber,
min=webinfo.MinorIIsVersionNumber)
print(version)
# 站點名稱
websettings
=
wmi.execquery('select
* from IIsWebServerSetting ')
websites
=
' | '.join(setting.ServerComment
for
setting
in
websettings)
print(websites)
|
6 總結
使用Python操作WMI,最大的難點並不在於如何編寫Python語句,而在於如果獲知想要查詢的內容在哪個名稱空間以及對應的類和屬性。而這些內容則需要查閱官方文件以及使用wbemtest進行探索。獲得了這些必要的資訊後,再去編寫Python程式碼就是一件非常輕鬆的事情。
相關文章
- 使用Python進行併發程式設計Python程式設計
- 如何在Windows上使用Python進行開發WindowsPython
- 使用 VS Code 進行 Python 程式設計Python程式設計
- 怎樣使用AJAX進行應用程式開發(轉)
- 使用Cassandra進行.Net程式設計NY程式設計
- 使用Lccwin32進行MySQL開發。 (轉)Win32MySql
- python教程:使用 async 和 await 協程進行併發程式設計PythonAI程式設計
- [轉載]使用BackgroundWorker元件進行非同步操作程式設計元件非同步程式設計
- 使用應用程式(Java/Python)訪問MaxCompute Lightning進行資料開發JavaPython
- 使用Devstack進行開發dev
- 使用容器Docker進行開發Docker
- 使用 Devstack 進行開發dev
- 在 Oracle JDeveloper 中進行 Ajax 程式設計(轉)OracleDeveloper程式設計
- 使用Java 7.0的 Fork/Join框架進行併發程式設計Java框架程式設計
- Linux 串列埠程式設計 使用termios與API進行串列埠程式開發Linux串列埠程式設計iOSAPI
- 快速使用 vscode 進行 Java 程式設計VSCodeJava程式設計
- 使用 Go 進行 iOS 和 Android 程式設計GoiOSAndroid程式設計
- 如何在 Linux/Windows/MacOS 上使用 .NET 進行開發LinuxWindowsMac
- 用Delphi進行OpenGL程式設計學習心得 (轉)程式設計
- 使用eclipse 進行 Cesium 開發Eclipse
- 使用 .NET 進行遊戲開發遊戲開發
- python的tkinter程式設計(四)GUI介面裡面使用類進行開發,也就是自定義元件Python程式設計GUI元件
- 5天玩轉C#並行和多執行緒程式設計 —— 第四天 Task進階C#並行執行緒程式設計
- 使用Java 9 Flow進行響應式程式設計Java程式設計
- 使用 JavaScript 進行函數語言程式設計 (一)JavaScript函數程式設計
- 用C語言技術進行CGI程式設計(轉)C語言程式設計
- 程式設計使用WMI 控制連線屬性 (轉)程式設計
- 使用shouldComponentUpdate進行效能優化優化
- Python語法進階(1)- 程式與執行緒程式設計Python執行緒程式設計
- 使用API進行區塊鏈開發API區塊鏈
- 使用 go kit進行微服務開發Go微服務
- Vue使用SCSS進行模組化開發VueCSS
- Python進行開發的兩種方式Python
- 使用Visual Studio Code進行MicroPython程式設計Python程式設計
- 使用python進行web抓取PythonWeb
- SQL Server中使用DTS設計器進行資料轉移SQLServer
- 【CSS模組化之路3】 使用?styled-components來進行react開發CSSReact
- 用C++進行Windows驅動開發的一些進展C++Windows