发布者 The Scripting Guys
如果脚本是非法的,那么只有非法者才使用脚本

如需获得脚本专栏所有脚本故事的列表以及其他信息,请点击此处。
Microsoft 的员工生活在虚幻的世界中,这是针对 Microsoft 员工的批评之一。意思是说我们这些 Microsoft 员工只是关注各种理想情况而对于系统管理员真正需要面对的实际问题却从不考虑。这可能适用与某些 Microsoft 员工,但是至于我们对系统管理员所面临的问题一无所知这种说法,Scripting Guys是有意见的。而且也有许多其他同仁同意我们的看法。例如,就在今天早上坐车来上班的路上,我们对司机说:"Bentley,你认为Scripting Guys是生活在虚幻的世界中的吗?是不是在系统管理员有需要的时候总是不能提供帮助?" "我不这样认为,"Bentley说,"绝对不是这样的。"

毕竟我们认为他是这么说的。说实在话,由于坐在后排的 Jacuzzi 的说话声音过大,我们听得并不是很清楚。

不过,问题是,Scripting Guys也只不过是些平常人物罢了,和其他人并没有什么区别。把我们归为那类不食人间烟火的"杰出精英"有点夸张了。我们觉得我们在一个重要的领域可能的确不够尽职:也许——注意,仅仅是也许——当系统管理员遇到安全问题时,我们没有出色地完成自己的工作。

我们承认,让Scripting Guys谈论安全问题可能会让你们听起来有点好笑,因为有好多人认为如果没有脚本程序那么就不会有那么多的安全问题。每当出现******或者破坏***以及新的病毒或者蠕虫病毒的时候,人们就会自然而然地将责备对号入座到脚本,然后扩大到我们这些从事与脚本有关的工作的人。他们会说,也许我们应该全面禁止脚本。也许, Microsoft 应该从操作系统中删除 Windows Script Host,也应该永久禁止宏功能。而且,把Scripting Guys都投入监狱并扔掉钥匙,让他们再没机会重见天日。(有趣的是,那些并不支持禁止脚本的人却也极力支持后面这个处罚措施。)

此外,我们也不否认脚本编写的确是某些上述***中的途径。是的,我们已经注意到了Kak.hta,我们也已经看到了 ILoveYou.vbs 病毒。(事实上,我们是最先遭受他们***的人之一。就权当真的有那么多人爱我们吧。)但是设想一下,如果我们真的放弃脚本编写,情况会变成怎么样?这些疯狂的举动就会停止了吗?

好吧,这的确是一个不错的想法,可是通过买魔力球×××赢取十亿美元也是一个很不错的想法,而且两者发生的几率也是十分的相似(同为0)。当然,蠕虫和其他病毒的确可以写成脚本,但是它们也同样被写成批处理文件,难道我们也要全面禁止批处理文件吗?它们还被编写成可执行文件,难道我们也要禁止在电脑中使用可执行文件吗?将电脑中的可执行文件全部删除,那么你的电脑除了看起来有点酷之外,就毫无其它用处了。

嘿嘿,那样我们岂不是发明了一台 Macintosh!(致无处不在的 Macintosh 的爱好者:开玩笑而已。)

事实上,脚本编写只不过是使蠕虫以及其他病毒的编写变得更加简便,即使是这点还是值得商榷的(某些病毒是十分复杂的)。但是如果我们禁止使用脚本的话,病毒编写者只需回复从前的样子用 C 或者 C++语言编写即可。但是请记住,在病毒当道的今天,即使我们通过某种方法消除了所有病毒,计算机在处理的时候也并不是百分之百的安全。设想,如果一个连接到 Internet 的计算机用户共享了他(她)的整个硬盘。在这种情况下,对计算机进行肆意破坏时甚至不需要任何脚本的帮助。设想将计算机设置成无论是谁打开机器都能登录到操作系统的情况;某些人因为贪图方便将密码设置过于简单的情况以及其他你能想象的到的一些不安全设置。

