比较类与托管资源
大部分 WMI 属性和方法是合理命名的。例如,如图 8 所示,如果您将由 Win32_Service 类定义的属性和方法与服务的属性对话框相比,就不难推断出 Win32_Service.Name、Win32_Service.DisplayName 或 Win32_Service.Descritpion 可能会包含什么。
图 8:服务属性对话框与 Win32_Service 类属性及方法
那么我们为什么要关心所有这些内容?因为类决定了您能够(或不能)用 WMI做什么。如果有一个服务的类,您就可以管理服务;如果没有,您就不能这样做。属性和方法是很重要的,这是因为 WMI 的版本在操作系统间是有区别的。Windows XP 中的 Win32_ComputerSystem 类有很多新的属性和方法,而它们在 Windows 2000 中的 Win32_ComputerSystem 类中是没有的。您必须知道 WMI 的详细信息,因为不同于 ADSI,为了让工作顺利进行,WMI 属性和方法必须可用于目标计算机。
如何确定一台远程 Windows 计算机是否支持某个属性或方法?请检查类定义。
检索类定义
与 WMI 中所有东西一样,有无数方法可以检索托管资源的类定义。好吧,也许我们有点夸张了,但是也足以说,有许多为每个用户界面首选项提供解决方案的方法。如果您想要检索文本文件,只需分割 MOF 文件。如果您更喜欢命令行,就使用 WMI 命令行工具 wmic.exe(仅限 Windows XP)。如果您乐于将时间花在图形化工具上,就使用 WMI 测试器 (wbemtest.exe) 或 CIM Studio。或者如果您喜欢我们,就使用 WMI 脚本库。
使用 WMI 脚本库,您可以通过三种不同的方法检索托管资源类定义。
1. | 您可以使用 SWbemObjectQualifiers_、Properties_ 和 Methods_ 属性检索类信息。 |
2. | 您可以使用 SWbemObjectGetObjectText_ 方法来检索以 MOF 语法格式化的类定义。 |
3. | 您可以使用 SWbemObjectExGetText_ 方法来检索以 XML 格式化的类定义(仅限 Windows XP 和 Windows Server 2003)。 |
让我们简要地看看每个脚本方案,就此结束今天的内容。
使用 SWbemObject Properties_、Methods_ 和 Qualifiers_
清单 9、10 和 11 演示了如何使用 WMI 脚本库的 SWbemObject 的 Properties_、Methods_ 和 Qualifiers_ 属性来检索关于 Win32_Service 类的信息。我们将研究清单 9,然后指出清单 10 和清单 11 中的不同之处,因为三个脚本使用了相同的基本方法。
清单 9 从初始化三个变量开始,它们是:strComputer、strNameSpace 和 strClass 分配给 strComputer 的值是启用了 WMI 的目标计算机。分配给 strNameSpace 的值是要连接到的命名空间。分配给 strClass 的值是在目标命名空间中的类的名称,此命名空间的属性将被检索和显示。将这三个值分开到多个变量中会使其他计算机、命名空间和类对脚本的重新使用变得简单。事实上,您可以用 Windows 脚本宿主 (WSH) 参数集合轻松地将清单 9 转换到命令行脚本。
接下来,这个脚本使用 VBScript 的 GetObject 函数连接到目标计算机上的 WMI 服务。注意传递到 GetObject 的连接字符串有什么不同?除了指定目标命名空间之外,类名也要进行指定,这对 GetObject 和 WMI 脚本库返回的内容有深远影响。如在我们前面的所有脚本,GetObject 返回一个对表示目标类的 SWbemObject 的引用,而不是返回对 SWbemServices 对象的引用。为什么?答案在于对象路径。虽然我们在第三部分中会详细讨论对象路径,但是这里我们还是给您一个概要的解释来帮助您理解清单 9 到清单 11(以及补充清单 C)中到底在进行些什么。
每个 WMI 类和每个 WMI 托管资源实例都有一个对象路径。将对象路径理解为一个文件的完全限定路径的 WMI 版本。每个文件都有一个完全限定路径,它由设备名称,后跟 0 或更多目录名称,再加上文件名组成。同样,每个类和托管资源也都有一个对象路径,它由启用了 WMI 的计算机名称,后跟 CIM 命名空间,后跟托管资源类名,后跟类的 key 属性以及 key 属性的值组成,如下所示。(注意,方括号只为了分清一个对象路径的四个许可部分,它们并不是对象路径的一部分。)
[//ComputerName][/Namespace][:ClassName][.KeyProperty='Value']
当您在传递到 GetObject 的连接字符串中使用全部或部分的对象路径时(顺便说一下,这就是我们一直在做的),您使用的对象路径确定了由 GetObject 和 WMI 脚本库返回的引用类型。例如,如果只包含了对象路径的计算机名称部分,您就会获得一个连接到默认命名空间的 SWbemServices 对象引用。如果包含了计算机名称和/或命名空间,您也会获得对 SWbemServices 对象的引用。如果包含了计算机名称、命名空间和类名,您将会获得对表示这个类的 SWbemObject 的引用。如果包含了所有四个部分,您将会获得表示由类、密钥和值识别的托管资源实例的 SWbemObject。再次提醒,我们会在本系列的第三部分更详细地讨论对象路径。现在,了解清单 9 中的 objClass 是对表示 Win32_Service 类的 SWbemObject 的引用。
脚本的剩余部分相当简明易懂。在回显一个简单的、标识其属性将被显示的类名的标题后,脚本使用从 GetObject 返回的 SWbemObject 引用 (objClass) 来访问 SWbemObjectProperties_ 属性 (objClass.Properties_)。SWbemObjectProperties_ 属性引用了一个 SWbemPropertySet,它是对这个类的属性的集合。SWbemPropertySet 集合中的每个属性都是一个 SWbemProperty (objClassProperty) 对象,我们用其读取并回显每个属性的名称。
概括地说,For Each 循环枚举了类的 SWbemPropertySet 集合(通过 SWbemObjectProperties_ 属性)并回显SWbemPropertySet 集合中每个 SWbemProperty 的 Name 属性。
清单 9:使用 SWbemObject Properties_ 检索 Win32_Service 属性
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Set objClass = GetObject("winmgmts://" & strComputer & _ "/" & strNameSpace & ":" & strClass) WScript.Echo strClass & " Class Properties" WScript.Echo "------------------------------" For Each objClassProperty In objClass.Properties_ WScript.Echo objClassProperty.Name Next
图 9 显示由 Win32_Service 类定义(或继承)的 25 个属性的名称。
图 9:GetProperties.vbs 输出
除了一个显著的例外,清单 10 与清单 9 是相同的。For Each 循环枚举类的 SWbemMethodSet 集合(通过 SWbemObjectMethods_ 属性),并回显 SWbemMethodSet 集合中每个 SWbemMethod (objClassMethod) 的 Name 属性。
清单 10:使用 SWbemObject Methods_ 检索 Win32_Service 方法
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Set objClass = GetObject("winmgmts://" & strComputer & _ "/" & strNameSpace & ":" & strClass) WScript.Echo strClass & " Class Methods" WScript.Echo "---------------------------" For Each objClassMethod In objClass.Methods_ WScript.Echo objClassMethod.Name Next
图 10 显示由 Win32_Service 类定义(或继承)的 10 个方法的名称。
图 10:GetMethods.vbs 输出
除了三点例外,清单 11 与清单 9 和 清单10 相同。
1. | For Each 循环枚举类的 SWbemQualifierSet 集合(通过 SWbemObjectQualifiers_ 属性),并回显 SWbemQualifierSet 集合中每个 SWbemQualifier (objClassQualifier) 的 Name 属性。 |
2. | 因为类限定符是类定义的一部分而且限定符有值,清单 11 也检索并回显 SWbemQualifierSet 集合中每个 SWbemQualifier (objClassQualifier) 的 Value 属性。 |
3. | 因为一个限定符可以有多个存储在数组中的值,清单 11 必须在读取限定符的值前说明此点。如果不这么做,如果脚本试图将一个基于数组的限定符作为标量变量来读取,将会导致运行时错误。Win32_NTLogEvent 类的 Privileges 限定符是一个基于数组的限定符实例。 |
清单 11:使用 SWbemObject Qualifiers_ 检索 Win32_Service 类限定符
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Set objClass = GetObject("winmgmts://" & strComputer & _ "/" & strNameSpace & ":" & strClass) WScript.Echo strClass & " Class Qualifiers" WScript.Echo "------------------------------" For Each objClassQualifier In objClass.Qualifiers_ If VarType(objClassQualifier.Value) = (vbVariant + vbArray) Then strQualifier = objClassQualifier.Name & " = " & _ Join(objClassQualifier.Value, ",") Else strQualifier = objClassQualifier.Name & " = " & _ objClassQualifier.Value End If WScript.Echo strQualifier strQualifier = "" Next
图 11 显示由 Win32_Service 类定义(或继承)的 5 个类限定符的名称和值。
图 11:GetClassQualifiers.vbs 输出
如您可能已经注意到的,清单 9 和清单 10 无法显示属性和方法限定符。说实话,这是故意让脚本保持在一个容易理解的大小。好消息是,在本专栏的结尾我们已经加入了完整的类限定符、属性、属性限定符、方法和方法限定符脚本(见补充清单 C)。欢迎参阅。
万一这不是很明显,您可以把清单 9、10、11 与清单 6(GetAllNamespaces.vbs 脚本)和清单 8(GetClasses.vbs 脚本)组合在一起来检索在 CIM 中定义的每个类的属性、方法和限定符。在使用所产生的带有 findstr.exe 命令的脚本,您会得到一个解决方案来搜索在 CIM 中定义的任何类、属性、方法或限定符。
使用 SWbemObject GetObjectText_
在前面我们说过,您可以直接从 MOF 文件(包含类的定义)中检索管理资源类定义。例如,如果您想要查找 Win32_Service 类,可以查看 %SystemRoot%/system32/wbem/cimwin32.mof 文件。但是,直接使用 MOF 文件是有代价的。您必须检查托管资源的类层次结构中的每个类,以获得完整的托管资源蓝图。
比如说,您想要查找 Win32_Service。您就不得不检查 Win32_Service 类层次结构中所有的 5 个类,以获得完整的蓝图,如图 1 所示,。如果您使用 WMI 测试器 (wbemtest.exe) 的 Show MOF 按钮(见图 7),也是同样。获得类的 MOF 表示形式的较简单方法是使用 WMI 脚本库的 SWbemObjectGetObjectText_ 方法,如清单 12 中演示的。
与清单 9 到 11 不同,清单 12 使用 SWbemServicesGet 方法来检索类,而不使用 GetObject。必须使用 SWbemServicesGet 方法,这样才能启用 wbemFlagUseAmendedQuailifiers 标志。启用 wbemFlagUseAmendedQuailifiers 标志,告诉 WMI 返回整个托管资源蓝图(类定义)而不仅仅是本地的定义。
使用 wbemFlagUseAmendedQualifiers 标记还有第二个好处。您也取回了类描述,以及对每个类的属性、方法和限定符的描述。类、属性、方法和限定符描述通常在一个本地化目的、单独的 MOF 文件中定义。例如,Win32_Service 类的中性语言部分是在 cimwin32.mof 中定义的。Win32_Service 类的特定语言部分,包括描述信息,是在 cimwin32.mfl 中定义的。特定语言的(或本地化的) MOF 文件通常带有一个 .mfl(而非 .mof)扩展名。
SWbemServicesGet 方法返回对表示目标类的 SWbemObject (objClass) 的引用,它用于调用 SWbemObjectGetObjectText_ 方法。GetObjectText_ 方法返回该类的 MOF 表示形式。如果我们使用了 GetObjectText_ 而没有启用 wbemFlagUseAmendedQuailifiers 标记,这个方法将只返回那些由 Win32_Service 定义的属性、方法和限定符,继承的属性和方法会被省略。
图 12:使用 SWbemObject GetObjectText_ 来检索 Win32_Service 类的 MOF 表现形式
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Const wbemFlagUseAmendedQualifiers = &h20000 Set objWMIService = GetObject("winmgmts://" & strComputer & "/" & strNameSpace) Set objClass = objWMIService.Get(strClass, wbemFlagUseAmendedQualifiers) strMOF = objClass.GetObjectText_ WScript.Echo strMOF
不过,对于使用 GetObjectText_ 有一个限定:没有关于在包含在由该方法返回的 MOF 语法中的继承限定符的信息。当 Key 限定符在一个父类的属性中定义时,如果您想要使用 GetObjectText_ 来确定一个类的 Key 属性,这可能会带来问题。
使用 SWbemObjectEx GetText_
Windows XP 和 Windows Server 2003 都包含一个名为 GetText_ 的新方法,它可以用于检索托管资源类定义的 XML 表现形式。
除了一个明显的例外,使用 GetText_ 与使用 GetObjectText_类似:传递到 GetText_ 方法的三个参数。
第一个参数是必需的,它标识所产生的 XML 格式。它目前可以是作为由 WMI WbemObjectTextFormatEnum 定义的两个值中的一个:wbemObjectTextFormatCIMDTD20(值:1)或 wbemObjectTextFormatWMIDTD20(值:2)。值 2 (wbemObjectTextFormatWMIDTD20) 告诉 GetText_ 根据 Distributed Management Task Force CIM 文档类型定义 (DTD) 2.0 版本的扩展 WMI 版本格式化所产生的 XML。
第二个参数是可选的,并且目前是为操作标记保留的。它必须被设置为 0(零)。
第三个参数 colNamedValueSet(也是可选的),是一个为 GetText_ 提供特殊说明的 SWbemNamedValueSet 集合。这里,我们让 GetText_ 进行:
• | 检索并编码所有属性和方法,不仅仅是本地定义的属性和方法。 |
• | 包含所产生的 XML 中的类限定符、属性限定符和方法限定符。 |
• | 包含所产生的 XML 中的系统属性。 |
• | 包含对所有属性和方法的类起源。 |
清单 13:使用 SWbemObjectEx GetText_ 来检索 Win32_Service 类的 XML 表现形式(仅限 Windows XP 和 Windows .NET)
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Const wbemFlagUseAmendedQualifiers = &h20000 Const wbemObjectTextFormatWMIDTD20 = 2 Set objWMIService = GetObject("winmgmts://" & strComputer & "/" & strNameSpace) Set objClass = objWMIService.Get(strClass, wbemFlagUseAmendedQualifiers) Set colNamedValueSet = CreateObject("Wbemscripting.SWbemNamedValueSet") colNamedValueSet.Add "LocalOnly", False colNamedValueSet.Add "IncludeQualifiers", True colNamedValueSet.Add "ExcludeSystemProperties", False colNamedValueSet.Add "IncludeClassOrigin", True strXML = objClass.GetText_(wbemObjectTextFormatWMIDTD20, 0, colNamedValueSet) WScript.Echo strXML
为了成功运行清单 13,将脚本复制并粘贴到您最常用的文本编辑器中,保存脚本(扩展名为 .vbs,例如:GetXML.vbs),然后使用下面列出的命令行运行脚本。
C:/Scripts> cscript //nologo GetXML.vbs >Win32_Service.xml
图 12 显示所生成的 XML 文件,Win32_Service.xml,使用 Microsoft Internet Explorer。
图 12:GetXML.vbs 输出
就到这里吧
如果对 WMI 有任何疑惑、困难或不知所措,那可能是在处理由 WMI 公布的大量数据。我们愿意认为,我们已经为您装备了有效地寻找并解释 WMI 托管资源类定义所必需的知识和工具。当然,对于这一点您是最好的裁判,所以请尽量让我们知道我们是否以及有哪些不足。枯燥的内容结束了,准备在我们投入到 WMI 脚本库的详细信息时在第三部分玩得开心点吧。哦,不管怎么样,随意打发剩下的时间吧。
等一下!在您打包走人之前,还有最后一个要注意的地方:WMI 开发小组让我们告诉您,以前只能随 WMI SDK 使用的 WMI 工具,现在已经进行了更新。更新的工具(包括 WMI CIM Studio、WMI 事件注册、WMI 事件查看器 和 WMI 对象浏览器),现在都与 Windows XP 和 Windows Server 2003 以及 Windows 2000 兼容。此外,更新的工具不包含 WMI SDK,这意味着现在您可以安装这些工具而不必安装整个 WMI SDK。这难道不是非常酷么?
补充脚本
清单 A:列出在 root/cimv2 命名空间中定义的抽象类类型
strComputer = "." Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2") Set colClasses = objWMIService.SubclassesOf() For Each objClass in colClasses For Each objClassQualifier In objClass.Qualifiers_ If LCase(objClassQualifier.Name) = "abstract" Then WScript.Echo objClass.Path_.Class & ": " & _ objClassQualifier.Name & "=" & _ objClassQualifier.Value End If Next Next 清单 B:列出在 root/cimv2 命名空间中定义的动态类类型 strComputer = "." Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2") Set colClasses = objWMIService.SubclassesOf() For Each objClass in colClasses For Each objClassQualifier In objClass.Qualifiers_ If LCase(objClassQualifier.Name) = "dynamic" Then WScript.Echo objClass.Path_.Class & ": " & _ objClassQualifier.Name & "=" & _ objClassQualifier.Value End If Next Next
列表 C:使用 SWbemObject Qualifiers_、Properties_ 和 Methods_ 检索类限定符、属性、属性限定符、方法和方法限定符
strComputer = "." strNameSpace = "root/cimv2" strClass = "Win32_Service" Set objClass = GetObject("winmgmts://" & strComputer & _ "/" & strNameSpace & ":" & strClass) WScript.Echo strClass & " Class Qualifiers" WScript.Echo "------------------------------" i = 1 For Each objClassQualifier In objClass.Qualifiers_ If VarType(objClassQualifier.Value) = (vbVariant + vbArray) Then strQualifier = i & ". " & objClassQualifier.Name & " = " & _ Join(objClassQualifier.Value, ",") Else strQualifier = i & ". " & objClassQualifier.Name & " = " & _ objClassQualifier.Value End If WScript.Echo strQualifier strQualifier = "" i = i + 1 Next WScript.Echo WScript.Echo strClass & " Class Properties and Property Qualifiers" WScript.Echo "------------------------------------------------------" i = 1 : j = 1 For Each objClassProperty In objClass.Properties_ WScript.Echo i & ". " & objClassProperty.Name For Each objPropertyQualifier In objClassProperty.Qualifiers_ If VarType(objPropertyQualifier.Value) = (vbVariant + vbArray) Then strQualifier = i & "." & j & ". " & _ objPropertyQualifier.Name & " = " & _ Join(objPropertyQualifier.Value, ",") Else strQualifier = i & "." & j & ". " & _ objPropertyQualifier.Name & " = " & _ objPropertyQualifier.Value End If WScript.Echo strQualifier strQualifier = "" j = j + 1 Next WScript.Echo i = i + 1 : j = 1 Next WScript.Echo WScript.Echo strClass & " Class Methods and Method Qualifiers" WScript.Echo "-------------------------------------------------" i = 1 : j = 1 For Each objClassMethod In objClass.Methods_ WScript.Echo i & ". " & objClassMethod.Name For Each objMethodQualifier In objClassMethod.Qualifiers_ If VarType(objMethodQualifier.Value) = (vbVariant + vbArray) Then strQualifier = i & "." & j & ". " & _ objMethodQualifier.Name & " = " & _ Join(objMethodQualifier.Value, ",") Else strQualifier = i & "." & j & ". " & _ objMethodQualifier.Name & " = " & _ objMethodQualifier.Value End If WScript.Echo strQualifier strQualifier = "" j = j + 1 Next WScript.Echo i = i + 1 : j = 1 Next
Scripting Clinic
Greg Stemp 长期以来被公认为美国国内的脚本编写权威之一,并且被大家广泛誉为世界级……哈哈!嗯,他们 的履历表中怎么都当过足球教练?真的吗?他被解雇 了?哦,好吧。Greg Stemp 工作在……哦,好了,难道我连这都不能说吗?好吧!Greg Stemp 从 Microsoft 领薪水,在那儿他拥有并不显赫的首席作家(System Administration Scripting Guide)的头衔。
Dean Tsaltas 是一个生活在 Redmond 的 Nova Scotian 人。他已经开始说一口流利的美语了,甚至会笑他的滨海省的朋友和家人们的发音。他的计算机生涯开始于他很小的时候,那时他的祖母和父母资助他,为他买了他心爱的 C-64,并为他订阅了 Compute! 的学报。现在,他已经在 Microsoft 工作了若干年,他有句话要告诉在家乡和温哥华的朋友和家人:“没有,我还没见过比尔!”
Bob Wells 漫无目的地四处游走,向每个听他说话的人大赞脚本编写的好处。有传言说,Bob 的两只达克思猎犬对脚本编写比大多数人类知道的都多。业余时间里,Bob 向 System Administration Scripting Guide 投稿。
Ethan Wilansky把他的很多的工作时间花在了写作和咨询方面。他狂热于脚本编写、瑜伽、园艺和他的家庭(不一定按此顺序)。他目前正致力于一种创建能倒垃圾和洗餐盘的脚本的方法。