脚本漫谈

转自: http://www.microsoft.com/china/technet/archives/columns/scripts/sg1102.asp
依托多部计算机运行WMI脚本
脚本专家组

 本页主要标题:


在围绕本月主题展开深入研讨之前,脚本专家组先向您表示诚挚的谢意!我们新近开辟的脚本程序员专区已被如潮水般滚滚而来反馈信息充斥,能够从如此之多的读者那里收到回复绝对是一件令人倍感兴奋的事情。即使我们尚无法对您们所发来的每封电子邮件一一做答(虽然我们力争回复尽可能多的邮件),却仍衷心盼望借助您们所提供的建议帮助我们保持正确的发展方向。这里再次向您们表示诚挚的谢意。

我们将在这个专栏中探讨针对从脚本中心获得的典型WMI脚本进行修改的具体方式,以及确保这些脚本依托多部计算机实现运行的修订方法。我们一直都在强调指出这些WMI脚本所具备的一大主要优势--它们主要设计用来仅仅依托本地计算机实现运行--就是可被轻而易举地调整为依托一系列指定计算机设备实现运行的状态。

这的确是一种非常明显的优势,但正如我们所知,“轻而易举”是一种相对性较强的说法;毕竟,除非有人教授您具体实现方法,脚本编程工作中就没有什么“轻而易举”可言。鉴于我们尚未着手将具体实现方式展现在您眼前,故而,我们收到以下列说法为典型代表的大量问题并不出乎意料:

“如果我编写了一个可供用来基于远程计算机对所有处于运行状态的服务加以查询的脚本,是否仍能利用同一脚本在命令行方式中引导我输入远程计算机名称?”

“是否存在可供这些脚本依托一台以上计算机实现运行的有效方式,是否存在从某一文件或其它对象中获取计算机名称的可能性?”

“能否令这个脚本依托所有域控制器实现运行?”

上述问题的答案只有一个:您当然可以。请将这个直截了当的回答牢记于心,并让我们开始本月的专栏研讨。

简要回顾

学习脚本编写方法的最佳途径就是亲手编制相关脚本。为此,让我们从一个来自脚本中心的示例脚本入手,该脚本主要借助WMI对已被安装于本地计算机的全部服务功能所处状态加以显示。在我们开始对该脚本进行相应修改、以确保它依托本地计算机之外的其它设备实现运行前,先让我们了解一下它在脚本中心中所呈现的本来面貌:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2")
Set colRunningServices = objWMIService.ExecQuery _
    ("Select * from Win32_Service")
For Each objService in colRunningServices 
    Wscript.Echo objService.DisplayName  & VbTab & objService.State
Next

如果您对WMI脚本还不十分熟悉,那么,上述代码看起来会多少有些费解。如果您确有此感,便可从以下两种入门方法中任选一种。如果您愿意的话,可立即前往MSDN网站,并查阅由脚本诊所专栏提供的WMI入门系列文章;当您彻底浸淫于WMI脚本编程天地之后,便可重新拾起曾在这篇专栏文章中暂时搁置的内容(请不必担心,我会在此耐心地等候您)。此外,您还可权且将信任托付给我们,而我们则将为您提供有关本文所涉及内容的简明概述。当然,您完全可稍后钻研WMI入门系列文章,以便学习更多详细内容。

无论您采取何种学习方法,我们都将从这里开始讲解上述脚本的工作原理。上述脚本的这个部分与WMI有关。更确切地说,这个代码行与一种被称作名称空间的对象有关:即root/cimv2名称空间。

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2")

需要再次加以说明的是,如果您希望了解更多详细资料,则应查阅MSDN网站。简而言之,脚本的这一部分可将您连接至基于某一名称已被赋值给strComputer变量之计算机的WMI服务(我们将随后加以详细介绍)。