这个问题的实质在于:只要我们使用电脑,那么一些不好的事情就有可能发生。这和生活中的所有事情都是一样的。比如让人们开车,就会有人会闯红灯或者倒车时撞上路旁的信箱。对于这些意外我们无能为力。我们所能做的就是教会人们怎样安全行车,并且提供安全带、安全气囊以及其他一些能够降低人们出事故时造成损害的安全设施。

这就是我们栏目今天所要传递给大家的信息。我们是否能够让人们停止传播病毒?我们是否能够让人们再不要将自己的计算机暴露于他人的潜在***下?我们是否能够保证计算机进行计算时百分之百的安全,消除一切出错的机会?不,我们做不到。至少在没有拔掉所有网络适配器、断开所有 Internet 连接以及彻底隔离各个计算机用户之前,我们是无法做到的。(致所有系统管理员:我们知道这听起来很诱人,但是这并不是Scripting Guy的正式建议。)不过,我们还是能够做些事情来帮助改善系统脆弱性的,防患于未然。脚本能够让我们的计算机变得更加安全,虽然这听起来似乎有点疯狂。(是的,我们说的的确是更加安全。请相信我们。)

本页内容
知识就是力量
最后的思考

知识就是力量
好了,好了:站在走廊上往下看,看那些手中掌握实权的家伙们。我们有时很难理解,他们的权利到底和他们所掌握的知识有什么联系。虽然事实如此,但是尽量多地掌握你所能得到的知识和信息毕竟不是一件坏事,这对于计算机安全这个问题尤其正确。你对于你的计算机以及它的设置知道得越清楚,那么你也就越有信心。这就是为什么计算机安全专家们建议大家对自己的计算机进行阶段性安全检查的原因。那么现在就剩一个问题:如何正确地进行这项阶段性安全检查?

事实上, Microsoft 已经发布了一款小巧实用的工具——Microsoft Baseline Security Analyzer——它能够帮助你完成这项安全检查。(我希望你已经下载了这个免费的小工具,如果还没有,请点击此处下载。)这款小工具的功能如其名称所示:它能够对一台计算机(如果你愿意,也可以是多台)进行分析,指出潜在的安全隐患,例如没有安装的安全补丁或者密码设置过于简单(甚至完全没有密码)的本地帐户。此软件个头虽小但却非常有用,无论是在家里还是办公室它都是必备软件。

当然,现在你也许在想:"好吧,既然 Security Analyzer 这么好用,我决定将它送给老妈作为圣诞礼物算了。但是这和脚本有什么关系呢?如果 Security Analyzer 能够提供我需要的一切,那我还要脚本干什么?Scripting Guys,我说的对吗?"

事实上,你说的很对:如果 Security Analyzer 能够做你所需要的一切,那么完全不必再使用脚本了。(或许你也并不是很需要那些救生圈,为什么不寄给 Scripting Guys,让我们来照顾它好了。)但是如果 Security Analyzer 并不能做你所需要的所有事情的时候怎么办?虽然 Security Analyzer 在收集信息方面做得很不错,但是毕竟它不能够对所收集到的信息做出任何反应。例如,它能够检测所有 5000 台工作站计算机的情况,并针对每台机子上的来宾帐户是否已经关闭做出详细报告(绝大多数机构都选择关闭来宾帐户以避免匿名或者没有授权的用户登录网络)。假设你的网络中有 2967 台计算机的来宾帐户没有关闭,那么 Security Analyzer 会将这一情况报告给你,但是最后还是需要你自己对每台机器进行处理,手动关闭这些机器上的来宾帐户。

后者就是脚本的用武之地。假如你想知道计算机上的来宾帐户是否已经关闭,你可以写一段脚本来完成上述过程,但是如果你只是想要检查一下这个帐户的状态的话,有什么意义?毕竟 Security Analyzer 就能够帮你检查帐户的状态,你完全没有必要写脚本。但是如果你想要做的不仅仅是检查一下帐户的状态而是想把打开的帐户全部关闭呢?单单靠 Security Analyzer 是不能完成上述两步的,但是你可以通过编写脚本来完成。

