最近在网上搜索Python和WMI相关资料时,发现大部分文章都千篇一概,而且基本上只说了很基础的使用,并未深刻说明如何使用WMI。本文打算更进一步,让咱们使用Python玩转WMI。html
具体请看微软官网对WMI的介绍。这里简单说明下,WMI的全称是Windows Management Instrumentation,即Windows管理规范。它是Windows操做系统上管理数据和操做的基础设施。咱们可使用WMI脚本或者应用自动化管理任务等。node
从Using WMI能够知道WMI支持以下语言:web
Application language | Topic |
---|---|
Scripts written in Microsoft ActiveX script hosting, including Visual Basic Scripting Edition (VBScript) and Perl安全 |
Start with Creating a WMI Script.app For script code examples, see WMI Tasks for Scripts and Applications and the TechNet ScriptCenter Script Repository.ide |
Windows PowerShell函数 |
Getting Started with Windows PowerShell测试 WMI PowerShell Cmdlets, such as Get-WmiObject.网站 |
Visual Basic applications |
|
Active Server Pages |
Start with Creating Active Server Pages for WMI. |
C++ applications |
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的用法来使用。那么接下来,咱们来说讲如何使用。
如下是一个遍历全部进程,全部服务的示例:
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的速度快了不少。而第二个问题,先卖个关子,后文会有介绍。
win32com能模仿VB的行为,想了解如何使用win32com来操做WMI,最直接的方式是了解如何使用VB来操做WMI。在微软的官网上提供了不少现成的例子:WMI Tasks: Processes, WMI Tasks: Services。
其中一个例子关于进程是这样的:
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就能够这么写(例子中打印的属性为了简便,就不像上面那么多啦):
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,那么就能够写成下面这样:
from win32com.client import GetObject wmi = GetObject('winmgmts:/root/cimv2') processes = wmi.InstancesOf('Win32_Process') for process in processes: print(process.ProcessID, process.Name)
有读者可能会问,咱们怎么知道本身想要了解的内容在哪一个名称空间,咱们应该获取哪一个实例,又该获取实例中的哪些属性呢?
使用下面的脚本能够得到当前计算机上的名称空间:
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')
得到的内容大概是这样的(...表示省略了一些输出内容):
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 事件日志,如读取、备份、清除、复制、删除、监视、重命名、压缩、解压缩和更改事件日志设置。
了解了名称空间的获取,每一个名称空间的主要功能,那么如何获取特定名称空间下全部的类,以及它们的属性和值呢?
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。
了解了这么多内容,我们就拿个对象练练手。如今有这么个需求,咱们想要获取IIS的版本号以及它全部的站点名称,怎么办?
在微软官网上比较容易的找到IIS WMI的说明,根据直觉,咱们要查询的信息可能会是在类名中包含setting的类中,那么看起来比较有可能的有IIsSetting (WMI), IIsWebServerSetting (WMI), IIsWebInfoSetting (WMI)。
对这些类都分别看一看,发现IIsSetting中提供了一个例子:
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代码来得到版本和站点名称:
# 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)
使用Python操做WMI,最大的难点并不在于如何编写Python语句,而在于若是获知想要查询的内容在哪一个名称空间以及对应的类和属性。而这些内容则须要查阅官方文档以及使用wbemtest进行探索。得到了这些必要的信息后,再去编写Python代码就是一件很是轻松的事情。
转载请注明出处: http://www.cnblogs.com/dreamlofter/p/5846966.html