脚本故事 - 2003年9月脚本环境 - 将你的工作站改造成脚本发电机 也许你曾经读过我们的脚本故事专栏,领教了我们肆无忌惮地宣传Windows 2000 脚本向导的本领,一时激动冲出去购买了这本书。也许你真正阅读并执行了有关升级到Windows Script Host 5.6的说明,将 Cscript.exe 设置为你的默认脚本主机,以及其他允许你优化脚本环境的所有细节。 如果这说的正是你,那么我们打赌你是知道爱沙尼亚的最大城市、能够记住圆周率的小数点后面10位数字的那种人。这类人总会高高地举起手,自信地向老师回答问题,然后在放学后在停车场因为弄坏标记线而被关禁闭。 另一方面,如果你和 Scripting Guys 一样,你可能没有耐心读完整本书;然后,注意到一些吸引人的脚本示例,赶紧走到计算机面前,在 Notepad 中输入这段脚本。最后,点击了14个消息框的“确定”,试图明白一系列含义模糊的“访问禁止”的错误后,你只能挠挠你的脑袋,把书扔到机箱后面,在咖啡壶里倒入爱尔兰奶酪酱和一勺泡沫(这是西雅图语的“咖啡”),恢复你那被打击的自尊心。 如果这正好是你,请不要沮丧。Windows 脚本的迷人之处就在于让它首次工作并不像灌篮那样轻松。它需要进行大量预先设计来配置你的管理工作站,这样才可以有效地运行脚本,并重复利用 —— 先深呼吸 —— Visual Basic Scripting Edition (VBScript)、Windows Script Host (WSH)、Windows Management Instrumentation (WMI) 和 Active Directory Service Interfaces (ADSI)。但是,这点苦难是值得的,你将从中学到很多脚本的知识。 注意: 我们怎么知道这点苦难是值得的呢?好,举例说,我们每个月都会收到这类的信件“我试图运行你们用来介绍如何使用 Exec 方法的脚本,可是我却得到了一个错误信息,说不支持这种方法”,或者 “我试图在我的 Windows 98 笔记本上运行你的 WMI 脚本,可是却获得了一个错误信息,说对象无法创建。”确切了解在你的计算机上可以安装以及不可以安装哪些脚本技术,这对于理解为什么某些脚本可以在一些计算机上运行,而在其他的机器上却不行,是很有帮助的。 如果你开始接触 Windows 脚本是有一两次失败,我们能够感觉到,并希望这个专栏能够帮助你减轻疼痛。我们希望它能够搬走一些绊脚石,这样你才可以更专注于使用所有这些技术来自动化的完成令人厌烦的工作—— 嗯,当你讨厌你的工作,甚至因此在上班的路上患上恐惧症时,你怎么称呼它呢?—— 汽车隧道综合症。 ![]() 本页内容
更新你的脚本技术为了发挥脚本的威力,你的工作站应该运行适用于你的 Windows 版本的最新VBScript、WSH、WMI 和 ADSI。Windows Server 2003 提供了你所需的一切。相对 Windows Server 20003 而言,Windows XP 中包括较早版本的 Windows Script 5.6 (其中包括了 VBScript 和 Jscript);这两个版本的功能基本上是相同的,只是最新的版本包括了一些针对小问题的修补程序 。Windows XP 还包括与 Windows Server 2003 相同版本的 ADSI,以及类似版本的 WMI (虽然在 Windows Server 2003 中有一些额外的类,这是在 Windows XP 中所没有的)。 在任何版本的 Windows 2000 (其中包含 WSH 2.0) 中,你可以运行 TechNet 脚本中心以及 Windows 2000 脚本指南中的大部分脚本示例。但是其中的一些示例需要 WSH 5.6,因此你可以需要升级到这个版本。 不相信我们?这里有一个脚本,其功能只是更改当前目录。只要你安装了 WSH 5.6,它就能正常工作。如果没有,则完全无法工作: Set objShell = WScript.CreateObject("WScript.Shell") Wscript.Echo "Initial Working Directory:" Wscript.Echo objShell.CurrentDirectory objShell.CurrentDirectory = "C:\" Wscript.Echo "Working Directory After Change:" Wscript.Echo objShell.CurrentDirectory 你可以从 Microsoft 开发人员网络(MSDN)中下载 Windows Script 5.6 的最新版本(单击表1中的链接),并将其安装在运行 Windows XP 和 Windows 2000 的计算机上。这样你就能提供一个跨越三个最新 Windows 操作系统的统一的最新 WSH 环境。表 1 还提供了下载 WMI 和 ADSI 升级的链接。 注意: 当然,你的反应可能是:“酷。现在我怎么能获得跨越三个最新 Windows 操作系统的统一的最新 WMI 和 ADSI 环境呢?”老实说,不行。在这三个平台上,ADSI非常类似,但是仍有一些差别。例如,在Windows XP 和 Windows Server 2003 中使用 ADSI 来编写安全描述符的脚本非常简单。在其他版本的 Windows 中完成整个工作也是可能的,但是相对困难。可惜现在仍然无法将 Windows 2000 计算机中的 ADSI 版本升级到 Windows Server 2003 中的相同版本。同样的,Windows 98 中的 WMI 类只是 Windows XP 中类的很少一部分。而且,现在也无法将 Windows 98 WMI 升级到 Windows XP WMI。 随便说一下,我们认识到当用户拥有各种计算机时是多么的沮丧,一些运行 Windows NT 4.0,一些运行 Windows 2000,其他的运行 Windows XP。你怎么知道是否有一个 WMI 脚本能够在所有这些平台上运行呢?好,不要睡着了;在脚本中心,紧盯着即将推出的 Comparmatic 实用工具,它将对 Windows 98、Windows NT 4.0、Windows 2000、Windows XP 以及 Windows SErver 2003 中的 cimV2 WMI 类进行比较。 表1 脚本技术/操作系统矩阵
注意: 虽然 WMI 和ADSI的升级仍适用于Windows 95,但是目前没有可用的 Windows 脚本升级,而且也没有更多有关脚本编写的信息,因此我们并不将它包含在这个列表中。 你说什么?你刚被雇佣,你也不知道在你的计算机上安装了什么版本的 WSH、WMI 和 ADSI。你正想知道 “Scripting Guys 是否能够告诉我如何知道在我计算机上安装了哪个版本?” 好,当然是有方法的;实际上,我们为你准备了一个完成这个任务的脚本。如果你可以再坚持一两分钟,我们还将让你了解这个脚本是如何工作的。 以具有管理权限的身份登录让我们假设你已经在你的工作站上安装了最新、最好的脚本技术。这就迈出了不错的第一步,是给你的朋友留下深刻印象的一种方法。(“哇,你有 WSH 5.6?!?哥们,你太XX了!")虽然向邻居展示你的保时捷总是很令人羡慕的,但拥有跑车的一半乐趣在于实际的驾驶。同样,拥有 WSH 5.6 的一半乐趣在于用它来运行脚本。 这也是某些用户会遇到问题的所在。我们真不愿意让那些成长中的黑客和解密高手感到失望,但是脚本并不能为你提供规避安全性的方法:如果你没有使用 GUI 完成某些任务(例如,安装打印机)的权限,那么你也无法使用脚本来完成这个任务。脚本遵守 Windows 安全性,但这也会是一个问题:我们收到了很多来自用户的提问,说他们无法运行脚本。这经常是由于脚本试图完成用户没有权限执行的任务。因此,了解运行脚本所需的安全上下文就变得十分重要了。 要本地或远程运行脚本,你必须首先作为本地管理员组的成员登录到你的工作站。要运行远程计算机上的 WMI 脚本,至少需要满足下面两点:
在 Windows XP 和 Windows Server 2003 中,WMI 不允许这个帐户的密码为空。虽然 Windows 2000 和更早版本的 Windows 操作系统并不强制实施这个要求,但是如果管理帐户的密码为空,可能会导致严重的安全性漏洞,因此请在所有平台上使用强健的密码。 为了在域成员的远程计算机上运行脚本,最好的方法是使用基于域的证书。 如果你需要使用另一个帐号在其他计算机上运行脚本,那么你可以使用 WMI 的 SWbemLocator 对象的 ConnectServer 方法来指定另一个用户名和密码。但是,ConnectServer 默认采用纯文本格式发送密码,这显然又将是一个安全性风险。 如果一台机器上运行了Windows NT 4.0 和早期版本的 WMI(早于1.5),而你希望在这台机器上远程运行脚本,那么你必须使用不同于默认值的模拟(impersonation)和身份验证。WMI SDK 中的文章 "在远程计算机上连接到 WMI "给出了详细的信息,地址:http://msdn.microsoft.com/library/en-us/wmisdk/wmi/connecting_to_wmi_on_a_remote_computer.asp。在Windows 98 和 95 上运行 WMI 之前,你必须执行特殊的安装程序,使这些操作系统接受远程DCOM 连接。 如果你使用 ADSI,你需要具有足够访问权限的基于域的证书,以便在所有目标机器上执行脚本中的任务。这将取决于 Active Directory 实现中的特定安全策略。例如,如果你有权重新设置用户密码,那么你可以运行一个重新设置用户密码的脚本。如果你没有这个权限,那么试图运行一个重新设置密码的脚本是没有任何意义的;它不会起任何作用。 当然,最简单的解决方法就是以域管理员身份登录。但是,登录为域管理员也可能增加安全性问题。根据你网络中的安全性策略,登录为不具有管理权限的用户,然后使用 Runas 命令来用具有管理权限的另一个证书运行脚本,这样可能更好一些。 将默认脚本主机更改为 Cscript我们建议你将 WSH 选项设置为默认在命令提示符中运行脚本。默认的 WSH 脚本主机是 Wscript.exe,它是在 GUI 中运行脚本的——也就是说所有的输入和输出都将出现在弹出消息框中,这就需要用户进行干预,点击“确定”才能使脚本继续工作。 Cscript.exe 是一种命令行脚本主机,通常更适用于系统管理任务,这些任务经常需要报告大量的信息(也就会导致你需要点击大量的消息框)。要将 Cscript.exe 设置为默认脚本主机,请打开一个命令窗口,然后在提示符后输入: cscript //h:cscript //nologo //s 这个命令行:
如果你没有运行这个命令行,那么为了在命令窗口中运行脚本,你必须在脚本文件名前输入"cscript",例如 cscript anyoldscript.vbs 如需了解可以在命令提示符中设置的全部 WSH 选项,请输入: cscript /? 使用脚本来检查你的脚本环境由于我们已经为你提供了大量的脚本新技术,而且我们认为应该将我们所推荐的技术加以实践——用 Microsoft 同事的话就是“eating our own dog food”(吃窝边草),因此我们提供了一个脚本(在你本地计算机上运行)来解决其中可能的问题。这个脚本将告诉你在你的计算机上安装了哪个操作系统,并告诉你所安装的 WSH、WMI 和 ADSI 的版本对于你的操作系统来说是不是最新的。如果它们并不是最新的,那么请参考后面的“技术下载”一节,从中你可以下载到最新的版本。 Scriptenv.vbs是本专栏所附带的一个脚本,它使用了多种方法来找出不同类型的数据,并加以显示。它创建了独立的函数来执行每个任务,这种 VBScript(以及几乎所有脚本语言)所提供的简便方法将一个复杂的脚本分成多个可管理的片断。 识别默认脚本主机 首先,GetWshHost() 函数确定了哪个脚本主机是当前的默认主机,Wscript.exe 或 Cscript.exe。这个函数对 Wscript 的 FullName 属性所返回的字符串进行分析,这个字符串返回了脚本主机可执行文件的完全路径,例如: C:\Windows\System32\CScript.exe 通过 VBScript 的 Right() 和 LCase() 函数,将整个字符串都转换成小写字母(消除比较中的大小写差异),然后提取该字符串右侧的11个字符,这11个字符正好是默认脚本主机的文件名。 下面这段简练的代码组成了该函数的核心部分(除了LCase()函数,将名称转换成全部小写字母): strFullName = WScript.FullName strWshHost = Right(strFullName, 11) WScript.Echo "Default script host: " & strWshHost 然后由子程序 ChangeToCscript 来检查默认脚本主机是否是 Wscript。如果是 Wscript,那么将做一件看上去很疯狂的事情,但实际上很有用。它将打开一个新的窗口,重新启动自己(Scriptenv.vbs)。这次是在 Cscript 中进行运行,然后终止原有的那个版本(这个从 Wscript 的更改在第一个版本关闭后才会生效)。为什么要这样做呢?在 Wscript 中运行脚本将需要在近 10 个弹出窗口上点击“确定”,来阅读信息。(而且,每次点击消息框后,数据会从视图中消失。)现在,脚本将强迫自己在 CScript 中运行,使你不会收到大量消息框的骚扰。而且,在脚本完全结束后,所有的信息仍然显示在命令窗口中。下面是这段代码: If strWshHost = "wscript.exe" Then Set objShell = CreateObject("WScript.Shell") objShell.Run _ "%comspec% /k ""cscript //h:cscript&&cscript scriptenv.vbs""", _ MAXIMIZE_WINDOW If Err.Number <> 0 Then WScript.Echo "Error 0x" & hex(Err.Number) & " occurred. " & _ Err.Description & ". " & VbCrLf & _ "Could not temporarily change the default script host to Cscript." Err.Clear WScript.Quit End If WScript.Quit End If 注意: 不论你使用的是哪种脚本宿主,在你脚本中将使用的对象就被称为 WScript。 识别在计算机上安装的 Windows版本 如果你需要了解在一台计算机上运行的是什么操作系统和版本,你可以打开“我的电脑”的系统属性对话框,在其常规选项卡的右上角就能够找到这些信息。但是如果我们需要在脚本中使用这些信息时应该怎么做呢? 注意: 为什么你需要了解在一台计算机上运行的是什么操作系统和版本呢?例如,你可以在 Windows 98 计算机中安装 WSH 5.6,你也可以将它安装在 Windows 2000 计算机上。但是,在 Windows 98 计算机上安装 WSH 5.6 所需的安装文件与在 Windows 2000 计算机上安装 WSH 5.6 的并不相同。因此在你开始升级之前,你需要了解你所处理的是哪个操作系统。 WMI 提供了一个Win32_OperatingSystem类 ,它能够让你获取有关操作系统名称、版本和服务包等信息,另外还包括日期、语言和序列号等 50 多种其他属性。 要简单地在屏幕上显示操作系统的名称和版本,你可以使用下列代码: Set objWMIService = GetObject("winmgmts:" & _ "{impersonationLevel=impersonate}!\\.\root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery _ ("SELECT * FROM Win32_OperatingSystem") For Each objOperatingSystem in colOperatingSystems Wscript.Echo "OS Name: " & objOperatingSystem.Caption Wscript.Echo "Version: " & objOperatingSystem.Version Next 当你在CScript中运行该脚本时,你可以获得下面所示的类似信息: OS Name: Microsoft Windows XP Professional Version: 5.1.2600 这个代码示例调用了 GetObject 来绑定到 WMI 的 root\cimv2 命名空间,这是 Win32_OperatingSystem 类所处的位置。然后使用以 WMI 查询语言(WQL)查询(类似于SQL)作为参数的 ExecQuery 方法来返回计算机上所有操作系统的信息,最后显示名称和版本号。 Scriptenv.vbs 将类似的代码嵌入到 GetOSVer() 函数中,该函数能够将一个代表操作系统版本的唯一整数返回到脚本的主体部分。 但是,Win32_OperatingSystem 并不能为较早版本的操作系统提供唯一的数值。因此 Scriptenv.vbs 使用了其中的两个属性 OSType 和 Version,并使用嵌套的 Select Case 语句来生成一个整数 intOSVer,在脚本中加以使用。Select Case 是 VBScript 中根据大量规则做出决策的方法,它能够处理比使用 If...Then...Else If...Else...End If 更多的选择。下面的示例中给出了这个代码的简化版。 Set objWMIService = GetObject("winmgmts:" & _ "{impersonationLevel=impersonate}!\\.\root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery _ ("Select * from Win32_OperatingSystem") For Each objOperatingSystem In colOperatingSystems intOSType = objOperatingSystem.OSType strOSVer = Left(objOperatingSystem.Version, 3) Next Select Case intOSType Case 16 'Windows 95 intOSVer = 1 Case 17 'Windows 98 intOSVer = 2 Case 18 Select Case strOSVer Case 4.0 intOSVer = 4 'Windows NT 4.0 Case 5.0 intOSVer = 5 'Windows 2000 Case 5.1 intOSVer = 6 'Windows XP Case 5.2 intOSVer = 7 'Windows Server 2003 Case Else intOSVer = 0 'Older or newer version End Select Case Else intOSVer = 0 'Older or newer version End Select 注意: Win32_OperatingSystem.OSType 和 .Version 无法为 Windows Millennium 提供一个数值。 接下来,这个脚本将获取WSH、WMI和ADSI的版本,并与适用于特定操作系统的最新版本进行比较。 识别计算机中所安装的 WSH、WMI 和 ADSI 的版本 GetWSHVer 函数将代表操作系统版本的整数和代表默认脚本主机(现在是 Cscript)的字符串作为参数。它使用 WSH 内建的属性来显示默认脚本主机,其路径以及 WSH Version 和 BuildVersion 属性。然后它将这些属性与操作系统进行比较,确定 WSH 的版本是否对于这个操作系统是最新的,然后返回布尔值True(如果是最新的)和False(如果不是最新的)。在你剔除错误处理和比较代码之后,这个函数的核心部分是这样的: WScript.Echo _ "WSH Path: " & WScript.FullName & VbCrLf & _ "WSH Version: " & WScript.Version & VbCrLf & _ "WSH Build Version: " & WScript.BuildVersion & VbCrLf 为了检查 WMI 版本,GetWMIVer 函数使用类似于 GetWSHVer 的方法。但它仅使用一个参数:代表 OS 版本的整数。GetWMIVer 使用 Win32_WMISetting 类来获取机器上 WMI 设置的信息(将只有一个)。它显示了build 版本号以及默认的 WMI 脚本名称空间。然后它使用 If...Then...Else...End If 语句以及一个布尔逻辑树来比较这个类的 BuildVersion 属性和 OS 版本整数,确认这个版本是否是最新的。根据所得结果,它返回 True 或 False。 Scripting Guy技巧 诚然,在所有这些情况下,我们可以仅报告版本号,然后由你去阅读全部的返回数据,确定是否已经安装了最新、最好的脚本技术。但是,为什么不让脚本来为你完成这些工作呢?例如,假设你要在你所有的计算机上安装一个新的应用程序,或者至少在具有256 MB 或更多 RAM 的计算机上安装。与其获得一堆 RAM 值(128、256、128、512、1024、256),为什么不让脚本报告“内存足够”(如果 RAM 是 256 或更多)或者“内部不足”(如果 RAM 少于 256)呢?这需要你增加一小段代码,但却能减少以后大量的分析。(特别是你编写脚本,而其他人将使用它们时,这样做特别有用。) 你可以从下列脚本片断中获得基本的 WMI 信息: Set objWMIService = GetObject _ ("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") Set colWMISettings = objWMIService.ExecQuery _ ("Select * from Win32_WMISetting") For Each objWMISetting In colWMISettings Wscript.Echo _ "WMI Build Version: " & _ objWMISetting.BuildVersion & vbCrLf & _ "Default scripting namespace: " & _ objWMISetting.ASPScriptDefaultNamespace Next 使用 GetADSIVer 检查 ADSI 版本的函数比较复杂,它需要经过比前两个函数更多的转折才能获得所需要的信息。它使用内建的 WshShell 对象来读取两个注册表项目,并从结果中推出 ADSI 版本。然后它使用 ADSI 名称空间提供器来获得已安装的ADSI提供器的列表,另外它还使用了一些模块,使你能够访问不同协议和目录服务(例如 LDAP 和 NDS)的名称空间。最后,它使用类似于 GetWMIVer 中所使用的布尔逻辑树来比较 ADSI 版本和 OS 版本,并返回True或False。下面是其基本代码: Set objShell = CreateObject("WScript.Shell") strAdsiVer = _ objShell.RegRead("HKLM\SOFTWARE\Microsoft\Active Setup\Installed " & _ "Components\{E92B03AB-B707-11d2-9CBD-0000F87A369E}\Version") If strAdsiVer = vbEmpty Then strAdsiVer = _ objShell.RegRead("HKLM\SOFTWARE\Microsoft\ADs\Providers\LDAP") If strAdsiVer = vbEmpty Then strAdsiVer = "ADSI is not installed." Else strAdsiVer = "2.0" End If ElseIf Left(strAdsiVer, 3) = "5,0" Then If intOSVer = 5 Then strAdsiVer = "5.0.2195" ElseIf intOSVer = 6 Then strAdsiVer = "5.1.2600" ElseIf intOSVer = 7 Then strAdsiVer = "5.2.3790" End If End If WScript.Echo "ADSI Version: " & strAdsiVer & VbCrLf If strAdsiVer <> "ADSI is not installed." Then Set colProvider = GetObject("ADs:") Wscript.Echo "ADSI Providers" & VbCrLf & _ "--------------" For Each objProvider In colProvider Wscript.Echo objProvider.Name Next Wscript.Echo End If 最后,子程序 ListUpToDate 将 GetWSHVer、GetWMIVer 和 GetADSIVer 所返回的布尔值作为参数,将它们经过嵌套的 If...Then...Else 循环的处理。每个循环或者告诉你该技术的版本是最新的,或者告诉你应该安装更新的版本。 储备脚本资源你已经可以开始庆祝了,但是为了使你的系统管理脚本更具生产力,还有几个步骤。有些资料非常有用,它们(或者是指向它们 URL 的链接)应该被保存在你的工作站中。下面的 “Microsoft系统管理脚本资源” 和 “第三方系统管理脚本站点” 中列出了其中的一部分。 Microsoft 系统管理脚本资源TechNet脚本中心 Windows 系统管理脚本的服务中心 http://www.microsoft.com/technet/community/scriptcenter/default.mspx Windows 2000 脚本指南 TechNet - 完全联机内容 MS Press 站点 - 如何购买书籍 http://www.microsoft.com/mspress/books/6417.asp 我们所知的最便宜的技术书籍电子零售商 Scriptomatic 帮助你编写 WMI 脚本的指导性协助 http://www.microsoft.com/technet/community/scriptcenter/tools/wmimatic.mspx Scripting Guy 的广告 很快推出的 Script Center:全新、超酷的 Scriptomatic 2.0! EzAdScripto 帮助你编写 ADSI 脚本的指导性协助 http://www.microsoft.com/technet/community/scriptcenter/tools/admatic.mspx MSDN 脚本诊所 许多高级脚本文章。 http://msdn.microsoft.com/library/en-us/dnclinic/html/scripting01142003.asp MSDN 中的 Windows 脚本主页 有关 VBScript、Jscript、WSH、Script Runtime 和其他脚本组件的文档。 http://msdn.microsoft.com/scripting/ WMI SDK 通过 MSDN 站点在线提供 http://msdn.microsoft.com/library/en-us/wmisdk/wmi/wmi_start_page.asp 下载(平台 SDK 的一部分) http://www.microsoft.com/msdownload/platformsdk/sdkupdate/default.htm 在左栏 “Windows SDK” 中选择 "WMI SDK"。 WMI 工具 WMI CIM 工作室、WMI 对象浏览器、WMI 事件注册工具和 WMI 事件查看器 ADSI SDK 通过 MSDN 站点在线提供 http://msdn.microsoft.com/library/en-us/netdir/adsi/active_directory_service_interfaces_adsi.asp MSN Windows 脚本社区 http://groups.msn.com/WindowsScript/_homepage.msnw?pgmarket=en-us 新闻组 News server: news.microsoft.com
第三方系统管理脚本站点Desktop Engineer 的 Junk Drawer Windows Scripting Solutions Journal 技术下载Windows Script 5.6 下载 包括 VBScript 5.6、JScript 5.6、Windows Script Host 5.6 以及 Windows Script Runtime 5.6。 http://msdn.microsoft.com/downloads/list/webdev.asp 适用于 Windows 2000 和 XP 这个下载包括一个比 Windows XP 中所附带产品更新的 Windows Script 5.6 build (8515)。 适用于 Windows 98、Millennium 和 NT 4.0。 所有 Windows Script 5.6 组件的文档 WMI CORE 1.5 下载 适用于 Windows NT 4.0 适用于 Windows 95 和 98 适用于 Windows NT 4.0 的 Active Directory 客户端扩展 这些客户端扩展也可以安装在 Windows 95 和 98 上。 http://www.microsoft.com/windows2000/server/evaluation/ news/bulletins/adextension.asp 要了解“脚本故事”专栏的列表和其他信息,请点击此处。 |