这也就是我们想在这里指出的。(如果你读过ADSI Scriptomatic Readme也许觉得很难相信,但是 Scripting Guys 实际上做的还是有点道理的)。脚本是一个很有用的工具,因为它可以帮助你得到与安全性相关的信息,但是它之所以成为必不可少的工具,其原因在于它可以对收集到的信息进行处理。这就是我们所要展示的:我们将向你展示 Security Analyzer 检索的信息,我们也想你展示如何通过编写能够检索同样信息的脚本。然后,在可能的时候,我们向你展示如何通过修改脚本来使它能够对检索的信息进行处理。

完全公布。好了,我们可能说的稍微有点夸张了:考虑到篇幅的原因,我们并不打算在此介绍 Security Analyzer 的所有功能。所以,我们会跳过中间的某些步骤,比如校验 SQL 服务器的帐户密码。希望你没有什么意见;Bentley 说他没问题。

顺便说一句,我们可能会在以后的专栏中更加深入地探讨与安全有关的话题。例如,我们会解释(或者至少试着解释)安全标识符奇怪而神秘的世界以及如何通过脚本来控制它。我们也会向你展示脚本在管理补丁程序和安全补丁方面发挥的作用。但是现在我们暂且先把这些内容搁置一旁。现在,就让我们不受任何打扰,开始讲解 Security Analyzer 能做什么以及如何通过脚本来实现相同的功能。

注意: 再打扰一下。为了使我们的脚本片段尽可能短,你在这里看到的脚本都是针对单机(本地单机)的。Security Analyzer 的实力在于它可以针对多机使用。脚本是否也能够做到呢?你猜猜看;有关更多详细信息请参阅前一期脚本故事专栏。擦亮你的眼睛,看看 Runomatic 是如何贴到脚本中心的。

什么是 Runomatic?你不想我们来破坏你自己找到答案时的那种惊奇感,是吧?

任务1:检索计算机名

老实告诉你吧,通过脚本来检索计算机名的途径数不胜数。但是因为 WMI 将要成为检索信息的主流技术,所以我们所展示的是一段返回目标计算机名称的 WMI 脚本。

strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\cimv2")
Set colComputers = objWMIService.ExecQuery _
    ("Select * from Win32_ComputerSystem")
For Each objComputer in colComputers
    Wscript.Echo objComputer.Name
Next

这看起来似乎有点可笑,尤其是这段脚本只是针对单机运行的时候。但是当它的目标计算机有 100 台的时候,它能够帮助我们将各台计算机区分开来。

任务2:检索 IP 地址

通过脚本实现 IP 地址检索同样非常简单:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\cimv2")
Set IPConfigSet = objWMIService.ExecQuery _
    ("Select IPAddress from Win32_NetworkAdapterConfiguration " _
        "Where IPEnabled=TRUE")
For Each IPConfig in IPConfigSet
    If Not IsNull(IPConfig.IPAddress) Then
        For Each strAddress in IPConfig.IPAddress
            WScript.Echo strAddress
        Next
    End If
Next

在判定一台计算机的 IP 地址时,只要注意两点。第一,WMI 将包括 ××× 和 RAS 连接在内的所有东西都认为是计算机网络适配器设置的一部分,为此,我们需要使用 WHERE 语句Where IPEnabled = TRUE来将返回的信息限定为实际网络适配器的信息。

第二,IP 地址通常以数组的形式返回,因此我们需要用一个 For-Each 循环来获得真正的 IP 地址。如果我们直接回应 IP 地址属性值的话,将会发生"类匹配"错误。

任务3:报告安全检查进行的日期和时间

实现这个功能也是非常的容易,但是鉴于我们复制绝大多数 Security Analyzer 的功能,下面是一行返回日期和时间的代码:

Wscript.Echo Now

你们有人不是觉得脚本是非常高深的吗!其实就这么简单。

任务4:检查升级包

好的,我们承认:从来就没有谁发布过完美的操作系统。(嗯,如果任何来自 Microsoft 的人这么问,我们可是不会这么说的。明白吗?)在操作系统发布后,总是会找到各种缺陷。不幸的是,我们同时也会找到各种安全漏洞和易遭受***的薄弱处。没有人喜欢发现缺陷这个事实,但是生活就是这个样子。没有人愿意切到自己的手指,但是万一你真的切了自己的手指,你不会坐以待毙,你肯定会翻出急救包然后给伤口上绷带。同样,如果一个操作系统需要类似的措施时,你应该翻出急救箱给系统装好升级包。

换句话说,你最好保证你的计算机安装了最新的系统补丁。Security Analyzer 就能够向你提供有关这方面的信息,而通过下面的脚本也同样能够做到:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer &
"\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
    Wscript.Echo objOperatingSystem.ServicePackMajorVersion  _
        & "." & objOperatingSystem.ServicePackMinorVersion
Next

在你开始提问之前,首先申明一点:WMI不会显示你所安装的所有升级包的信息,它只会告诉你安装的最新的升级包情况。但是这个应该不成问题,因为最新的升级包都包含了以前版本中的修补程序和升级程序。如果你在 WINDOWS 2000 中安装了 Service Pack 4,那么你安装的不仅仅是 Service Pack 4 中所增加的内容,它也包含了 Service Pack 1、2 和 3 中的所有内容。或者说,只要你知道自己的计算机已经安装了 Service Pack 4,你就没有必要担心你的计算机是否已经安装了Service Pack 1、2 或 3。事实上,它们肯定已经全部安装了。

任务五:检查 Hot Fix

你知道有关最近几次病毒以及蠕虫***的真正悲哀的地方在哪里吗?其实很多补丁已经提供很久了,如果用户能够使用的话,就能够避免计算机遭受***。但是出于多种原因,人们就是没有使用这些补丁,直到病毒找上门来,后果我不说大家也知道了。我说这些是什么意思?确保自己有最新的补丁和热修补程序(有关如何操作的更多信息请点击此处),并且确保自己的计算机安装了必需的修补程序。

但是你怎么知道机器上装了哪些热修补程序呢?你问的真是好笑:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer &
"\root\cimv2")
Set colQuickFixes = objWMIService.ExecQuery _
    ("Select * from Win32_QuickFixEngineering")
For Each objQuickFix in colQuickFixes
    Wscript.Echo "Description: " & objQuickFix.Description
    Wscript.Echo "Hot Fix ID: " & objQuickFix.HotFixID
Next

注意: 如果你使用的是 WINDOWS 2000 操作系统,有些计算机在进入Win32_QuickEngineering 类的时候可能会发生死机现象。有关此已知问题的更多信息以及如何修复,请点击这里。

这段脚本可以很好的工作,但是老实说,和 Security Analyzer 比起来还是要逊色一点。因为 Security Analyzer的确有些不俗的表现:它不仅仅告诉你哪些热修补已经安装了,还显示哪些没有安装。换句话说,如果没有安装某些必须的补丁的话,它会提示你。

那么 Security Analyzer 如何分辨哪些必须安装哪些不必呢?当你运行 Security Analyzer 时,它会参考一个文件(Mssecure.xml),该文件包含一个重要补丁列表以及哪些计算机(不同版本的 WINDOWS)需要哪些补丁的信息。

编写 Mssecure.xml 文件超出了本专栏的范围(虽然对于掌握 XML 知识的人来说这并非不可能)。但是,在以后的专栏中,我们将展示一些你也可以执行针对特定热修补 和补丁的类似方法。

任务六:检查本地管理员数目