说明:那么,何谓名称空间呢?您可在WMI中针对被称作“类”的对象执行操作。而类则属于真实、生动事物的虚拟表象;举例来说,某一计算机上存在着可供用来指代所有服务的Win32_Service类。名称空间是可供用来存储一整套类的简单位置;而在本例中,Win32_Service类则被存储于root/cimv2名称空间。

那么,计算机名称又意味着什么呢?我们刚刚谈到,计算机名称被存储于strComputer变量。但该变更已被设定为一个圆点(.)。试问,有谁会将自己的计算机命名为一个圆点呢?

好吧,也许没有人会这么做。然而,在WMI中,将计算机名称设定为圆点的做法仅仅是在避免将您自身局限于某一特定本地计算机的前提下用来指代“本地计算机”的简化方式。假设您拥有一台已被命名为TestComputer的独立计算机。在这种情形中,以下两行代码的任意一行均可引导您依托名为TestComputer的本地计算机运行相关脚本:

strComputer = "."
strComputer = "TestComputer"

事实上,如果TestComputer的IP地址为192.168.1.1,那么,以下这行代码便可发挥作用:

strComputer = "192.168.1.1"

如前所述,我们已利用编码手段将计算机名称强行写入脚本。举例来说,下面这行代码主要用来同基于名为HRServer01之计算机的WMI服务实现连接:

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!//HRServer01/root/cimv2")

既然如此,我们为何不干脆将上述名称直接强行写入脚本呢?我们之所以这样做,就是为了便于依托任何计算机运行相关脚本,而我们必须执行的全部操作仅仅是针对strComputer变量加以修改。这恰恰是这篇专栏文章的讨论核心。

示例脚本的下一部分将要求WMI服务提供某些相关信息。它将针对已被安装于指定计算机的全部服务发出一系列请求,并在此基础上将相关信息保存至colRunningServices变量。(如果您希望给自己的朋友留下深刻印象,就请告诉他们,colRunningServices实际上属于一种被称作对象引用的特殊变量类型。但这样一来,我们便只能希望他们不再追问“何谓对象引用”,因为我们已没有时间深入探讨这个问题了。)

Set colRunningServices = objWMIService.ExecQuery _
    ("Select * from Win32_Service")

示例脚本的最后部分仅供用来显示已被保存于colRunningServices变量的每项服务名称及其所处状态:

For Each objService in colRunningServices 
    Wscript.Echo objService.DisplayName  & VbTab & objService.State
Next

让我们继续将全面脚本代码键入记事本,并保存为ListServices.vbs。虽然您为该脚本指定的存储位置实际上无关紧要,但既然我们围绕同一页面进行讨论,就应将各自脚本统一保存至C:/Scripts目录。如果您所使用的计算机上尚未存在C:/Scripts目录,就应在执行脚本保存操作之前先行创建该目录。

脚本专家组提供的一项免费技巧:请注意,这里有一种能够真正打动您朋友的程序方法;下列脚本将为您创建C:/Scripts文件夹:

Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CreateFolder("C:/Scripts")

当您执行脚本保存操作后,请打开一个命令行窗体,并导航至C:/Scripts目录,然后,通过输入下列命令并敲击回车键的方式运行该脚本:

cscript ListServices.vbs

您将会看到如下图所示的脚本输出结果,窗体中显示了基于本地计算机的全部服务,以及每项服务的当前状态信息(如“已停止”或“正在运行”)。


如果您所使用的浏览器无法支持嵌入式框架,请, 点击此处 以便在单独页面中进行浏览。

现在,一切均处于正常状态,但如果您希望从某一远程计算机获取相同服务信息,又将如之奈何?您也许还记得,我们已在脚本的第一行中将strComputer变量设定为用来指代本地计算机的一个圆点(.)。而在脚本的后续部分中,strComputer则被用来同基于指定计算机的WMI服务建立连接。这样一来,由脚本检索到的信息都将是关于远程计算机的信息,而与运行脚本的计算机无关。

