五、 CIM储存库和CIM类(1)
上一讲我们介绍了WMI的体系结构,还记得那张体系结构图吗?记得我们说到关注的重点应该是CIM储存库和WMI脚本对象库,为什么我们这样说呢?因为我们的程序直接是利用WMI脚本对象库进行编程,而这个WMI脚本对象获取或操作的内容都是来自CIM储存库(注意:我们这里说的CIM储存库,指的“是公共信息模型对象管理器Common Information Model Object Manager,CIMOM”和“公共信息模型Common Information Model,CIM 储存库”。这样做一是为了叙述和理解方便,其次目前对我们编写WMI应用程序来说实在没有必要把它区分开来)。为了强调CIM储存库和CIM类的重要性,仔细观察一下在前几讲中展示的实例1至实例4,唯一有区别的是标识 WMI 托管资源的类名和每个类属性的子集。相同程序模板可以用来检索全部的物理内存、服务、事件日志记录、进程和操作系统信息,这一事实说明了 CIM 类在 WMI应用程序中扮演的重要角色。一旦知道如何编写一个程序来管理一类 WMI 托管资源,您就可以对其他托管资源使用相同的基本技术。
当然,知道一个托管资源的类名以及该类的相应属性只是本文的一部分。在您能够巧用WMI的全部强大功能之前,您需要对 CIM 储存库和 CIM 类的结构了解得再多一些。为什么呢?我们将给出两个重要的理由:了解如何浏览 CIM 将帮助您确定通过 WMI 公开的计算机和软件资源,另一个是了解如何解释托管资源的类定义,将帮助您理解可以在托管资源上执行的任务。
那么如何了解或学习它呢?一种方法是通过查阅微软或其他第三方提供的各种资料书籍或使用一些WMI工具。另一种更强大、灵活的方法是使用 WMI 脚本对象库。关于 WMI,真正酷的事情之一是,您可以使用 WMI 脚本对象库来学习 WMI。没错,用编写 WMI 应用程序来检索 WMI 托管资源相同的方法,您也可以编写 WMI 应用程序来学习关于 WMI 本身的各种有趣的详细信息。您可以编写 WMI 应用程序来列出 CIM 储存库中所有的命名空间和类,您可以编写应用程序来列出一台启用 WMI 的计算机上安装的所有提供程序,您甚至可以编写 WMI 脚本来检索托管资源类定义。我们下面的例程9就是采用编写WMI 应用程序来获得CIM的所有命名空间。
接下来让我们仔细了解一下 WMI 的管理模型 — CIM 储存库。
CIM 储存库
在第上一讲中,我们说到 WMI 的基本思路是 — 来自不同来源的配置和管理信息能够用一种架构统一地表示,而 CIM 储存库就是针对 WMI 的架构。WMI CIM 构建构成计算机的硬件、操作系统和软件的模型。CIM 是 WMI 的数据模型。虽然 CIM 储存库能够存储一些数据(而且它确实存储了),但是它的主要目的是构建管理环境的模型。CIM 不是为存储它所定义的大量管理信息而设计的。相反,大部分数据是根据需要动态地从 WMI 提供程序检索的。一个例外是 WMI 操作数据。WMI 操作数据(例如,命名空间信息、提供程序注册信息、托管资源类定义和永久事件订阅)存储于 CIM 储存库中。
图 1:CIM 储存库的结构化视图 — WMI 架构
图 1 提供了一个 CIM 储存库的内部结构和组织的概念化视图。如图 1 所示,CIM 使用类来创建数据模型。不可否认,CIM 包含的类远超过关系图中展示的 11 个 — 上次我们在 Windows Server 2003 上统计大约有 5000 个。要了解的重要内容是,CIM 储存库是定义 WMI 托管环境和每个通过 WMI 公开的可托管资源的类存储。
图 1 中展示三个重要的 CIM 概念,您需要了解它们以成功地浏览并解释 WMI 架构。
1. CIM 储存库被划分为多个命名空间。
2. 每个命名空间包含下面一个或多个类的组:系统类、核心和公共类和/或扩展类。
3. 有三种主要的类类型:抽象、静态和动态。
抽象类 是用于派生(定义)新的抽象和非抽象类的模板,不能用于检索托管资源的实例。
静态类 定义物理存储在 CIM 储存库中的数据 — 最常见的是 WMI 配置和操作数据。
动态类 是为从提供程序中动态检索的 WMI 托管资源建模的类。
关联类 是一个抽象、静态或动态的类,描述两个类或托管资源之间的关系。
暂时别太担心关于 CIM 类类型问题,我们很快就会在一个更实际的环境中讨论 CIM 类类型。下面让我们更详细地看看每一个 CIM 概念。
命名空间定义
CIM 类被组织到命名空间中。命名空间是 CIM 使用的分区机制,控制托管资源类定义的范围和可见性。CIM 中的每个命名空间包含一个表现特定技术或管理区域的相关类的逻辑组。命名空间中的所有类必须有一个唯一的类名,一个命名空间中的类不能从另一个命名空间中的类派生,这就是为什么您将发现在多个命名空间中定义了相同的系统类、核心类以及公共类。
多数为 Windows 托管资源建模的类驻留在 root/cimv2 命名空间中。不过,按照图 1 中的描述,root/cimv2 不是您唯一需要注意的命名空间。虽然,事件日志、性能计数器、Windows 安装程序和 Win32 提供程序都将它们的托管资源类定义存储在 root/cimv2 命名空间中。但另一方面,注册表提供程序将其类定义存储在 root/DEFAULT 命名空间中。另外,新的 Windows Server 2003 DNS 提供程序将其托管资源类定义存储在 root/MicrosoftDNS 命名空间中。
命名空间使用
那么,命名空间如何影响您的 WMI 应用程序呢?每个 WMI 应用程序都首先需要初始化连接到一个命名空间,如下所示:
strComputer = "."
Set wbemServices = GetObject("winmgmts://" & strComputer)
如上,如果没有指定目标命名空间,则脚本连接到由下列注册表设置识别的命名空间:
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/WBEM/Scripting/Default NameSpace
默认的命名空间设置是 WMI 程序中检索一个托管资源时,如果没有指定命名空间,CIMOM(WMI 服务)就在默认的命名空间寻找该托管资源的类定义)。如果 CIMOM 在默认的命名空间中找不到托管资源类定义,就会产生一个 WBEM_E_INVALID_CLASS (0x80041010) 错误。
特别要注意不要将默认的命名空间设置与 root/DEFAULT 命名空间相混淆。它们是不相关的,除非您将 root/DEFAULT 设置为您的默认命名空间。
命名空间 root/cimv2 被初始配置为脚本默认的命名空间;但是,默认的脚本命名空间可以很容易地进行更改。因此,您应该始终在您的 WMI 脚本中标识一个托管资源的命名空间,而不是采用默认设置。如果上个月就遵照了我们自己的建议,所有 4 个清单(以及本文的清单 1 和 2)中的连接步骤就应该编写如下:
strComputer = "."
Set wbemServices = GetObject("winmgmts://" & strComputer & "/root/cimv2")
将目标命名空间添加到连接字符串会告诉 CIMOM 在 CIM 中到哪里去寻找托管资源类定义,很像完全限定路径告诉操作系统到底去哪里寻找一个文件。当您指定了目标命名空间,默认的命名空间就不使用了。
管理默认命名空间
下面是读取默认命名空间的主要代码(为减少多余的叙述,以后所有的例程都需要添加“Microsoft WMI Scripting V1.1 Library”,不再专门提示了)(例程6):
Set objSWbemServices = GetObject("winmgmts:root/cimv2")
Set objSWbemObjectSet = objSWbemServices.InstancesOf("Win32_WMISetting")
For Each objSWbemObject In objSWbemObjectSet
MsgBox "CIM命名空间:" & objSWbemObject.ASPScriptDefaultNamespace
Next
下面是设置默认命名空间的主要代码(例程7):
Set objSWbemServices = GetObject("winmgmts:root/cimv2")
Set objSWbemObjectSet = objSWbemServices.InstancesOf("Win32_WMISetting")
For Each objSWbemObject In objSWbemObjectSet
objSWbemObject.ASPScriptDefaultNamespace = "root/cimv2"
objSWbemObject.Put_
Next
您可以像例程6和例程7中展示的那样,将使用Win32_WMISetting 类来读取和更改CIM的默认命名空间。Win32_WMISetting 是一个为 WMI 服务的操作参数建模的动态类。可写的属性表示脚本的默认命名空间是 ASPScriptDefaultNamespace。
例程7是设置CIM的默认命名空间,您应该将指定的命名空间字符串赋值给ASPScriptDefaultNamespace属性,然后用 SWbemObject 的 Put_ 方法将更改提交到 WMI 托管资源。设置和提交操作在例程7中的 For Each 循环内执行,因为 SWbemServices的InstancesOf 方法总是返回一个 SWbemObjectSet 集合,即便是只有一个目标 WMI 托管资源实例。
列出命名空间
到目前为止,我们已经用相同的 WMI 编程技术来检索动态的 WMI 托管资源的实例。例如,在第一讲中,我们使用相同的程序模板来查询进程,在第二讲中,我们检索服务等,这表明,您可以使用相同的 WMI 编程技术来从 CIM 中检索命名空间信息。象在托管资源脚本中的情况一样,您需要对程序做的唯一更改就是目标类名。
命名空间信息作为 __NAMESPACE 类的一个静态实例存储在 CIM 中。__NAMESPACE 类是我们前面简要定义的静态类类型的示例。不同于从提供程序按需检索的动态 WMI 托管资源,静态类实例存储在 CIM 中,且无需使用WMI 提供程序而直接从 CIM 中检索。下面的例程8使用 __NAMESPACE 类来检索并回显所有直接在根命名空间下的命名空间,主要代码如下。
Set objSWbemServices = GetObject("winmgmts://./root")
Set objSWbemObjectSet = objSWbemServices.InstancesOf("__NAMESPACE")
For Each objSWbemObject In objSWbemObjectSet
List1.AddItem objSWbemObject.Name
Next
运行此例程后,您可能已经注意到的,例程8不提供目标计算机上所有可用的命名空间的完整描述。它只检索并显示在单一的、指定命名空间下的命名空间。为了在本地或远程的启用 WMI 的计算机上回显所有命名空间,您需要修改例程8用递归方法枚举每个命名空间。幸运的是,这不想您想象中的那么难 — 就像例程9中展示的那样,在窗口添加1个List1控件,代码如下(例程9):
Option Explicit
Dim objSWbemServices As SWbemServices
Dim objSWbemObjectSet As SWbemObjectSet
Dim objSWbemObject As SWbemObject
Dim Num As Long
Private Sub Form_Load()
EnumNameSpaces "root"
End Sub
'采用递归方式,枚举CMI的所有命名空间到List1
Sub EnumNameSpaces(strNameSpace As String)
Num = Num + 1
List1.AddItem "(" & Num & ")" & strNameSpace
Set objSWbemServices = GetObject("winmgmts://./" & strNameSpace)
Set objSWbemObjectSet = objSWbemServices.InstancesOf("__NAMESPACE")
For Each objSWbemObject In objSWbemObjectSet
Call EnumNameSpaces(strNameSpace & "/" & objSWbemObject.Name)
Next
End Sub
前面我们已经提到过我们怎么才能知道当前我的计算机系统里有多少个CIM命名空间?呵呵,运行这个例程后我们就清清楚楚地知道了。希望大家把例程9自己去做一下,看看你自己的系统一共有多少个命名空间,我测试的机器是Win2000 Server,一共有16个命名空间,它们分别是:root、root/DEFAULT、root/SECURITY、root/CIMV2、root/CIMV2/Applications、root/CIMV2/Applications/MicrosoftIE、root/CIMV2/ms_409、root/CIMV2/ms_804、root/directory、root/directory/LDAP、root/directory/LDAP/ms_409、root/MicrosoftNLB、root/MicrosoftNLB/ms_804、root/MSAPPS、root/WMI、root/WMI/ms_409。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cw198624/archive/2009/02/19/3911797.aspx