人多手脚乱,太多的管理员同样也会坏了好事。更加重要的是,有更多的管理员意味着某人(管理员)犯某种错误从而将计算机暴露与他人***之下的可能性也大大增加。你也许会给你的邻居一把备用钥匙,好让他在你不在的时候更好的照看你的东西。但是你不会将你的备用钥匙分发给公共汽车上遇到的每个人。(我们暂且假设你不会这么做)同理,所以你会限制本地管理员的数量,因为从定义上来说,他们可以做许多超出你期望范围以外的事。

同 Security Analyzer 一样,脚本也能够返回计算机上本地管理员组的所有成员。事实上,下面这段代码就是完成这项功能的:

Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set objGroup = GetObject("WinNT://" & strComputer &
"/Administrators,group")
For Each objUser in objGroup.Members
    Wscript.Echo objUser.Name
Next

这些材料是非常有用的;无任什么时候,只要你有时间(假设你能够抽出时间),你可以仔细研究这份名单,必要的话,删除那些完全没有必要成为管理员的人。

但是如果你所在机构已经制定出与管理员资格有关的政策,应该如何实施这项功能?例如,假设已经规定普通用户不能成为管理员,而合格的管理员只能是本地管理员用户帐号和域管理员帐号(我们在此例中假设你工作于 fabrikam.com)。这种情况下,你所要求脚本做的不是返回多少个外部帐号,而是希望它能够删除那些外部帐号,只剩下 Administrator和fabrikam\Administrator 帐号。这才算够酷,不是吗?

好吧,如果这真的是你所想的,为什么不承认呢?这段脚本列举出管理员组的所有成员。如果它发现某个既不是 Administrator 也不是 fabrikam\Administrator 帐号的话,就会使用删除方法从该组中删除此帐号。

Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set objGroup = GetObject("WinNT://" & strComputer &
"/Administrators,group")
For Each objUser in objGroup.Members
    If objUser.Name <> "Administrator" and objUser.Name <> _
        "fabrikam\Administrator" Then
        objGroup.Remove(objUser.ADsPath)
    End If
Next

对了:这就是如何使用脚本来增强 Security Analyzer 功能的典型例子。
任务7:检查未过期密码

如果说有什么东西用户会不喜欢的话,那么定时过期的密码肯定名列其中。毕竟,你还没有记住它时,它就已经需要更换了。那么,既然用户们这么憎恨定时过期密码的话,那么干嘛要用他们呢?(我们并不是指为了那些在想密码的时候倒在键盘和鼠标上的无数杯咖啡)。

但是,事实是***们和用户们一样憎恨定时过期密码。设想一名***想要进行字典穷举***。他或者是她也许已经排除了aardvark是密码的可能,而这时候用户恰恰在***进行一半的时候将 aardvark更改为系统密码。即使***真的猜中了密码,那么这种胜利也是暂时的。也许正当***猜中密码的时候,用户马上就将其更改为其它的了。经常更改系统密码是有效提高安全性的途径之一,而经常更改密码最好的办法就是让密码经常过期。

因为用不过期的密码会造成某种安全弱点,所以如果 Security Analyzer 发现任何帐户使用不过期密码的时候,它都会报告这一情况。也许你已经猜到了,我们恰巧也有一段相应的脚本来完成这个相同功能:

Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set colAccounts = GetObject("WinNT://" & strComputer & "")
colAccounts.Filter = Array("user")
For Each objUser In colAccounts
    Set usr = GetObject("WinNT://" & strComputer & "/" & _
        objUser.Name & ", user")
    flag = usr.Get("UserFlags")
    If flag AND ADS_UF_DONT_EXPIRE_PASSWD Then
        Wscript.Echo usr.Name & ": Password does not expire."
    Else
        Wscript.Echo usr.Name & ": Password expires."
    End If
Next

而且你还以通过以下脚本将密码全部设置为过期密码:

Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set colAccounts = GetObject("WinNT://" & strComputer & "")
colAccounts.Filter = Array("user")
For Each objUser In colAccounts
    Set usr = GetObject("WinNT://" & strComputer & "/" & _
        objUser.Name & ", user")
    flag = usr.Get("UserFlags")
    If flag AND ADS_UF_DONT_EXPIRE_PASSWD Then
        usr.UserFlags = flag XOR ADS_UF_DONT_EXPIRE_PASSWD
        usr.SetInfo
    End If
Next

任务8:进行本地帐户密码测试

蠕虫和病毒得到大家的广泛关注,这个可以理解,但是某些时候真正造成计算机安全威胁的往往是那些最最简单的东西,比如说微不足道的留言便条。在办公室里,职员们经常在留言便条上记录密码,并且将它们贴在显示器上面。现在,你要禁止这种做法了,或者可以严惩那些乱贴这类留言条的家伙这种做法会导致另外一个问题(我们不是指使用走私的便条)。为什么人们会将他们的密码记录下来?因为这些密码太难记了。如果用户不可以记录这些密码,那么他们会倾向于使用他们无需记录就可以记下来的更加简单的密码——例如password。

即使是一个业余***或者发泄不满的人使用密码password也可以侵入计算机。虽然 Security Analyzer 不能检测在显示器上是否有记录密码的便条,但是它却可以检查是否有本地用户帐号:

&#8226; 使用空密码

&#8226; 使用与用户名相同的密码

&#8226; 使用与计算机名相同的密码

&#8226; 使用password作为密码

&#8226; 使用单词admin或administrator作为密码


Security Analyzer 是如何进行这么酷的测试的?毕竟,它不可能检索用户的密码。不然的话这也成了一个安全突破口。好了,告诉你答案,事实上我们也不知道。但是我们怀疑它使用 ADSI ChangePassword 方法(或者某种相当的API)来测试并且修改用户密码。为什么是 ChangePassword ?因为使用这种方法时,如果你不知道当前用户的密码,就不可能顺利实现此项功能,你需要一起提供当前密码以及新密码来完成。因为 Security Analyzer 并没有真正修改密码,所以我们怀疑它只是简单的提供相同的密码(例如password)来同时作为当前密码和新密码,或者与之类似的情况:

objUser.ChangePassword "password", "password"

如果当前密码不是password,这个方法就行不通,系统就会报错。如果当前密码是password,这种方法就会成功,不会产生任何错误,然后密码会被改成password。当然,这一过程的净效果就是密码没有改变,但是系统现在知道当前的密码就是password。这听起来似乎有点混乱,但是先看看这段脚本,看看它到底做些什么。思路其实非常简单。

而且,是的,这也是***可能进行的测试。我们现在是借用***方法来做正事。

以下就是一段用来检测帐户是否使用的密码是否是password的脚本。这段脚本也可以做简单的修改来检测帐户使用的密码是不是空白的,或者使用登录名作为密码,或者其它。

On Error Resume Next
Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
strPassword = "password"
Set colAccounts = GetObject("WinNT://" & strComputer & "")
colAccounts.Filter = Array("user")
For Each objUser In colAccounts
    objUser.ChangePassword strPassword, strPassword
    If Err = 0 or Err = -2147023569 Then
        Wscript.Echo objUser.Name & " is using the password " & _
            strpassword & "."
    End If
    Err.Clear
Next

注意: 你可能注意到了,我们的脚本检测是否出现错误(Err=0);如果没有错误,就说明密码已经被改变,这就说明我们知道这个帐号的密码就是password。但是我们同样检测是否存在错误-2147023569。如果当前的密码是password但是这个密码不能被更改,因为自从上次密码更改以后还没有经过足够长的时间,那么就会产生上述这个错误。(根据默认设置,密码只有每14天才能被更改一次)。

任务9:检测文件系统

