最近在网上搜索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 ScriptCenter Script 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 什么是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 ScriptCenter Script 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的名称空间
使用下面的脚本可以获得当前计算机上的名称空间: