谁希望成为脚本专家?

每周脚本测验题

*

脚本测验题答案:2006 年 1 月 13 日:我的两个用户不见了!

这道测验题您可以知道答案也可以不知道。而且,您会看到,理由很充分:如果您还不知道答案,要靠您自己找到答案会很难。不过别担心:今天离开前,我们会告诉您需要查阅的资源,这些资源可以帮助您理解这个脚本和它失败的原因。当然,现在不会对您有太多帮助(毕竟,您未能解决这道测验题),但下次将对您有所帮助。而且要记住,您不可能永远不败。

如果您没有参加上周的测验,可以在这里试一下;您也可以继续阅读,让我们告诉您答案。不要忘了,本周我们又给出了一道新测验题。请试一试,看看您的答案会是什么。

返回页首返回页首

2006 年 1 月 13 日答案

不能正常工作的脚本总是令人愤怒。但是提供错误消息的脚本至少可以缓解一些愤怒。错误消息常常会有助于您找到解决方案;最起码,这些错误消息可以让您知道脚本有问题。那么,即不正常运行也不提供任何错误消息的脚本呢?还有比这更令人气愤的事吗?

好吧,说的对:还有可能更气人一点的事情:脚本测验题的解答并不详尽,只给出测验题的答案。明确这一点后,下面让我们来看一下对于修复创建用户帐户脚本,一个不创建任何用户帐户的脚本,我们能做些什么。

首先,没有必要一丝不苟地查看代码;不管您相信与否,代码一点问题也没有。或者,更准确地说,现在这些代码没有任何问题;问题出在这里没有的代码上。任何时候要在 ADSI(用于管理本地用户和组帐户以及 Active Directory 的脚本编写技术)中创建新对象,都需要使用 SetInfo 方法将这些更改正式写入目录服务(尽管是本地 Security Accounts Manager、Active Directory 等等)。如果遗漏了 SetInfo,就不会创建新对象。仅此而已。任何时候,如果要使用 ADSI 修改读写属性,也是这样。更改属性值后,必须调用 SetInfo 将这些更改写回实际对象。如果不 …。

换句话说,要修复此脚本,我们需要做的只是添加一对调用 SetInfo 的代码:一处添加在完成设置 Ken Myer 用户帐户的属性值之后,另一处添加在完成设置 Pilar Ackerman 用户帐户的属性值之后。添加这两行代码,运行脚本,我们就会获得一直所预期生成的两个用户帐户。

修订后的脚本如下所示。我们所做的只是添加两行代码(objUser.SetInfo 的两个实例)。其他的都不变:

On Error Resume Next

Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName

Set colAccounts = GetObject("WinNT://" & strComputer & "")

Set objUser = colAccounts.Create("user", "kenmyer")
objUser.Description = "Local user account for Ken Myer."
objUser.FullName = "Ken Myer"
objUser.AccountExpirationDate = #12/31/2006#
objUser.SetPassword "09iu%4et"
objUser.SetInfo

Set objUser = colAccounts.Create("user", "pilarackerman")
objUser.Description = "Local user account for Pilar Ackerman."
objUser.FullName = "Pilar Ackerman"
objUser.AccountExpirationDate = #12/31/2006#
objUser.SetPassword "LweQ9%4z!"
objUser.SetInfo

那么,为什么我们还需要 SetInfo?任何时候处理 ADSI,大部分工作都发生在本地内存中(通常称为本地缓存)。假设您要修改 Active Directory 中的用户帐户。绑定到该用户帐户后,就将帐户的副本传送到本地缓存。修改属性值时,实际上只更改本地副本的值;并不涉及到原始(实际)用户帐户。只有在调用 SetInfo 时,脚本才连接到实际用户帐户,并使用本地缓存中的已修改副本替换原始对象。这和在文字处理程序中处理文档没有什么两样。您可以键入所有需要的内容,但在单击“保存”按钮之前并不实际保存所做工作;如果您关闭文字处理程序而不保存文档,那么文档就不会被保存。

顺便提一下,处理远程计算机或远程目录服务时,这样做有助于削减网络通信量。假设您正在处理一个 Active Directory 用户帐户,这是一个有 200 多个属性的对象。您可能不希望,每次修改其中一个属性时,脚本都要到网络的另一头,进行连接,就更改一个值,然后回来,而且每次更改别的值都重复这个过程。相反,您希望在本地内存中进行所有更改,然后调用 SetInfo,使用一个网络调用修改对象 en masse

返回页首返回页首

我们为什么要知道这些?

正如我们前面所说的,您自己解决这个问题有点困难;毋庸置疑,如果您看到这个脚本,并且没有 ADSI 的预备知识,然后说“我打赌,如果在这儿添加一个名为 SetInfo 的方法,就可以解决问题”,我们将非常吃惊。如果您还没有掌握 ADSI 的基本常识,那么诊断和修复这个脚本是很困难的。

嘿,但这正是“脚本中心”的作用:我们生命中的一个重要使命就是提供各种脚本编写技术的基本常识。例如,Microsoft Windows 2000 脚本指南中包含综合性的一章,全面广泛地介绍了 ADSI 和 ADSI 的基础知识;同样,“脚本专家”也进行了几个网络广播,介绍 ADSI 和 ADSI 的基本概念。如果您只是处于脚本编写入门阶段(特别是 ADSI 脚本编写),最好从上述资料入手。不要低估了浏览脚本存储库的作用;毕竟,只是看示例脚本就可以学到很多东西。这些示例脚本可以执行各种各样的任务,其中至少包括一个创建本地用户帐户任务。

换句话说,这就是您应了解 SetInfo 的方法。


返回页首返回页首