举例来说,假设您需要将脚本用途修改为与一台名为HRServer01的远程计算机建立连接。为实现上述目的,您只需将strComputer变量值从“.”修改为“HRServer”。如果您正在家中使用着自己的计算机,就请从您所在的网络系统上选取一台远程计算机,并将赋值语句中的圆点替换为所选计算机名称。请注意,在缺省状态下,您必须从属于远程计算机的本地管理员组,以确保该脚本实现正常运行。这主要是因为,只有本地管理员组成员才具备借助WMI从远程计算机上检索相关信息的能力。

举例来说,下面就是一个可供用来从名为HRServer01的计算机上检索服务信息的新脚本:

strComputer = “HRServer01”
Set objWMIService = GetObject(“winmgmts:” _
& “{impersonationLevel=impersonate}!//” & strComputer & “/root/cimv2”)
Set colRunningServices = objWMIService.ExecQuery _
(“Select * from Win32_Service”)
For Each objService in colRunningServices 
Wscript.Echo objService.DisplayName  & VbTab & objService.State
Next

请按与从前完全相同的方法运行已经过修改的脚本,即在命令行窗体内输入以下命令。并敲击回车键:

cscript ListServices.vbs

您应该看到与上个脚本相似的运行结果(您所看到的实际结果可能因已被安装于远程计算机的服务而有所区别)。


如果您所使用的浏览器无法支持嵌入式框架,请, 点击此处 以便在单独页面中进行浏览。

上述脚本同我们编写的第一个脚本之间的关键性区别在于:由前者列示的服务将是那些基于远程计算机HRServer01运行的对象。举例来说,您可能已经注意到,基于本地计算机运行的应用管理服务(详见上一幅屏幕快照)已在名为HRServer01的计算机上被终止。

说明:如果您选择了一台并不存在的计算机,亦或所选计算机目前正处于脱机状态,又将如之奈何?在这种情况下,脚本将发生崩溃。为此,请将脚本中的第一行代码修改为“On Error Resume Next”(如发生错误,继续执行后续代码),以便提供一个暂时工作区。稍后,我们将围绕针对这一问题的更优解决方案展开讨论。

将计算机名称输入为命令行参数

针对strComputer变量加以修改的做法的确可以奏效;它将允许您依托某一远程计算机运行相关脚本。然而,如果您不必为确保脚本依托不同计算机运行而每次均对该脚本进行相应修改,那么,将会令事情变得更加完美。事实上,如果您仅仅将计算机名称指定为某一命令行参数,事情同样可以变得更加完美。

这听起来可能有些困难,但实际上却相当简便易行。每当您从命令行方式中启动某一脚本(例如,通过输入cscript ListServices.vbs命令的方式)时,在脚本名称后面键入的任何字符都将会被系统解释为命令行参数。事实上,这些字符不仅会被解释为命令行参数,而且,还将被自动检索并保存,以确保您能够从脚本内部对其实施访问调用。

举例来说,假设您通过输入以下命令的方式启动一个脚本:

cscript ListServices.vbs HRServer01 WebServer01

您可在脚本中借助WScript.Arguments(0)来引用第一个参数(HRServer01),并借助WScript.Arguments(1)来引用第二个参数(WebServer01)。如果还存在第三个参数,就请借助WScript.Arguments(2)对其加以引用。您可依次类推地将这种方法应用于若干个参数。而当您使用命令行参数启动某一脚本时,还必须用至少一个空格将每个参数分隔开来。

说明:如果您必须输入一个包含空格在内的参数(例如,Default Domain Policy),又应如何是好?在这种情况下,您必须使用引号将所需输入的参数括起来,例如,“Default Domain Policy”。如果您没有使用引号,字符串Default Domain Policy便会被解释为三个彼此独立的参数:Default、Domain和Policy。

让我们尝试处理尽可能简单的情况:首先,针对我们的脚本进行修改,以确保其依托被我们指定为命令行参数的任何计算机运行。为实现上述目的,我们只需将strComputer变量设定为与第一个命令行参数WScript.Arguments(0)相等的状态。也就是:

strComputer = Wscript.Arguments(0)
Wscript.Echo “Running Against Remote Computer Named: “ & strComputer
Set objWMIService = GetObject(“winmgmts:” _
& “{impersonationLevel=impersonate}!//” & strComputer & “/root/cimv2”)
Set colRunningServices = objWMIService.ExecQuery _
(“Select * from Win32_Service”)
For Each objService in colRunningServices 
Wscript.Echo objService.DisplayName  & VbTab & objService.State
Next

说明:我们还添加了一行用来显示脚本运行所依托之计算机名称的代码,以便帮助您清楚地了解到当前正在运行的脚本。

先对脚本进行相应修改,再尝试运行它。请注意,如果您试图通过先前采取的方式运行该脚本--即仅仅输入cscript ListServices.vbs命令,便会看到以下错误信息:

C:/scripts/ListServices.vbs(1, 1) Microsoft VBScript runtime error: 
Subscript out of range.

为何会出现这种情况?因为您并没有在文件名ListServices.vbs后面输入命令行参数,而针对Wscript.Arguments(0)的引用则不具备任何意义;您已告诉脚本将strComputer变量设定为第一个参数值,但却无从发现相关参数。这样一来,VBScript便会使您陷入一个因此而产生的困境。(顺便说明,(1,1)中的第一位数将可告诉您发生VBScript语言错误的脚本代码行号。)

让我们尝试通过输入以下命令的方式排除由VBScript语言识别出的错误(您可将HRServer01替换为自身网络系统上的真实计算机名称):

cscript ListServices.vbs HRServer01

(如果您只拥有一台计算机,就请在此输入这台计算机的名称。而更加简便的方法则是,输入一个圆点,并查看脚本是否依托本地计算机运行--我们相信,这种方法肯定行之有效。)

您应该再次查看服务列表及相关服务的当前状态。而主要区别则体现为,您只需在命令行状态下输入适当名称,即可依托任何计算机运行相关脚本。可见,您已实现了上述目的。多谢合作,并祝晚安。

将多个计算机名称输入为命令行参数

到目前为止,我们仍未触及曾许诺在这篇专栏文章中加以解决的问题:依托多台计算机运行相关脚本。前述脚本确实可依托多台计算机运行--只要您愿意将其运行多次。举例来说,您可通过输入下列命令的方式在三台不同计算机上列示服务项目及其当前状态:WebServer01、FileServer01和SQLServer01。

cscript ListServices.vbs WebServer01
cscript ListServices.vbs FileServer01
cscript ListServices.vbs SQLServer01

但您是正确的:这种依靠重复输入的方法对于脚本编程人员来说,未免过于繁琐。我们为何不只输入一条像这样的命令来克服重复问题呢?

Cscript ListServices.vbs WebServer01 FileServer01 SQLServer0

我们当然做到了。正如我在前面说过的那样,命令行参数一经保存,便会被纳入名为WSHArguments的集合。WSHArguments集合仅仅是由那些在脚本运行过程中被输入的命令行参数所构成的集合。

那么,这对我们来说,又会产生哪些帮助呢?我们可利用For Each循环语句从WSHArguments集合中检索到每个参数(即每台计算机的名称)。这里提供了一个可依托被当作命令行参数的每台计算机实现运行的脚本:

For Each strArgument in WScript.Arguments
   strComputer = strArgument
   WScript.Echo "***** Computer ******" & vbCrLf & strComputer & vbCrLf
   Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2")
   Set colRunningServices = objWMIService.ExecQuery _
    ("Select * from Win32_Service")
   For Each objService in colRunningServices 
      Wscript.Echo objService.DisplayName  & vbTab & objService.State
   Next
Next

上述脚本所具备的功能如下所示:

  1. 该脚本将可对命令行参数进行截取--也就是这个例子中的WebServer01、FileServer01和SQLServer01--并将它们保存至WSHArguments集合。
  2. 该脚本将可对第一个参数(WebServer01)值进行截取,并将其赋予strComputer变量。
  3. 该脚本可供用来与那台由strComputer变量指代的计算机建立连接,并针对同全部服务有关的信息执行检索和显示操作。
  4. 该脚本可追溯至For Each循环起点,并截取第二个参数(FileServer01)值,再将其赋予strComputer变量。
  5. 该脚本可供用来与那台由strComputer变量指代的计算机建立连接,并针对同全部服务有关的信息执行检索和显示操作。
  6. 该脚本可追溯至For Each循环起点,并截取第三个参数(SQLServer01)值--依次类推。该脚本将周而复始地执行循环程序步骤,直到遍历整个命令行参数集合。

顺便说明,针对第三个参数所执行的操作也并没有什么稀奇之处。您可对第1、第2、第3乃至第100个参数如法炮制。只要您所提供的参数不少于1个,这行代码便可正常发挥作用。

说明:如何有人忘记在程序代码中提供所需参数,又该如何防范?如果您担心这种情况发生,就应在脚本开始处添加下列代码。这段代码主要利用WSHArgument对象的Count属性来计算集合所含参数个数。如果Count属性被赋值为0,便意味着程序员并未提供任何参数,于是,脚本将在显示一条提示信息之后终止运行:

If WScript.Arguments.Count = 0 Then
    Wscript.Echo "You must supply at least one computer name."
    Wscript.Quit
End If

从文本文件中检索计算机名称

本期专栏开始时,我们主要围绕一个由TechNet脚本中心提供的WMI脚本展开研讨,以期检索到与单一计算机相关的服务信息:亦即服务功能所依托的计算机。我们现已能够在运行脚本的同时向命令行中输入任意数量的不同计算机名称,而被显示出来的运行结果则是源自这些计算机的服务信息。

说明:通过这种方法获取的信息资料将会多得令您应接不暇。在后续发布的专栏文章中,我们会介绍给您一种将此类信息保存为多种格式的具体方法;但目前,我们只能利用重定向符号(>)将脚本输出结果导引至某一文本文件(而非命令行窗体)。此后,您还可利用记事本打开保存有脚本输出结果的文本文件,并随心所欲地浏览文件内容(不必在刺眼的屏幕滚动效果下进行查看)。如需运行相关脚本,并将运行结果导向一个名为report.txt的文本文件,就请在命令行方式下输入以下命令:

cscript ListServices.vbs WebServer01 FileServer01 > report.txt

我们能猜到您现在想些什么。您正在想,“我应该感谢脚本专家组,但我必须依托50台计算机运行自己所编写的脚本。你们能否告诉我如何一边运行脚本一边在命令行方式下将这50个计算机名称全部输入?”

这种设想当然无法实现。但您却可要求自己的脚本针对保存有计算机名称的文本文件执行读取操作,并在此基础上依托其所包含的每台计算机实现运行。

为实现上述目的,应首先生成一个包含有计算机名称的简单文本文件;在这个文件中,每个计算机名称将独自占据一行位置。为方便进行演示,请将该文件保存为C:/Scripts/Computers.txt。


如果您所使用的浏览器无法支持嵌入式框架,请, 点击此处 以便在单独页面中进行浏览。

下列代码便是可供用来针对前述文本文件执行读取操作的脚本。在运行该脚本时,您将不必使用任何命令行参数,而只需在命令行方式中输入以下命令,并敲击回车键:

cscript ListServices.vbs

Const INPUT_FILE_NAME = "C:/Scripts/Computers.txt"
Const FOR_READING = 1

  
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(INPUT_FILE_NAME, FOR_READING)
strComputers = objFile.ReadAll
objFile.Close
 
arrComputers = Split(strComputers, vbCrLf)
 
For Each strComputer In arrComputers
   Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2")
   Set colRunningServices = objWMIService.ExecQuery _
    ("Select * from Win32_Service")
   For Each objService in colRunningServices 
      Wscript.Echo objService.DisplayName  & vbTab & objService.State
   Next
Next

上述脚本的运行结果将体现为,针对名称已被列示于文本文件的全部计算机所托管的服务信息加以显示。可见,我们已得到了一个可供用于实现目标操作的程序脚本;现在,我们将围绕该脚本的作用机理展开分析研讨。

如您所见,该脚本的前两行主要用来设定旨在使其更加便于阅读和理想的相关常量。INPUT_FILE_NAME保存着包含有计算机名称的文本文件路径。而FOR_READING则用来在打开文件时声明从中读取相关信息的需求。我们将在后续发布的专栏文章中围绕文件操作方法进行介绍;但您现在只需了解,您既可对文本文件执行读取操作,又可对此类文件执行写入操作。鉴于您无法同时执行读写操作,因此,必须在脚本中指明所需使用的操作模式。

脚本专家组提供的另一项免费技巧:如果下面这个窍门还无法打动您的朋友,您就应该考虑交一位新朋友了。请将上述脚本的第一行修改为:

INPUT_FILE = Wscript.Arguments(0)

要问这对您有什么好处?好吧,假设您拥有多个包含有计算机名称的文本文件:其中,一个与您的DHCP服务器有关,一个与您的域控制器有关,还有一个与您的电子邮件服务器有关。您是否需要针对它们中的每一个分别生成彼此独立的程序脚本?当然没有必要。请在Windows资源管理器中将所需文本文件拖放至脚本文件图标(ListServices.vbs)。于是,脚本便会将文本文件名作为一个参数加以使用,并在此基础上针对该文件自动执行打开和读取操作。您只要尝试一下,便会理解我们的用意所在。

代码行:Set objFSO = CreateObject("Scripting.FileSystemObject")将指示您的脚本为处理相关文件做好准备。VBScript并不知道应如何对文件进行处理;而替代方法则是以COM对象作为辅助手段。我们在本例中使用了FileSystemObject。这是一个随同VBScript和Windows Script Host一并安装的COM对象,并且具备良好的文本文件读写能力。

代码行:Set objFile = objFSO.OpenTextFile(INPUT_FILE_NAME, FOR_READING)是一条非常易于理解的语句。它主要用来为执行读取操作而打开访问路径名已被保存于INPUT_FILE_NAME常量的文本文件。顺便说明,这恰恰是我们对常量加以运用的原因所在。下面这行使用强行编码值1的脚本代码还可为执行读取操作打开一个文本文件,但有关效果的直观性将大打折扣:

Set objFile = objFSO.OpenTextFile(INPUT_FILE_NAME, 1)

代码行:strComputers = objFile.ReadAll是文件内容读取操作实际发生的地方。文件内容将以其完整面目接受读取操作(ReadAll),并被保存于strComputers变量。而下一行脚本则仅供用于关闭当前文本文件。

在这个环节中,我们几乎置身于一个非常熟悉的境界。当我们使用命令行参数时,将以某一集合所包含的计算机名称收尾(这种情况在系统管理脚本编程工作中相当普遍)。我们还为针对包含于特定集合的所有项目进行遍历而使用了For Each循环语句。所不同的是,我们这次已将全部计算机名称纳入strComputers变量;事实上,如果您愿意对strComputers变量值加以显示,便会得到效果类似于文本文件的输出结果。遗憾的是,这并不是一个集合,而我们也只能依赖For Each循环语句,并期待获得合理的运行结果。

代码行:arrComputers = Split(strComputers, vbCrLf)主要用于截取strComputers变量(计算机名称清单)所存储的内容,摘录单个计算机名称,并将它们置于一种被称作阵列的对象当中。阵列与集合较为相似(虽然两者之间存在重大差异,但仅就我们所设定的用途而言,这种差异并无关紧要)。重要的是您可借助我们的老朋友--For Each--对相关阵列进行遍历。

您也许非常想知道Split函数将如何对存储于strComputers变量的计算机名称进行区分。正如您所记得的那样,每个计算机名称都在文本文件中占据着一个独立行次。而在此类文本文件中,每一行次均以一个被VBScript称作vbCrLf的不可见标识符(即回车换行)收尾。我们基本上会告知Split函数,对应于单个项目的strComputers变量将以回车加换行标识符进行分隔。举例来说,该函数会先查找到字符串HRServer01,然后,才遇到回车换行标记。而这恰恰是第一个项目--HRServer01--已被发现的迹象。Split函数将把计算机名称HRServer01置入阵列,并继续执行读取操作。接下来,该函数还将发现字符串WebServer01,然后,遇到回车换行标记。依次类推,您将可设想出整个处理过程的其余部分。

在将相关计算机名称置入阵列后,脚本剩余部分的功能也就和修改之前没有区别了。它仅仅借助For Each循环语句对阵列(集合)中的全部计算机名称执行检索操作。而脚本运行结果则是针对每台计算机上的相关服务信息加以显示。

从Active Directory容器中检索计算机名称

因满足上述收获而裹足不前简直无异于犯罪(当然,您也没必要为此拿起电话拨叫9-1-1报警台)。我们的确拥有一个相当出色的解决方案。当然,也请您思考一下将这些计算机名称归集起来置入相关文本文件的具体实现方式。如果您目前处在一个基于Active Directory的环境当中,便有可能调用Active Directory Users and Computers特性,并针对相关目录进行检查。但您毕竟是一位脚本程序员!您又何必偏偏从事这种手工劳动呢?难道您不应该指示脚本为您完成上述工作吗?您当然应该。而Microsoft公司则恰好为您提供了所需脚本库:Active Directory服务界面(ADSI)。

ADSI将允许您所编写的脚本同类似于Active Directory的目录服务进行交谈。但针对ADSI的工作原理加以解释却已超出了本文的讨论范围。换言之,如果不讲解具备ADSI支持特性的脚本直接从相关目录中截取计算机名称的具体实现方式,这篇文章也就不够全面完整。因此,我们将通过一个示例脚本向您提供较为浅显的解释,并以此为Microsoft Press即将出版的专业书籍鸣锣开道。这本题为Microsoft Windows 2000脚本编程指南的专著将围绕ADSI展开详细介绍(请不必担心,我们并不是一群顶着巨大压力的推销员;我们即将通过在线方式免费提供这本专业著作,以便帮助您节省下每一分钱去购买X-Box。)

以下便是用来实现上述目的的示例脚本。该脚本主要利用ADSI附着在fabrikam.com域中的Computers容器上,并可将存储在这个容器内的全部计算机名称截取到一个集合当中。当完成以上任务后,该脚本的剩余部分将照旧利用For Each循环语句对特定集合进行遍历,并在此过程中收集相关服务信息。

Set colComputers = GetObject(“LDAP://CN=Computers, DC=fabrikam, DC=com”)
For Each objComputer in colComputers
      strComputer = objComputer.CN
      Set objWMIService = GetObject("winmgmts:" _
       & "{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2")
      Set colRunningServices = objWMIService.ExecQuery _
       ("Select * from Win32_Service")
      For Each objService in colRunningServices 
         Wscript.Echo objService.DisplayName  & vbTab & objService.State
      Next
Next 

如果您所使用的计算机帐号未被存储于Computers容器,又该如何是好?没问题;您可针对字符串“LDAP://CN=Computers, DC=fabrikam, DC=com”进行相应修改,以便与相关目录下的其它容器建立连接。举例来说,以下代码行便可供用来与Finance OU建立连接(请注意,您必须使用形如OU= 的语法格式,而非CN= ):

Set colComputers = GetObject("LDAP://OU=Finance, DC=fabrikam, DC=com")
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