如果计算机运行的是 Windows NT、Windows 2000、Windows XP 或者 Windows 2003操作系统,那么将硬盘各个分区格式成NTFS文件系统是非常重要的。(或许会有很少的用户会例外,我们这里暂且不管了。)除非你喜欢将你的硬盘暴露给外界,否则你需要将硬盘格式成为 NTFS 格式,然后就可以享受 NTFS 安全机制了。同样这就好像是家庭的安全一样:除非你想其他人或者他们的狗能够自由出入你家,并且随意使用屋里的东西,否则你就应该在门上加锁,并且在你人不在的时候把锁锁上。

那么你如何检测硬盘上安装的是什么文件系统呢?这里有一个非常简便的方法:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\" & strComputer &
"\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
    ("Select * from Win32_LogicalDisk Where DriveType = 3")
For Each objDisk in colDisks
    Wscript.Echo "Disk drive: "& objDisk.DeviceID & " -- " & objDisk.FileSystem
Next

在前述 WQL 查询中,你可能已经发现我们只是查询 DriveType 等于 3 的逻辑盘。为什么这么做?因为 DriveType 等于 3 代表的是硬盘,通过将返回数据限定在硬盘上,可以省去我们在软盘、CD-ROM 驱动器以及其它我们知道不会(也不可能)安装 NTFS 文件系统的驱动器上花费的时间。

任务10:检测自动登录

可以将 Windows 设置成每当开机就自动使用注册的用户名和密码登录。这听起来很方便,但是的确不适用于那些始终与 Internet 保持连接或者在信息亭中使用的计算机。但是,从另一方面来说,这却有点安全漏洞的嫌疑,至少可以这样说。毕竟它允许任何打开计算机的人以储存在注册表中的用户名和密码登录。正因为如此,Security Analyzer 所执行的一项检查就是查看计算机的自动登录功能是否打开。同样,你也可以使用脚本来完成这项检查:

Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set objReg=GetObject("winmgmts:\" & strComputer &
"\root\default:StdRegProv")
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\WinLogon"
strValueName = "AutoAdminLogon"
objReg.GetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName,
dwValue
If dwValue = 1 Then
    Wscript.Echo "Auto logon is enabled."
Else
    Wscript.Echo "Auto logon is disabled."
End If

同样,你肯定不希望计算机上的自动登录打开。所以,为什么不用一段脚本来关闭自动登录功能而不是像 Security Analyzer 那样仅仅只是提示自动登录功能的状态呢。可以使用类似以下的脚本:

Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set objReg=GetObject("winmgmts:\" & strComputer &
"\root\default:StdRegProv")
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\WinLogon"
strValueName = "AutoAdminLogon"
dwValue = 0
oReg.SetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName,
dwValue

任务11:检查来宾帐户状态

这个问题取决于你如何看待,来宾帐户在不需要证实身份的情况下向他人提供了一种登录你的计算机的途径(我们假设唯一的例外就是,此 Guest 不是指 Christopher Guest)。正因为如此,在 Windows XP 和 Windows 2003 中来宾帐户在默认条件下是关闭的,而且在 Windows 2000 和 Windows NT 4.0 中同样也应该是关闭的。这是一段报告本地计算机上来宾帐户状态的脚本:

Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set objUser = GetObject("WinNT://" & strComputer & "/Guest")
If objUser.AccountDisabled Then
    Wscript.Echo "The Guest account is disabled."
Else
    Wscript.Echo "The Guest account is enabled."
End If

看,酷吧。但是假设你决定所有计算机上的来宾帐户都应该关闭。可以修改这段脚本来让它在检查来宾帐户以外多做一两件其它的事。如果来宾帐户已经关闭,那么它只需要报告状态事实;但是如果来宾帐户开启的话,它进一步关闭此帐户:

Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set objUser = GetObject("WinNT://" & strComputer & "/Guest")
If objUser.AccountDisabled Then
    Wscript.Echo "The Guest account is already disabled."
Else
    objUser.AccountDisabled = True
    objUser.SetInfo
    Wscript.Echo "The Guest account has been disabled."
End If