首 页文章中心下载中心娱乐八卦本站论坛拜仁联盟球迷社区博客日志建站服务域名抢注繁體中文
设为首页
加入收藏
联系我们
E-mail:WebMaster#fcbu.com
载入中…
当前位置:站长天下 -> 编程讨论 -> WSH教程

WSH教程


收集:TTXS(Fcbu.Com)   来源:互联网   时间:2006-06-25 

WSH简介
1.概述
虽说不是只有NT5才有WSH,但NT5(WINDOWS2000)一定有WSH的。实际上,你在WIN98 PWS里,或者NT4 IIS4里,你就能找到WSH。
WSH是微软脚本技术系列中的一种,简单讲,就是提供了一种脚本环境,在这个环境中,预定义了一些对象,同时也可以使用COM里的其他对象。他使用一种脚本引擎来对脚本解释执行,微软自己支持VBSCRIPT和JSCRIPT,第三方也可以开发自己的脚本引擎。
具体点,就是你先编好一些脚本文件(微软自带例子若干,后缀.vbs或 .js),然后用一个程序对他解释执行,这个程序就叫Windows Scripting Host,程序的名字是Wscript.exe(或者命令行的Cscript.exe),你可以查看一下你的机器里有没有这两个文件,就知道有没有WSH了。这非常像批处理文件,只不过文件里不是命令行,而是脚本语言写的脚本。同时,他完成的功能也非常像批处理文件,只不过多了些控制。
我主要用WSH来完成一些繁琐的、通常需要我反复操作才能完成的任务,比如给大量目录设置ACL,或者创建大量的目录等等。虽然这也可以编写VB或VC程序来实现,不过比起脚本来,实在麻烦,至少需要那么大的环境,而脚本只要一个写字板就成。用WSH技术来配置服务器,包括创建用户,创建邮箱,创建目录,创建站点,设置ACL,设置FrontPage ServerExtention,我将在WSH实用讲座中分几讲详细介绍。
2.组成
WSH自带的几个内置对象包括:
1.由 Wscript.exe 提供的对象
Wscript 作为 Wscript 公开给脚本引擎。
WshArguments 未公开;通过 Wscript.Arguments 属性访问。
2.由 WSHom.Ocx 提供的对象。
WshShell 自动对象。
ProgID 是 Wscript.WshShell。
WshNetwork 自动对象。ProgID 是 Wscript.WshNetwork。
WshShortcut 未公开;通过 WshShell.CreateShortcut 方法访问。
WshUrlShortcut 未公开;通过 WshShell.CreateShortcut 方法访问。
WshCollection 未公开;通过 WshNetwork.EnumNetworkDrives 或 WshNetwork.EnumPrinterConnection 方法访问。
WshEnvironment 未公开;通过 WshShell.Environment 属性访问。
WshSpecialFolders 未公开;通过 WshShell.Folder 属性访问。
他们主要可以完成环境变量的获取,网络登陆,驱动器映射,快截方式创建,程序加载,特殊文件夹(如系统文件夹)信息获取等功能。
如果你的系统里支持ADO等COM部件,你同样可以使用。
3.示例
下面这个例子演示打开写字板查看文本文件,同时创建一个文本文件并写入一段话,你可以把他拷贝到写字板中,然后以.vbs为后缀存盘,之后双击他,
';test.vbs
Set WshShell = Wscript.CreateObject("Wscript.Shell")
WshShell.Run ("notepad " & Wscript.ScriptFullName)
';上面用SHELL对象启动程序
Set fs = Wscript.CreateObject("Scripting.FileSystemObject")
Set a = fs.CreateTextFile("c:\testfile.txt", True)
a.WriteLine("这是一个测试。")
a.Close
';用COM对象Scripting.FileSystemObject操作文本文件
4.哪里找到学习材料
在PWS和IIS4的产品文档里有非常齐全的WSH文档,建议大家先学习学习,了解了解WSH的基础知识。
补充:
WSH--这个在词典中都很难找寻的名词,对许多朋友来讲也许还比较陌生。但正是WSH ,使 Windows 操作系统具备了更为强大的功能。它让我们在使用系统时拥有了许多的便利,但同时,也让我们的电脑遭遇了不少的麻烦。下面,就让我们一步步走进 WSH 的神秘世界,共同评判它的是非功过。
一、WSH 是什么?
WSH,是“Windows Scripting Host”的缩略形式,其通用的中文译名为“Windows 脚本宿主”。对于这个较为抽象的名词,我们可以先作这样一个笼统的理解:它是内嵌于 Windows 操作系统中的脚本语言工作环境。
Windows Scripting Host 这个概念最早出现于 Windows 98 操作系统。大家一定还记得 MS-Dos 下的批处理命令,它曾有效地简化了我们的工作、带给我们方便,这一点就有点类似于如今大行其道的脚本语言。但就算我们把批处理命令看成是一种脚本语言,那它也是 98 版之前的 Windows 操作系统所唯一支持的“脚本语言”。而此后随着各种真正的脚本语言不断出现,批处理命令显然就很是力不从心了。面临这一危机,微软在研发 Windows 98 时,为了实现多类脚本文件在 Windows 界面或 Dos 命令提示符下的直接运行,就在系统内植入了一个基于 32 位 Windows 平台、并独立于语言的脚本运行环境,并将其命名为“Windows Scripting Host”。WSH 架构于 ActiveX 之上,通过充当 ActiveX 的脚本引擎控制器,WSH 为 Windows 用户充分利用威力强大的脚本指令语言扫清了障碍。
再具体一点描述:你自己编写了一个脚本文件,如后缀为 .vbs 或 .js 的文件,然后在 Windows 下双击并执行它,这时,系统就会自动调用一个适当的程序来对它进行解释并执行,而这个程序,就是 Windows Scripting Host,程序执行文件名为 Wscript.exe (若是在命令行下,则为 Cscript.exe)。
WSH 诞生后,在 Windows 系列产品中很快得到了推广。除 Windows 98 外,微软在 Internet Information Server 4.0、Windows Me、Windows 2000 Server,以及 Windows 2000 Professional 等产品中都嵌入了 WSH。现在,早期的 Windows 95 也可单独安装相应版本的 WSH。(附:各种版本 WSH 的安装程序可以从 http://msdn.microsoft.com/scripting 站点下载)。
二、WSH 有什么用?
WSH 的设计,在很大程度上考虑到了“非交互性脚本(noninteractive scripting)”的需要。在这一指导思想下产生的 WSH,给脚本带来非常强大的功能,例如:我们可以利用它完成映射网络驱动器、检索及修改环境变量、处理注册表项等工作;管理员还可以使用 WSH 的支持功能来创建简单的登陆脚本,甚至可以编写脚本来管理活动目录。
而事实上,上述功能的实现,均与 WSH 内置的多个对象密切相关,这些内置对象肩负着直接处理脚本指令的重任。因此,我们也可以通过了解 WSH 的内置对象来探寻 WSH 可以实现的功能。
WSH 共有 14 个内置对象,它们各自有着明确分工。具体而言,位于最底部的 Wscript ,主要作用是提取命令行变量,确定脚本文件名,确定 WSH 执行文件名(wscript.exe 还是 cscript.exe),确认 host 版本信息,创建、关连及分离 COM 对象,写入事件,按程序结束一个脚本文件的运行,向默认的输出设备(如对话框、命令行)输出信息等;WshArguments 的作用是获取全部的命令行变量; WshNamed 负责获取指定的命令行参数集;WshUnnamed 负责获取未经指定的命令行参数集;WshNetwork 的主要作用是开放或关闭网络共享,连接或断开网络打印机,映射或取消网络中的共享,获取当前登陆用户的信息;WshController 可以创建一个远程脚本对象;WshRemote 可以实现网络中对计算机系统的远程管理,也可按计划对其它程序/脚本进行处理;WshRemote Error 的作用在于:当一个远程脚本(WshRemote 对象)因脚本错误而终止时,获取可用的错误信息;WshShell 主要负责程序的本地运行,处理注册表项、创建快捷方式、获取系统文件夹信息,处理环境变量;WshShortcut 主要用于按计划创建快捷方式;WshSpecialfolders 用于获取任意一个 Windows 特殊文件夹的信息;WshURLShortcut 用于按程序要求创建进入互联网资源的快捷方式;WshEnvironment 用于获取任意的环境变量(如 WINDIR, PATH, 或 PROMPT);WshScriptExec 用于确定一个脚本文件的运行状态及错误信息。
在这些内置对象的帮助下,我们就可以利用 WSH 充分发挥 VBScript 及 JScript 等脚本的强大威力,极大地提高我们的工作效率。
第一讲 获取机器的网络属性配置
其实就是读注册表,不过如果能获得机器的IP配置等信息,以后配置IIS时就简单了。下面的脚本读出机器的所有可用IP地址,子网掩码,却省网关等信息:
Option Explicit
Dim WSHShell
Dim sNic, sMan
Dim Gateway
Dim IPAddress
Dim SubnetMask
Dim i
Dim sTcpipRegKey
Dim bIsDHCP
Set WSHShell = CreateObject("WScript.Shell")
sNic = WSHShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards\1\ServiceName")
If sTcpipRegKey <> "Microsoft" And Err.Number = 0 Then
sTcpipRegKey = "HKLM\SYSTEM\CurrentControlSet\Services\" & sNic & "\Parameters\Tcpip\"
bIsDHCP = WSHShell.RegRead(sTcpipRegKey & "EnableDHCP")
If bIsDHCP Then
Gateway = WSHShell.RegRead(sTcpipRegKey & "DhcpDefaultGateway")
IPAddress = WSHShell.RegRead(sTcpipRegKey & "DhcpIPAddress")
SubnetMask = WSHShell.RegRead(sTcpipRegKey & "DhcpSubnetMask")
MsgBox ("DefaultGateway: " & Gateway(0) & Chr(10) & Chr(13) & "IPAddress: " & IPAddress & Chr(10) & Chr(13) & "SubnetMask: " & SubnetMask)
Else
Gateway = WSHShell.RegRead(sTcpipRegKey & "DefaultGateway")
IPAddress = WSHShell.RegRead(sTcpipRegKey & "IPAddress")
SubnetMask = WSHShell.RegRead(sTcpipRegKey & "SubnetMask")
For i=0 to Ubound(IPAddress)-1
MsgBox ("DefaultGateway: " & Gateway(0) & Chr(10) & Chr(13) & "IPAddress: " & IPAddress(i) & Chr(10) & Chr(13) & "SubnetMask: " & SubnetMask(i))
Next
End If
End If
说明:机器的网络配置保存在注册表里,网卡项目下面,所以首先必须知道网卡的名字。然后取注册表数据,IP地址和子网掩码都是数组形式(其实注册表里保存的是二进制数据,VBSCRIPT帮我们转换了)。在WSH里读注册表非常的简单,具体请看上面的程序。
第二讲 创建用户、目录和站点
本讲将使用到ADSI,即活动目录服务接口.可以到15Seconds.com找到一些相关的资料.
1.创建用户
下面这段代码在独立服务器white上创建用户user1,初始口令user1,用到了ADSI.
Dim Username,UserPass
Dim oDomain,oUser
Username = "user1"
UserPass = "user1"
Set oDomain = GetObject("WinNT://white")
Set oUser = oDomain.Create ("user", UserName)
If (err.number = 0) Then
oUser.SetInfo
oUser.SetPassword UserPass
oUser.SetInfo
Else
WScript.Echo "创建用户" & UserName & "出错!"
End If
Set oUser = Nothing
Set oDomain = Nothing
2.创建目录
使用FileSystemObject创建目录:
Dim FsObject
Dim tmpFolder
Set FsObject = WScript.CreateObject("Scripting.FileSystemObject")
tmpFolder = "D:\userdate\user1"
If Not FsObject.FolderExists(tmpFolder) Then
FsObject.CreateFolder(tmpFolder)
If Err.Number<>0 Then
WScript.Echo "创建目录" & tmpFolder & "失败!"
End If
End If
注意在创建目录前,先检查了目录是否存在,如果存在,则不用创建了.
3.创建站点
下面这个子程序负责创建一个WWW站点,各个参数的意义为:站点IP地址,站点根目录,站点说明,主机名,端口号,计算机名(一搬为LOCALHOST),是否立即启动,匿名访问时所使用的帐号,匿名访问时所用帐号的口令,LOG文件的目录.
函数返回所建站点在IIS中的序号(在IIS中,所有站点依次编号,第一个为1).
一个调用示例:siteid = ASTCreateWebSite("10.1.3.122","d:\userdata\user1","www_user1","","80","LocalHost",True,"IUSR_user1","8iui%#","D:\Logfiles")
Function ASTCreateWebSite(IPAddress, RootDirectory, ServerComment, HostName, PortNum, Computer, Start,AnonymousUserName,AnonymousUserPass,LogFileDirectory)
Dim w3svc, WebServer, NewWebServer, NewDir
Dim Bindings, BindingString, NewBindings, Index, SiteObj, bDone
On Error Resume Next
Err.Clear
Set w3svc = GetObject("IIS://" & Computer & "/w3svc")
If Err.Number <> 0 Then
WScript.Echo "无法打开: "&"IIS://" & Computer & "/w3svc" & VbCrlf & "程序将退出."
WScript.Quit (1)
End If
BindingString = IpAddress & ":" & PortNum & ":" & HostName
For Each WebServer in w3svc
If WebServer.Class = "IIsWebServer" Then
Bindings = WebServer.ServerBindings
If BindingString = Bindings(0) Then
WScript.Echo "IP地址冲突:" & IpAddress & ",请检测IP地址!." & VbCrlf & "取消创建本站点。"
Exit Function
End If
End If
Next
Index = 1
bDone = False
While (Not bDone)
Err.Clear
Set SiteObj = GetObject("IIS://"&Computer&"/w3svc/" & Index)
If (Err.Number = 0) Then
Index = Index 1
Else
Err.Clear
Set NewWebServer = w3svc.Create("IIsWebServer", Index)
If (Err.Number <> 0) Then
Index = Index 1
Else
Err.Clear
Set SiteObj = GetObject("IIS://"&Computer&"/w3svc/" & Index)
If (Err.Number = 0) Then
bDone = True
Else
Index = Index 1
End If
End If
End If
If (Index > 10000) Then
WScript.Echo "看起来不能创建站点,正在创建的站点的序号为: "&Index&"." & VbCrlf & "取消创建本站点。"
Exit Function
End If
Wend
NewBindings = Array(0)
NewBindings(0) = BindingString
NewWebServer.ServerBindings = NewBindings
NewWebServer.ServerComment = ServerComment
NewWebServer.AnonymousUserName = AnonymousUserName
NewWebServer.AnonymousUserPass = AnonymousUserPass
NewWebServer.KeyType = "IIsWebServer"
NewWebServer.FrontPageWeb = True
NewWebServer.EnableDefaultDoc = True
NewWebServer.DefaultDoc = "Default.htm, Default.asp, Index.htm, Index.asp"
NewWebServer.LogFileDirectory = LogFileDirectory
NewWebServer.SetInfo
Set NewDir = NewWebServer.Create("IIsWebVirtualDir", "ROOT")
NewDir.Path = RootDirectory
NewDir.AccessRead = true
NewDir.AppFriendlyName = "应用程序" & ServerComment
NewDir.AppCreate True
NewDir.AccessScript = True
Err.Clear
NewDir.SetInfo
If (Err.Number = 0) Then
Else
WScript.Echo "主目录创建时出错."
End If
If Start = True Then
Err.Clear
Set NewWebServer = GetObject("IIS://" & Computer & "/w3svc/" & Index)
NewWebServer.Start
If Err.Number <> 0 Then
WScript.Echo "启动站点时出错!"
Err.Clear
Else
End If
End If
ASTCreateWebSite = Index
End Function
下面函数创建FTP站点:
Function ASTCreateFtpSite(IPAddress, RootDirectory, ServerComment, HostName, PortNum, Computer, Start,LogFileDirectory)
Dim MSFTPSVC, FtpServer, NewFtpServer, NewDir
Dim Bindings, BindingString, NewBindings, Index, SiteObj, bDone
On Error Resume Next
Err.Clear
Set MSFTPSVC = GetObject("IIS://" & Computer & "/MSFTPSVC")
If Err.Number <> 0 Then
WScript.Echo "无法打开: "&"IIS://" & Computer & "/MSFTPSVC" & VbCrlf & "程序将退出."
WScript.Quit (1)
End If
BindingString = IpAddress & ":" & PortNum & ":" & HostName
For Each FtpServer in MSFTPSVC
If FtpServer.Class="IIsFtpServer" Then
Bindings = FtpServer.ServerBindings
If BindingString = Bindings(0) Then
WScript.Echo "IP地址冲突:" & IpAddress & ",请检测IP地址!." & VbCrlf & "取消创建本站点。"
Exit Function
End If
End If
Next
Index = 1
bDone = False
While (Not bDone)
Err.Clear
Set SiteObj = GetObject("IIS://"&Computer&"/MSFTPSVC/" & Index)
If (Err.Number = 0) Then
Index = Index 1
Else
Err.Clear
Set NewFtpServer = MSFTPSVC.Create("IIsFtpServer", Index)
If (Err.Number <> 0) Then
Index = Index 1
Else
Err.Clear
Set SiteObj = GetObject("IIS://"&Computer&"/MSFTPSVC/" & Index)
If (Err.Number = 0) Then
bDone = True
Else
Index = Index 1
End If
End If
End If
If (Index > 10000) Then
WScript.Echo "看起来不能创建站点,正在创建的站点的序号为: "&Index&"." & VbCrlf & "取消创建本站点。"
Exit Function
End If
Wend
NewBindings = Array(0)
NewBindings(0) = BindingString
NewFtpServer.ServerBindings = NewBindings
NewFtpServer.ServerComment = ServerComment
NewFtpServer.AllowAnonymous = False
NewFtpServer.AccessWrite = True
NewFtpServer.AccessRead = True
NewFtpServer.DontLog = False
NewFtpServer.LogFileDirectory = LogFileDirectory
NewFtpServer.SetInfo
Set NewDir = NewFtpServer.Create("IIsFtpVirtualDir", "ROOT")
NewDir.Path = RootDirectory
NewDir.AccessRead = true
Err.Clear
NewDir.SetInfo
If (Err.Number = 0) Then
Else
WScript.Echo "主目录创建时出错."
End If
If Start = True Then
Err.Clear
Set NewFtpServer = GetObject("IIS://" & Computer & "/MSFTPSVC/" & Index)
NewFtpServer.Start
If Err.Number <> 0 Then
WScript.Echo "启动站点时出错!"
Err.Clear
Else
End If
End If
ASTCreateFtpSite = Index
End Function
第三讲 创建邮箱
创建邮箱,情况就复杂了,因为你可能采用不同的电子邮件服务器.有些把邮箱信息放在文本文件里,有些把信息放在注册表里,有些提供ADSI接口,所以,得根据具体情况来定. 
对于用户邮箱信息放在文本文件里的,可以直接操作文本文件,下面是一段写文本文件的代码示例:
Dim fs
Dim fw
Set fs = WScript.CreateObject("Scripting.FileSystemObject")
Set fw = fs.CreateTextFile("c:\users.dat")
fw.WriteLine "user1,user1@abc.com,,,"
对于用户信息放在注册表里的,可以用WSH直接操作注册表,从而完成邮箱的创建.比如IMAIL,他的用户信息就放在HKEY_localmacine\SoftWare\IPswitch\domain\下的.唯一麻烦的邮箱的初始口令,我们不知道他的加密算法.所以只能先手工创建一个邮箱,然后采用一个固定的口令,看他加密后是多少,我们的脚本在创建别的邮箱时也使用它.这样的问题是,我们必须告诉用户,他们必须在今后修改口令,否则是不安全的.
Exchange Server提供ADSI接口,创建邮箱就方便了.而且他的邮箱可以与NT的域用户同步.下面是一段示例代码:
objContainer = GetObject("LDAP://SERVERNAME/o=OrgName/ou=SiteName/cn=Recipients")
objUser = objContainer.Create("Remote-Address", "cn=CustRecip")
objUser.cn = "CustRecip"
objUser.Put "Target-Address", "SMTP:CustRecip@msn.com"
objUser.Put "Internet-Encoding", 1310720objUser.UID = "CustRecip"
objUser.textEncodedORaddress = "c=US;a= ;p=DOIT;o=CDO;s=CustRecip;"
objUser.Mail = "CustRecip@msn.com"
objUser.Put "otherMailbox", "MS:OrgName/SiteName/CustRecip"
objUser.Put "Replication-Sensitivity", 20
objUser.Put "MAPI-Recipient", False
objUser.SetInfo
WScript.Echo objUser.cn
For i = 1 ToobjUser.PropertyCount
Set vProp = objUser.Next
WScript.Echo vProp.Name
Next
注:由于我现在没有Exchange Server做实验,所以上面这段代码未曾测试过,如果大家有问题,请到他的原出处寻求解决.
这段脚本,稍加修改,也可以用在ASP中.
第四讲 配置目录权限
即配置目录的ACL,至于该如何配置权限,才能让你的服务器是安全的,那得根据你自己的客观实际了,而且,这也是商业秘密。我这里只是说明用脚本实现的方法。
有两种方法可以完成这个任务(也许还有其他的方法),一种是采用第三方组件(我经常使用的是NTAccess.Permission,这是个要MONEY的东东,但是我把系统时间改成1997年4月25日,这样,它就不认为我过期了,等执行完脚本,我再改回1999年4月25日,呵呵。另外一个是SA的FILEMANAGER,功能强大,但体积也大);另一种是在WSH里调用NT的命令行cacls.exe,它的用法为(摘自NT的帮助文件):
Cacls
显示或修改文件访问控制表(ACL)。
cacls filename [/t> [/e> [/c> [/g user:perm> [/r user [...>> [
/p user:perm [...>> [/d user [...>>
参数
filename
显示文件或指定文件的访问控制表 ACL 。
/t
在当前目录及所有子目录下改变指定文件的 ACL 。
/e
编辑 ACL,但不替换。
/c
继续更改 ACL,并忽略错误。
/g user:perm
将访问权授予指定用户。Perm 可以是:
r 读取
c 更改(写)
f 完全控制
/r user
撤消指定用户的访问权。 /p user:perm
还原指定用户的访问权。Perm 可以是:
n 无
r 读取
c 更改(写)
f 完全控制
/d user
拒绝指定用户的访问。
可以在一个命令中指定多个文件或用户。
使用NTAccess.Permission的一个例子如下:
Rem ----------------------------
Rem 定义常量
Rem ----------------------------
const ntpNoAccess = 1
const ntpRead = 2
const ntpWrite = 4
const ntpExecute = 8
const ntpDelete = 16
const ntpPermissions= 32
const ntpOwnership = 64
const ntpFileRights = 1
const ntpDirRights = 2
ntpChange = ntpRead ntpWrite ntpExecute ntpDelete
ntpFull = ntpChange ntpPermissions ntpOwnership
Rem -----------------------------------------------
Rem 开始设置
Rem -----------------------------------------------
WScript.Echo "开始设置."
Set ntp = CreateObject("NTAccess.Permissions")
set acl = ntp.File("d:\test", true )
'; add No Access entries first
acl.Add "Users" , ntpNoAccess, ntpFileRights
acl.Add "Users" , ntpNoAccess, ntpDirRights
'; now delete any ACE';s we want to remove
acl.Delete "Everyone", ntpFileRights
acl.Delete "Everyone", ntpDirRights
'; now add any other new ACE';s
acl.Add "Administrators", ntpFull, ntpFileRights
acl.Add "Administrators", ntpFull, ntpDirRights
acl.Add "white", ntpChange, ntpFileRights
acl.Add "white", ntpChange, ntpDirRights
'; finally remember to call save
acl.save
WScript.Echo "已经完成设置!"
使用cacls的一个例子如下:
Set WshShell = Wscript.CreateObject("Wscript.Shell")
userdir = "d:\userdate"
username = "white"
argu = userdir & " /t /e /p " & username & ":f"
WshShell.Run ("c:\winnt\system32\cacls " & argu)
microsoft官方介绍:
Windows Scripting Host:脚本语言的通用脚本主机(全文)
摘要
Windows Scripting Host (WSH) 是一个用于 32 位 Windows 平台的独立于语言的脚本主机。Windows Scripting Host 将集成到 Microsoft® Windows® 操作系统的更新程序和新版本中。
引言
Windows Scripting Host (WSH) 是一个独立于语言的脚本主机,用于 32 位 Microsoft®Windows® 操作系统平台上。Microsoft 同时给 Visual Basic® Script 以及 Java Script 脚本引擎提供了 WSH。Microsoft 预计,其它软件公司将会给其它一些语言(如 Perl、TCL、REXX 以及 Python)提供 ActiveX® 脚本引擎。
WSH 可以从基于 Windows 的主机运行 (Wscript.exe),也可以从基于命令行解释器的主机运行 (Cscript.exe)。
本文将讲述:
WSH 的用途。
如何安装 WSH。
如何使用 WSH。
Windows Scripting Host 已集成到 Windows 98、Internet Information Server 4.0 版, Windows 2000 Server 以及 Windows 2000 Professional 中。它也可用于 Windows 95 操作系统。
Windows Scripting Host 的优点
Windows Scripting Host (WSH) 给 32 位 Windows 平台提供了使用简便、功能强大和变化灵活的脚本。
过去,Windows 操作系统支持的唯一正宗的脚本语言是 MS-DOS® 命令语言。尽管 MS-DOS 速度很快,且很小巧,但与 Visual Basic Script 和 Java Script 相比,其功能有限。现在,ActiveX 脚本体系结构可让用户能使用强大的诸如 Visual Basic Script 和 Java Script 之类的脚本语言,同时也支持 MS-DOS 命令脚本。
ActiveX 脚本体系结构允许使用诸如 VB Script、Java Script 及 Perl 等语言编写功能强大的脚本。Microsoft 现为在 Windows 平台上运行这些脚本语言提供三种主机:
Microsoft Internet Explorer
Internet Information Server (IIS)
Windows Scripting Host (WSH)
Internet Explorer 能使脚本在客户计算机上从 HTML 页内运行。
Internet Information Server 现支持 Active Server Page,它能使脚本在 Web 服务器上运行;换句话说,它在 Internet 或 Intranet 上启用服务器端脚本。
Windows Scripting Host 能使脚本直接在 Windows 桌面或命令控制台上执行,无须将脚本嵌入到 HTML 文档中。脚本可以直接从桌面(通过点击脚本文件)或命令控制台上运行。WSH 提供了一个内存消耗少的脚本主机,非常适合于非交互脚本,如登录脚本、管理脚本等等。
WSH 安装
要使用 Windows Scripting Host,必须安装 Microsoft Internet Explorer 3.0 版或更高版本。WSH 依赖与 Internet Explorer 3.0 或更高版本一起提供的 Visual Basic Script 和 Java Script 引擎。WSH 作为 Windows 98、Windows 2000 以及 Internet Information Server 4.0 的一部分安装的。在 Windows 95 中安装,则需要单独的安装程序。
要在基于 Windows 95 的系统上安装 WSH,如还未安装 Microsoft Internet Explorer 3.0 版或更高版本,则必须安装。如没有 Internet Explorer 3.0 或更高版本,请参见 Microsoft IE Web 页,网址是:http://www.microsoft.com/ie/ie.htm。
从 Microsoft 下载站点下载 WSH 安装程序,网址是:http://www.microsoft.com/msdownload/vbscript/scripting.asp。
使用基于命令的脚本主机运行脚本
Cscript.exe 使用以下语法:
cscript [host optionsU> [script name> [script options>
Host parameters(主机参数)启用或禁用各种 WSH 选项。主机参数前面有两条斜线 (//)。
script name(脚本名称)是脚本文件的名称;例如 CHART.VBS。
Script parameters(脚本参数)传递给脚本。脚本参数前面有一条斜线 (/)。
每个参数都是可选的;但是,不能指定脚本参数而不指定脚本。如果不指定参数,Cscript.exe 就会显示 Cscript.exe 语法,以及有效的主机参数。
Cscript.exe 支持以下主机参数:
参数 说明
//R 通过搜索注册的脚本引擎来注册脚本扩展名(.vbs、.js、.tcl)。
备注 当使用 //R 转移指令时,不需要提供脚本文件名。
//I 交互模式 (默认值,与 //B 相反)
//B 批处理模式。禁止脚本请求的任何非命令行控制台 UI。
//T:nn 超时(秒数)。脚本可运行的最长时间,默认值为 No limit(没有限制)。 此选项用来防止脚本执行时间过长;它设定一个计时器。当执行时间超过指定值,Cscript 就会使用 IActiveScript::InterruptThread 方法中断脚本引擎,并终止该进程。
备注 有一个回叫挂钩。如果调用超时,就调用 OnTimeOut 函数进行清理。尽管可能会产生无限循环,但使用此功能,还是利多弊少。

//logo 在执行时显示执行横幅标志(默认值 - 与 //NoLogo 相反)。
//nologo 执行时不显示执行横幅标志。
//C 将 Cscript.exe 作为运行脚本的默认应用程序。
//S 为这个用户(每个用户)保存当前命令行选项。
//® 显示命令用法(与不带参数运行相同)。
当安装 WSH 时,就会安装一些脚本示例。脚本示例放在 %windir%\WSamples 文件夹中(其中 %windir% 是 Windows 95 或 Windows 2000 文件夹)。
要运行 Chart.vbs
请转到 Windows 2000 或 Windows 95 命令提示符。
运行以下命令:
cscript //logo %windir%\wsamples\chart.vbs
cscript //nologo %windir%\wsamples\chart.vbs
使用基于 Windows 的脚本主机运行脚本
在 Windows 中使用 WSH 有三种方法运行脚本。可以:
在“我的电脑”、“资源管理器”和“查找”窗口中双击文件和图标。
使用 Windows“运行”命令。
运行 Wscript.exe。
当您使用 Wscript.exe 运行脚本时,您可以选择“始终使用 Windows Scripting Host 打开该文件”复选框,并在“WSH 属性”页上设置属性。
当运行脚本且选定了“始终使用 Windows Scripting Host 来打开文件”复选框时,对于带有正在运行的脚本的扩展名的文件,Wscript.exe 就成为运行这些文件的默认应用程序。例如,当您运行 Chart.vbs 时,如果选定了该复选框,Wscript.exe 就成为运行所有扩展名为 .vbs 的文件的默认应用程序。此复选框对 Cscript.exe //C 转移指令同样适用。
WSH 属性页提供以下选项:
属性 用途 CSCRIPT.EXE 的对应项
注册常见的脚本扩展名  通过搜索常见的注册脚本引擎,重新注册常见的脚本扩展名 (.vbs、.js、.tcl)。 //R
n 秒后终止脚本 指定脚本运行的最大秒数。(默认值是没有限制。) //T:nn
默认情况下,以下列模式运行脚本:交互/批处理 禁用或启用脚本的所有非命令行控制台 UI 请求。交互模式允许非命令行控制台 UI 请求。而批处理则不允许。 //I & //B
WSH 体系结构概述
Windows Scripting Host 用作 ActiveX 脚本引擎的控制器,其作用如同 Microsoft Internet Explorer。因为该脚本主机不是完全 Internet 浏览器,所以它比 Microsoft Internet Explorer 需要的内存少;因此,WSH 适于执行简单快速的任务。
该脚本主机按脚本引擎提供的 IActiveScriptParse::ParseScriptText 方法读取指定脚本文件内容并将其送到注册的脚本引擎。
[UploadFile=Scrpht01_1131001755.gif>
该脚本引擎并不使用 SCRIPT 标记(在 HTML 中使用),而使用文件的扩展名。因此,脚本编写者无须熟悉各种脚本引擎的确切 ProgID。此脚本主机维持了一种脚本扩展名与 ProgID 的对应关系,并使用 Windows 关联模式启动相应的引擎。

第五讲 从WSH脚本中运行程序
范例:
<HTML>
<HEAD><title>一个简单首页</title>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub Button1_onClick
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ipconfig"
End Sub
-->
</SCRIPT>
</HEAD>
<BODY>
<H3>一个简单首页</H3><HR>
<form><INPUT NAME="Button1" TYPE="BUTTON" value="单击此处"></form>
</BODY>
</HTML>
详解如下:
我们所收到的较为常见一个问题就是,如何从WSH脚本中运行程序。以下是摘自此类电子邮件的一个具有代表性的片断。
你们曾在Web广播中提到过两行可帮助你们运行某一外部程序的脚本代码。请问,你们能否提供有关代码的示例样本?
作为针对上述问题的答复,我们决定占用本专栏第一期的篇幅向您介绍从自行编制的脚本中运行外部程序的具体实现方式。若问您为何需要从脚本中运行外部程序?就请这样设想:命令行工具将允许您执行一整套特定任务,而批处理脚本则提供了所需逻辑线程,以便您用来将这些任务缝合成足以构建自定义解决方案的基本要素。但是,如果批处理脚本所提供的逻辑线程尚不具备足够强大的功能,亦或构建解决方案所需必要组件不能由命令行工具提供,又将如之奈何?而这恰恰是WSH脚本大显身手的用武之地。这种脚本将允许您针对由脚本编程语言(如VBScript)所提供的强大逻辑线程加以应用,并借助强大的工具手段(如WMI和ADSI)以及命令行工具和批处理脚本将您自己的任务解决方案付诸实施。
让我们立即着手编写一个示例脚本。事实上,我们应该在编写脚本之前,先确保具备一个用来保存这个脚本的物理位置。如果在您所使用的计算机上并不存在一个名为C:\Scripts的文件夹,就请返回根目录,并新建这个文件夹。当您完成上述工作后,应打开记事本或其它文本编辑器,并键入以下脚本代码,然后,使用RunIPConfig.vbs文件名将其保存至您的C:\Scripts文件夹。
Set objShell = CreateObject(“Wscript.Shell”)
objShell.Run “ipconfig”
在尝试运行刚刚生成的脚本之前,让我们先对其进行检查,并设法事先指出可能产生的运行结果。在这个脚本中存在着两个有助于我们预测运行结果的暗示。第一行代码中包括动词Create(生成,实际上是CreateObject),而第二行代码则包含动词Run(运行)。可见,这个脚本将有可能先生成某种被称作对象的东西,并随后运行某一特定程序。事实上,情况看上去更象是该脚本将运行一个文件名为ipconfig.exe的命令行工具。
以上预测的确与该脚本所产生的运行结果相符。该脚本首先生成一种被称作对象的东西。在这个示例中,脚本所生成的对象是Shell(WshShell)对象。您可将某一对象理解成类似于命令行工具的东西;而您的脚本则可借助它执行某一特定类型的任务。Shell对象将允许您从脚本中执行原本可在Windows命令解释程序内执行的任务--就像运行程序一样。
与命令行工具不同的是,您必须在开始对其加以应用之前,先行生成一个新对象。当生成该对象时,还应为它指定一个将在脚本其余部分中被用来对它进行引用的名称。在这个示例中,我们所使用的名称是objShell。当对象生成完毕并被赋予相关名称后,我们便可利用该对象执行相关任务,具体方法为:在对象名后加上一个圆点(.),并在圆点后加上所需完成的任务名称。这个例子中的任务名是Run。而Run则是众所周知的Shell对象方法。
现在,请打开一个命令行窗体,并导航至C:\Scripts文件夹。如需运行您刚刚编写的脚本,则请输入cscript RunIPConfig.vbs命令,并按回车键。您将看到一个窗体在屏幕上一闪而过,但该窗体所显示的内容却在您能够看清之前消失了!您可反复尝试运行该脚本,并试图破解消失在窗体中的信息。这也许是一件饶有兴味的事,但却可通过一种更加简便的方法完成。
为了便于您进行理解,我们必须针对在您运行命令行工具的同时所发生的事件给予关注。当您在命令行方式下输入ipconfig、并在键盘上敲击回车键时,便对命令解释程序发出了一个指令。而命令解释程序则将对您所输入的指令进行检查。如果您所输入的命令代表着一个有效程序,那么,命令解释程序便会为您运行该程序。如果您所输入的命令并不代表有效程序,那么,命令解释程序则将通过显示错误信息的方式就有关情况向您进行告知。基于Windows NT操作系统的命令解释程序是Cmd.exe。而Windows 9x操作系统中的命令解释程序则是Command.exe。
此时此刻,上述脚本中的objShell.Run “ipconfig”命令将在其运行ipconfig程序的同时绕过命令解释程序;换句话说,该命令将在无须先运行命令解释程序再由命令解释程序运行ipconfig的前提下直接运行ipconfig。在某些情况下,这种方式或许利大于弊,但在这个示例中,我们却不希望绕过命令解释程序。为什么?因为命令解释程序可帮助我们发现“窗体一闪而过”问题的答案。正如您所看到的,命令解释程序可接受大量开关选项(如果您有兴趣了解cmd.exe或command.exe所具备的全部功能,则请在计算机帮助系统中查找该程序的可执行文件),而这些选项中的/k开关则恰恰用来指示命令解释程序在某一程序运行完毕后保持输出窗口的开启状态。我们需要借助这个选项来确保程序窗体不会在打开后立即关闭。
为实现上述目的,我们应将正在运行的命令从ipconfig修改为cmd.exe /k ipconfig或command.exe /k ipconfig,这里,cmd.exe对应于Windows NT操作系统,而command.exe则适用于Windows 9x操作系统。但是,如果您必须同时面向Windows NT和Windows 9x操作系统提供支持,又将如之奈何?针对我们正在使用的操作系统进行跟踪的确是一件颇为麻烦的事。也正是出于这种原因,我们才引用了一个名为%COMSPEC%的环境变量,以期提供通往适当命令解释程序的完整路径。该环境变量可确保下列脚本代码既可在Windows NT操作系统上运行,又能在Windows 9x操作系统上执行:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ipconfig"
请尝试运行这个经过修改的脚本。您只需启动记事本(或其它习惯使用的文件编辑器),并将%COMSPEC% /k添加到先前编写的脚本中,然后,将修改过的文件另存为RunIPConfig.vbs。接下来,在命令行窗体中导航至C:\Scripts目录,再通过输入cscript RunIPConfig.vbs命令并按回车键的方法运行该脚本。您这次将看到一个用来显示ipconfig命令输出结果的新窗体,具体情形如下图所示。
[UploadFile=1_1131002294.gif>
如果您所使用的浏览器无法支持嵌入式框架,请, 点击此处 以便在单独页面中进行浏览。
您接下来应该做的就是进行适用性测验。上述脚本所能运行的程序绝不仅限于ipconfig。而您所需要完成的全部工作仅仅是修改第二行代码中跟在Run方法后面的字符串。您可尝试将%COMSPEC% /k ipconfig分别替换为%COMSPEC% /k netstat或%COMSPEC% /k mmc。举例来说,您将可从某一脚本中运行GUI(图形用户界面)工具,而这个脚本则以运行计算器程序为例:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
您不仅能从某一脚本内部运行其它脚本,而且,还可从当前脚本中调用其它批处理文件;如果您碰巧拥有一些批处理文件,不妨尝试运行它们。当然,如果这些批处理文件的存储位置与您计算机上PATH环境变量的设定范围并不相符,您就应将相关存储位置添加到全局访问路径或单独指定通往批处理脚本的完整访问路径。举例来说,如果您在C:\Batchscripts目录下拥有一个名为Checkserver.bat的批处理脚本,那么,应由您传递给Run方法的字符串就应类似于:%COMSPEC% /k C:\batchscripts\checkserver.bat。
如果您已完成了上述试验,我们就将继续讲解后面的内容。您将学习到借助Run方法运行单一程序的具体方法。如果您需要连续运行两个程序,应如何是好?这恰恰是由下列脚本即将执行的任务:该脚本将在运行ping程序后,紧接着运行nslookup程序。请注意,您可将对应于所需运行程序的命令行参数包含在传递给Run方法的字符串当中。在此,我们将把127.0.0.1作为参数分别传递给Ping和Nslookup。
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ping 127.0.0.1"
objShell.Run "%COMSPEC% /k nslookup 127.0.0.1"
请按针对先前所述脚本的处理方法保存并运行这个脚本。脚本运行结果应该是两个命令行窗体同时打开,其中,Nslookup程序在一个窗体中运行,而Ping程序则在另一个窗体中以同步方式运行,具体情形正如以下屏幕快照所示。
您接下来应该做的就是进行适用性测验。上述脚本所能运行的程序绝不仅限于ipconfig。而您所需要完成的全部工作仅仅是修改第二行代码中跟在Run方法后面的字符串。您可尝试将%COMSPEC% /k ipconfig分别替换为%COMSPEC% /k netstat或%COMSPEC% /k mmc。举例来说,您将可从某一脚本中运行GUI(图形用户界面)工具,而这个脚本则以运行计算器程序为例:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
您不仅能从某一脚本内部运行其它脚本,而且,还可从当前脚本中调用其它批处理文件;如果您碰巧拥有一些批处理文件,不妨尝试运行它们。当然,如果这些批处理文件的存储位置与您计算机上PATH环境变量的设定范围并不相符,您就应将相关存储位置添加到全局访问路径或单独指定通往批处理脚本的完整访问路径。举例来说,如果您在C:\Batchscripts目录下拥有一个名为Checkserver.bat的批处理脚本,那么,应由您传递给Run方法的字符串就应类似于:%COMSPEC% /k C:\batchscripts\checkserver.bat。
如果您已完成了上述试验,我们就将继续讲解后面的内容。您将学习到借助Run方法运行单一程序的具体方法。如果您需要连续运行两个程序,应如何是好?这恰恰是由下列脚本即将执行的任务:该脚本将在运行ping程序后,紧接着运行nslookup程序。请注意,您可将对应于所需运行程序的命令行参数包含在传递给Run方法的字符串当中。在此,我们将把127.0.0.1作为参数分别传递给Ping和Nslookup。
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ping 127.0.0.1"
objShell.Run "%COMSPEC% /k nslookup 127.0.0.1"
请按针对先前所述脚本的处理方法保存并运行这个脚本。脚本运行结果应该是两个命令行窗体同时打开,其中,Nslookup程序在一个窗体中运行,而Ping程序则在另一个窗体中以同步方式运行,具体情形正如以下屏幕快照所示。
[UploadFile=2_1131002380.gif>
在这个例子中,事实表明,实现Ping和Nslookup的同时运行根本不成问题。然而,如果您需要运行两个批处理脚本,并希望在第一个脚本运行完毕后再开始运行第二个脚本,又该如何是好?举例来说,第一个程序将针对某一特定类型的信息执行检索,并将其保存为一个文本文件;而第二个程序则将在前者基础上通读刚刚生成的文本文件,并针对相关内容执行特定操作。在这种情况下,两个程序的同时运行将是无法接受时;只有在第一个程序执行完毕的前提下,第二个程序才能开始运行。
到目前为止,我们一直都在传递给Run方法一个用来指定所需运行程序的字符串。Run方法将可再接收两个参数,而这两个参数中的每一个均为可选参数。第二个参数将允许您针对某一程序在开始运行时所呈现的窗体外观加以指定。并非所有程序都将使用到该参数,但对于那些使用该参数的程序来说,该参数却可帮助您启动一个呈现多种窗体风格(包括最小化、最大化和隐藏在内)的程序。我们并不打算在这篇专栏文章中过多涉及该参数。如果您需要了解有关该参数的更多信息资料,敬请查阅WSH在线文档http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001169(点击接近本页面顶部的“Windows Script Host文档”链接)。
专供Run方法接收的第三个参数将允许我们防止相关程序以并发方式运行。您可将第三个参数赋值为True,以便指示脚本停留在使用Run方法的代码行并保持等待状态,直到已被激活的程序运行完毕。我们已经知道了因未设定该参数所产生的后果,该参数在缺省状态下被设定为False,而这种设置必将导致两个程序同时运行。
让我们将前面的脚本修改为先运行Ping程序,待Ping程序运行完毕后,再运行Nslookup程序的状态。
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /k ping 127.0.0.1",,True
objShell.Run "%COMSPEC% /k nslookup 127.0.0.1"
请注意,我们已将被赋值为True的第三个参数添加到应在脚本第二行中被调用的Run方法之后。我们之所以连续使用两个逗号的原因在于,如果我们只使用一个逗号,那么,Run方法便会认为我们随后指定的是第二个参数,而非第三个参数。如您所见,两个连续逗号之间并不存在任何内容,因此,也就不会有任何设置被当作第二个参数传递给Run方法。如果我们没有对某一参数专门赋值,那么,Run方法便会使用缺省值。举例来说,第三个参数的缺省值应该是False。
现在就让我们试着运行经过修改的脚本。您会马上注意到,只有Ping程序得到运行。当Ping运行完毕后,该程序运行时所使用的窗体仍在屏幕上保持开启状态;而Nslookup程序则尚未开始运行。请试着关闭这个窗体并查看接下来发生的情况。当您关闭Ping程序所使用的窗体后,Nslookup便会开始运行。请记住,您正在使用/k选项运行cmd.exe(或command.exe),也就是说,您已经告诉Run方法,直到cmd.exe运行完毕,方可继续执行后续指令。好的,由于我们事先设定了/k选项,因此,只有曾被要求保持开启状态的窗体得到关闭,cmd.exe才会执行完毕。
如果您需要运行两个批处理文件,并且无需查看它们的输出结果,那么,便可将/k选项删除,而这两个批处理文件仍将接续(而非同时)运行,这也恰恰是您在第二个程序信赖第一个程序运行结果的前提下所需确保的运行方式。
两个程序之间应就以下信息进行沟通,那就是,第一个程序实现运行的情况必须被告知第二个程序。某些程序将返回一个错误代码(也就是一个数字),用来指示自身是否已得到成功运行。而Run方法便可将这种错误代码返回给您所编写的脚本。正处于运行状态的程序必须在得知即将被返回的错误代码之前运行完毕,为此,您必须通过将Run方法的第三个参数设定为True的方式强制脚本等候程序运行完毕。
我们将在接下来的脚本中运行Ping程序,并通过针对Wscript对象使用Echo命令的方式将该程序所返回的错误代码显示出来。Wscript对象将不必被生成为类似于WshShell对象的状况,而您则可在脚本当中的任意控制点对它所提供的方法加以运用。
Set objShell = CreateObject(“Wscript.Shell”)
iErrorCode = objShell.Run(“ping 127.0.0.1”,,True)
Wscript.Echo iErrorCode
除具备错误代码检索功能外,以上脚本还在两方面与先前脚本有所区别。首先,请注意,即将被传递给Run方法的字符串已被加上了一对圆括号。这主要是因为,Run目前被要求返回一个数值。这属于VBScript语言的一项要求;如果您并未在此使用圆括号,便会在脚本运行过程中收到一条错误信息。应该被返回的数值是Ping程序的错误代码,并将被保存至变量iErrorCode,然后,借助WScript.Echo命令被显示出来。
需要给予关注的第二件事就是,我们并没有运行命令解释程序。我们希望错误代码来自Ping,而非来自Cmd.exe(或Command.exe),为此,我们直接运行了Ping程序。而由Ping返回的错误代码既不是很有趣,也不是很有用。当然,某些命令行工具却可返回可供您所编写的脚本做出相关判断(或生成日志)的有用错误代码。
从借助Run实现运行的某一程序中所获得的相关信息仅能满足最低使用需求,并很有可能不具备多少使用价值。举例来说,许多程序都将只返回一个0数值,以此表明自身已实现运行并且运行完毕。当然,它们并没有必要就自身成功运行且运行完毕的情况向您进行汇报。
当然,如果您已拥有WSH 5.6版(可从http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001169页面下载),便具备了另一种可供使用的方法,以便运行那些可帮助您与当前所运行程序改善信息交流方式的程序。而这种方法便是Exec。它还是从属于WshShell对象的一种方法,这里所说的WshShell正是为使用Run而必须生成的那个对象。这对我们来说主要意味着,不必为开始利用Exec方法而针对脚本的第一行代码进行修改。
让我们直接编写一个利用Exec方法运行ipconfig程序的脚本。
Set objShell = CreateObject("WScript.Shell")
objShell.Exec "%COMSPEC% /k ipconfig"
上述脚本同我们为您展示的第二个脚本之间所存在的唯一区别就是,我们已在这个脚本中将objShell.Run修改为objShell.Exec。然而,当您运行这一个脚本时,将难以觉察到上述修改所产生的效果。您甚至无法看到那个一闪即逝的窗体。实际上,您根本看不到任何东西。如果我们此时告诉您,ipconfig实际上已运行完毕,不知您是否愿意相信?好吧,还是不要轻易相信我们所说的话;取而代之的做法是,在ipconfig命令后方添加一个重定向符号(>),并在针对ipconfig发出的调用后紧跟一个文本文件名。上述代码将导致命令执行结果被输出到指定文件。如果您尚未习惯使用重定向操作,不妨这样设想:如果我们将真实情况告诉您,而ipconfig程序的确处于运行状态,那么,它便会生成自己的标准文本显示信息。遗憾的是,我们将无法看到相关信息。重定向操作将允许我们捕捉到任何命令的输出结果,并将它们强行导向一个指定文件。这将有助于我们针对ipconfig命令是否处于运行状态加以确认。接下来的脚本可供用来将所需查看的输出结果呈现给我们。
Set objShell = CreateObject(“Wscript.Shell”)
objShell.Exec “%COMSPEC% /k ipconfig > ipconfig_output.txt”
在上述脚本运行完毕后,请查看ipconfig_output.txt文件内容。如需查看这个文本文件的内容,则请按下列屏幕快照所示键入type命令。
[UploadFile=3_1131002419.gif>
这就是您所得到的信息!我们的脚本就是实实在在地运行ipconfig,只不过没有让我们看到命令输出结果。无论您相信与否,这都算得上一件好事。Exec之所以没有为我们显示输出结果,恰恰是因为我们原本并未提出相关要求。正如您所看到的那样,我们可借助Exec针对输出结果的呈现和操作方式加以控制。
您是否还记得令Run方法返回错误代码的具体实现方式?Exec事实上可返回一个被称作WshScriptExec的完整对象。正如WshShell对象为我们提供针对Run和Exec这两种方法的访问调用权限那样,WshScriptExec对象将为我们提供针对附加功能特性的访问调用权限,而这些附加功能特性则允许我们围绕某一程序的输出结果展开操作。脚本中大量操作的实现都会以额外复杂性为代价,而上述附加功能特性也不例外。我们即将或多或少地遭遇这种复杂性,为此,请继续阅读本文,并在接下来的章节中确保集中精力。
Exec方法可供用来返回一个WshScriptExec对象。而在某一脚本中促成这一事件的发生则需要使用VBScript语言中的Set关键字,具体代码如下所示:
Set objWshShellExec = objShell.Exec(“ipconfig”)
说明:我们并未在此继续使用%COMSPEC%环境变量;该变量已不具备继续存在的必要,其原因主要体现为,我们不需要为确保某一并不存在的窗体处于开启状态而将/k选项传递给相关命令。那么,我们又该如何将这个窗体关闭并继续运行脚本代码呢?我们将可在此使用/c选项(该选项表示只运行一条命令,然后,接着执行后续代码);事实上,如果我们需要运行一条已被内建于命令解释程序的命令(例如dir),便会需要使用该选项。而像dir这样的工具本身并不属于工具范畴;它们更加近似于cmd.exe(或command.exe)命令的参数;正因如此,您才需要为确保它们发挥作用而指定%COMSPEC%这一环境变量。
当您将与WshShellExec对象相关的引用存储于objWshShellExec变量后,便已具备了开始围绕程序输出结果展开操作的必要条件,但此时的条件尚不够充分。而这正是复杂性乘虚而入的大好时机。正如Exec方法返回WshShellExec对象那样,WshShellExec对象亦可返回另一对象;这个对象将通过调用StdOut属性的方式被返回,而这恰恰允许您针对程序输出结果执行相关操作。
如果不对照一个示例脚本,上述思路几乎不可能得到理解。为此,我们专门编写了一个最为简单的示例,旨在针对由嵌套于WSH脚本的某一程序所产生的输出结果加以运用。请将该脚本当作一种特殊类型的重定向操作。只有在这种情况下,程序输出结果才不会被导入某一文件,取而代之的是,相关输出结果将被赋予一个名为strOutput的变量。遗憾的是,我们这回将不能仅仅使用一个简单的重定向符号(>),而必须围绕两个不同对象执行操作。
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ipconfig")
Set objStdOut = objWshScriptExec.StdOut
strOutput = objStdOut.ReadAll
WScript.Echo strOutput
由上述脚本生成的输出结果将被显示在专供脚本运行的窗体内;这里并没有新的窗体生成。事实上,如果您从命令行方式中运行ipconfig本身的话,输出结果看上去也将别无二帜。既然如此,为何不干脆采取这种方式?我们已经在脚本当中为输出结果生成了一个中间存储位置--strOutput变量。尽管我们将在上述脚本的下一行内利用Wscript.Echo命令针对输出结果加以显示,然而,却往往需要在执行显示操作前先对输出结果实施操控,只有这样,才能对由ipconfig工具显示的信息进行修改。
在尝试运行上述脚本之前,让我们先对它的最后三行代码给予更多关注;当然,您已经对前两行代码非常熟悉了。在第三行代码中,WshScriptExec对象所配备的StdOut属性将被用来检索代表正处于运行状态之程序(标准)输出结果的相关对象;而ipconfig则是本例中待处理结果的输出程序。在第四行代码中,ReadAll方法将被用来针对全部输出结果执行检索,并将其保存于strOutput变量。最后,也就是在第五行代码中,WScript.Echo将被用来显示输出结果。
我们现在已拥有了经常被当作ipconfig工具(或可供我们用来在上述脚本中替代ipconfig的其它任何工具)封装程序的对象。封装程序是一种可就另一程序功能特性加以应用、并能够以简便快捷方式针对已被封装程序功能进行修改的特殊程序。封装程序为我们创造了针对已被封装程序的输出结果进行修改的理想时机。而这恰恰是我们将利用本文剩余篇幅加以介绍的内容。
在围绕ipconfig工具开展自定义的过程中,我们将需要了解以每次一行的频率对程序输出结果进行相关处理的具体方法。当前,我们主要借助objStdOut.ReadAll对ipconfig工具的全部输出结果执行检索操作,并将检索结果保存于strOutput变量。而我们将在下一个脚本中执行的任务则是利用ReadLine(而非ReadAll)针对输出结果进行逐行检索。我们将对输出结果的每一行进行检查,如果任意一行包括“Physical Address”(物理地址)字符串,就会将它显示出来;否则,便不会显示这行输出结果。我们只对包含“Physical Address”(物理地址,也就是对应于网卡的MAC地址)字符串的输出结果行执行了筛选操作,并未将其它任何内容显示出来。
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ipconfig /all")
Set objStdOut = objWshScriptExec.StdOut
While Not objStdOut.AtEndOfStream
   strLine = objStdOut.ReadLine
   If InStr(strLine,"Physical Address") Then
       WScript.Echo strLine
   End If
Wend
上述脚本的前三行看上去多少有些眼熟;请注意,我们必须将/all选项添加至ipconfig命令后方,以确保Physical Address(物理地址)被显示出来。这个脚本同上个脚本之间的主要区别在于,前者使用了While/Wend循环语句。我们将使用ReadLine方法对单个输出结果行执行检索操作,但却需要掌握针对是否超出行检索范围的状态加以判定的具体手段。而这恰恰是While/Wend循环和objStdOut.AtEndOfStream指令的用武之地。只要程序尚未触及(标准)输出结果数据流的结尾,上述循环便会保持接续执行状态(而符合检索条件的输出结果行则将被保存至strLine变量)。您可将一个数据流想象为由一系列字符排列而成的长串,而您则可按排列顺序对其进行相关处理;本例中的数据流便是ipconfig /all命令的完整输出结果。
每当我们完成一次程序循环时,便会将下一行内容保存至strLine变量,并利用If/Then语句决定是否应对该行内容加以显示。我们主要借助InStr(字符串命令)功能对存储在strLine变量当中的输出结果行是否包含“Physical Address”(物理地址)加以判断。如果当前行确实包含有“Physical Address”(物理地址),就应使用WScript.Echo命令将它显示出来。以下屏幕快照展现了由脚本生成的部分典型输出结果。

我们的下一个脚本将使用与上一个脚本完全相同的基本组件,所不同的是,我们已不再针对输出结果执行筛选操作,而是向它们当中添加特定内容。鉴于ipconfig /all命令可针对DHCP释放获取时机及其超时状态信息执行检索,因此,将当前日期和时间包含于命令输出结果的处理方法或许具备一定实用价值。接下来的脚本正是用来实现这一设想。
脚本一开始便针对输出结果的前四行执行检索和显示操作,并且对每一行所采取的方法完全相同--先调用ReadLine命令,紧接着调用WScript.Echo命令。当输出结果的第四行已被检索并显示出来后,我们便生成了一个包含有当前日期和时间标注信息的字符串。而这里所说的当前日期和时间则是由VBScript所配备的Now()函数提供的。
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ipconfig /all")
Set objStdOut = objWshScriptExec.StdOut
';
'; Skip first four lines
';
strLine = objStdOut.ReadLine
WScript.Echo strLine
strLine = objStdOut.ReadLine
WScript.Echo strLine
strLine = objStdOut.ReadLine
WScript.Echo strLine
strLine = objStdOut.ReadLine
WScript.Echo strLine
';
'; Add date/time information
';
strCurrentTime = "   Current Date/Time. . . . . . . . .: " & Now()
WScript.Echo strCurrentTime
';
'; Display the rest of the output
';
While Not objStdOut.AtEndOfStream
   strLine = objStdOut.ReadLine
   WScript.Echo strLine
Wend
毋庸置疑,上述脚本已开始变得多少有些复杂了。而解读这一脚本的最佳方法则是逐段分析。您应对该脚本的前三行较为熟悉。而下一个附有注释的部分则主要借助ReadLine和Echo命令对ipconfig /all输出结果的前四行执行读取和显示操作。
附有注释的下一部分自然以编排将被临时存储于strCurrentTime变量的新信息行为起点。这个信息行将由一个与VBScript Now()函数调用操作相关联的简单字符串构成,而VBScript Now()函数则用来提供当前日期和时间信息。一旦这个信息行编排完毕并被保存于strCurrentTime变量,我们便可当即使用WScript.Echo命令对其加以显示。
在最后一个附有注释的部分中,我们将对输出结果的剩余内容执行循环操作,并在无需进行任何修改的前提下对其进行逐行显示。以下屏幕快照展现了脚本运行产生的典型输出结果。请注意,脚本输出结果看上去与ipconfig的标准输出结果别无二帜。而由我们插入Host Name(主机名称)行下方的Current Date/Time(当前日期/时间)行则与全新的上下文环境结合得天衣无缝。

最后,让我们使用For/Next循环语句执行前四行内容的输出操作,以便使脚本变得更加精简,具体代码如下所示。
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ipconfig /all")
Set objStdOut = objWshScriptExec.StdOut
';
'; Skip first four lines
';
For i = 1 To 4
   strLine = objStdOut.ReadLine
   WScript.Echo strLine
Next
';
'; Add date/time information
';
strCurrentTime = "   Current Date/Time. . . . . . . . .: " & Now()
WScript.Echo strCurrentTime
';
'; Display the rest of the output
';
While Not objStdOut.AtEndOfStream
   strLine = objStdOut.ReadLine
   WScript.Echo strLine
Wend
事实上,还存在着从WSH脚本中运行其它程序的另一种替代方法:即针对Windows管理规范(WMI)加以应用。您将可借助WMI完成一系列Windows管理任务!虽然借助WMI实现程序运行的方式将涉及相对复杂的语法,但却可帮助您完成Run和Exec无法实现的任务,例如,设定程序运行优先级或基于远程计算机运行相关程序。在此,我们诚恳地建议您尽可能了解有关WMI的更多信息资料。如果您确实对此抱有兴趣(我们希望您能够这样),则请到MSDN网站上一个名为Scripting Clinic(脚本诊所)的专栏中查阅由三部分组成的系列文章(http://msdn.microsoft.com/columns)。
好在我们已回答了您针对从WSH脚本中运行其它程序而产生的某些疑难问题。我们还为您提供了有关Run和Exec方法的简要概述,并初步涉及了存在于两者之间的某些差异--其中,最明显的区别体现为,Exec方法将允许您针对程序输出结果进行处理,而Run方法则不具备这种能力。另一个重要区别是:只有WSH 5.6及其后续版本方可提供Exec方法。
我们衷心希望您能够对第一篇专栏文章感到满意。请将您的意见和观点发送至:scripter@microsoft,以便让我们有所了解。此外,请务必告诉我们您希望以后各期专栏能够涉及哪些内容。如果您能够在百忙之中抽出宝贵时间,则请查阅刊载于Scripting Clinic(脚本诊所)专栏的WMI系列文章;如果您利用在这里学到的知识技能完成了某些既简洁明快又富于实用价值的工作,就请将事情的经过记录下来;我们非常乐于听到与这方面有关的消息!

打印本文  返回顶部  加入收藏  关闭窗口
广 告 位 招 租
  • 上一篇: 页面问题
  • 下一篇: [首发]YYmp3音乐小偷免费版
  • 关于本站 - 网站帮助 - 广告合作 - 下载声明 - 友情连接 - 网站地图 - 管理登录
    联系方式
    Copyright © 2004-2007 FCBU.Com All Rights Reserved.
    版权所有:『站长天下』 新凌讯网络;保留所有权利. 赣ICP备05002812