您好,脚本专家!回答您有关 OU 的问题......只挣 5 美分

Microsoft 脚本专家

下载这篇文章的代码: HeyScriptingGuy2007_03.exe (151KB)

问:如何才能显示一个允许我从 Active Directory 选择 OU 的对话框?

您要知道, 如果我们脚本专家在每次被问到这个问题时都能得到 5 分镍币,我们应该得到 -- 嗯,实际上,也只不过是 37.15 美元,不是吗?当然,但如果对于那些想要向我们咨询这个问题但只是从未抽出时间来真正提问的每个人收取 5 分镍币,我们会得到 -- 嗯,金额是多少并不重要。毕竟,我们做脚本专家并不是为了赚钱。我们做脚本专家是为了体验帮助别人更简单快捷地执行系统管理任务所获得的满足感。

注意。 是的,从表面上看,我们做脚本专家的确是为了赚钱。但之后经理告诉我们,“要知道,你们大家是可以做得很出色并赚到很多钱的,但仅是在你们乐于真正努力地工作并只创造出高质量作品的情况下。”也就是在那时,我们确定了金钱并不代表一切。

没有关系。意义在于,许多人都想知道如何显示允许他们选择 OU、然后再使用脚本连接到该 OU(通过扩展)的对话框。最近发来的一封电子邮件中提到,“您曾经介绍过如何显示允许我们选择文件夹的对话框,也介绍过如何显示允许我们选择文件的对话框。那为什么从未介绍过如何显示允许从 Active Directory® 选择 OU 的对话框呢?”

嗯,首先,我们的确曾经介绍过如何显示允许选择文件夹的对话框,就在此处您就可以找到相关示例。我们也向所有人介绍过如何显示允许他们选择文件的对话框,如果您不相信的话,可以查看 microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx。这两篇文章都收到了好评,而且我们知道用户在自己的脚本中采用了这些方法。那么,为什么我们未向大家介绍如何显示允许从 Active Directory 选择 OU 的对话框呢?是 Microsoft 有某种密约还是有其他什么原因?

当然不是。(哎呀,稍等一下:这正是一项密约中所涉及的人要说的话,不是吗?)事实是,实际上有一个很好的理由可以解释为什么我们还没有介绍如何显示允许从 Active Directory 选择 OU 的对话框:因为根本不存在这样的对话框。就像棒球运动中常说的一句话,您无法击中看不到的东西。我们在编写脚本时也会常说,您无法显示不存在的东西。

因此,我们想这正是本月专栏要讨论的内容。下次见。

我就是这样不走运!据 TechNet 杂志的编辑所说,本月专栏的主题并不是这个。“那么,如果像那样的对话框不存在怎么办?”他们问到。“你们是脚本专家,看在上帝的份上。难道你们就不能创建一个用来处理此任务的对话框吗?我们原以为你们这些人在脚本编写方面可以做到任何事情。”

不用说,TechNet 杂志的编辑听到的消息显然不正确。在脚本编写方面可以做到任何事情?并不完全是这样。事实是,在涉及脚本编写时,我们脚本专家知道如何只做一件事情。

不过幸运的是,这一件事请就是创建允许您从 Active Directory 选择 OU 的对话框。看一看图 1

这个脚本有点长是不是?但您知道人们常说的那句话:有失才有得。同样,您不可能不付出代价就构建一个自定义对话框(我们在这个专栏进行到一半时感觉有点饿,不得不停下来吃点快餐)。既然我们已经吃饱了,就让我们看看是否能够阐明其整个工作原理。

我们对这个脚本所要完成的任务是使用 Internet Explorer® 对象模型构建一个伪对话框。我们要创建一个 Internet Explorer 实例,从 Active Directory 获取一个 OU 集合,然后在 Internet Explorer 窗口的某列表框中显示这些 OU。我们会一直等到用户选择一个 OU,然后获取所选项的 ADsPath,退出该“对话框”,然后从此处继续往下操作。

注意。这会成为所创建过的最奇妙、最别致的对话框吗?如果“最奇妙和最别致”指的是甚至连“确定”和“取消”按钮都没有的骨架式风格,那么是的。但站在我们的立场,这里提到的概念只是为您提供基本框架。如果您想要美化或修改该对话框,就要靠您自己来完成了。

(朋友,如果我们在每次说过“对不起,这要靠您自己来完成”后就收取 5 分镍币,我们确实会变得非常富有。请将您捐赠的脚本代码发送至 TechNet 杂志转“脚本专家”。)

为使分配给我们的空间能够容纳下对我们方法的说明,我们不得不只略谈几个方面。例如,对以下代码块我们要说的只是,它将创建一个 350x400 像素的 Internet Explorer 实例,这样做会隐藏地址栏和状态栏之类的元素:

Set objExplorer = CreateObject( _
    "InternetExplorer.Application")

objExplorer.Navigate "about:blank"   
objExplorer.ToolBar = 0
objExplorer.StatusBar = 0
objExplorer.Width= 350
objExplorer.Height = 400 
objExplorer.Left = 400
objExplorer.Top = 400
objExplorer.Visible = 1             

当然,这只是要为我们提供一个空白的 Internet Explorer 窗口。为了获取我们域中 OU 的列表,我们需要搜索 Active Directory。我们今天无法阐明有关 Active Directory 搜索的细节;有关这方面的信息,请看一下我们在脚本中心发布的由两部分组成的系列文章 (microsoft.com/technet/scriptcenter/resources/tales/sg0405.mspx)。我们能做的只是告诉您,这是我们用来检索域 fabrikam.com 中每个 OU 的 Name 和 ADsPath 的代码:

objCommand.CommandText = _
    "SELECT Name, ADsPath FROM 'LDAP://DC=fabrikam,DC=com' WHERE objectCategory=
    'organizationalUnit' ORDER BY Name"

哦,我们还按名称的字母顺序对 OU 进行了排序,只是为了让您更方便一些。这就是 ORDER BY Name 子句的作用。(没问题;毕竟,我们的使命是提供服务。)

当我们调用 Execute 方法时,将取回一个由在 fabrikam.com 中找到的所有 OU 组成的记录集。这意味着我们的下一步是在一个列表框中显示其中的每个 OU。

那么,我们如何去做呢?首先,我们需要在内存中构造整个列表框。对于初学者来说,这意味着使用这个代码行将 <SELECT> 标记存储在名为 strHTML 的变量中:

strHTML = "<select size = '20' name='OUList' style='width:300px'>"

我们要用这个代码行做什么呢?我们只需构造一个标准 HTML 列表框(使用 <SELECT> 标记执行的某个操作)。在此过程中,我们为该列表框赋予的 Name 是 OUList,并将其配置为一次显示 20 个项目,且宽度为 300 像素 (300px)。如果您非常了解 HTML,就会对上面的代码感到很熟悉。

接下来,我们需要将一些项目(即,一些 OU)添加到列表框中。令人感到十分凑巧的是,我们的记录集恰好由域中每个 OU 的相关信息组成。正因如此,我们可以设置一个 Do Until 循环来遍历整个数据集,获取信息,然后将每个 OU 添加到列表框中。在该循环内部,我们使用下列代码(再次重申,用于将项目添加到列表框的标准 HTML)添加每个 OU,从而对相应项目进行配置以使 OU Name 显示在列表中,如果在列表框中单击该 OU,会将 ADsPath 传递给脚本:

strHTML = strHTML & "<option value= " & _
    Chr(34) & objRecordSet.Fields
    ("AdsPath").Value & Chr(34)
strHTML = strHTML & ">" & objRecordSet.
    Fields("Name").Value

为什么要将 ADsPath 传递给脚本?道理很简单。假定我们改为传递 OU Name。例如,如果 Name 是 Finance,则就很难绑定到该 OU;毕竟“Finance”本身并不是一个有效的 ADSI 绑定字符串。但如果我们取回的是 ADsPath (LDAP://ou=Finance,dc=fabrikam,dc=com),那么绑定只不过是小菜一碟。这是因为 ADsPath 正是我们需要查找并连接到 Active Directory 中的对象的属性。

顺便说一下,我们将在列表框中显示 Name,因为我们假定您的 OU 名称是唯一的。有时 OU 名称可能不是唯一的;例如,OU 的 North America\Research 和 Europe\Research 就使用相同的名称 (Research)。如果您的 OU 具有重复的名称,您最好在列表框中改用另一个属性(比方说,ADsPath 或 distinguishedName)。这是一个您必须自己做决定的事情。(好耶!又得到 5 分镍币!)

顺便说一下,要注意到我们仍在内存中构造列表框:添加到该列表框中的各项将被添加到变量 strHTML。下面是这个计划的全部内容:我们将列表框的整个代码保存到变量 strHTML 中,然后使用该变量的值将列表框实际添加到我们的 Internet Explorer 的实例中。

在添加了所有 OU 之后,我们使用此代码行表示列表框的末尾:

strHTML = strHTML & "</select>"

此时,strHTML 中包含了创建列表框(最好是创建一个其中每一项都代表 Active Directory 中一个 OU 的列表框)所需的所有 HTML 标记。这意味着我们现在可以将 strHTML 值赋予我们 Internet Explorer 文档的 InnerHTML 属性:

objExplorer.Document.Body.InnerHTML = strHTML

反过来,这也为我们提供了一个显示域中所有 OU 的列表框。

请等一下,别走;我们还没有完全结束呢。例如,我们还需要一些允许我们将脚本一直暂停到用户从对话框中选择了 OU 为止的代码;如果没有这些代码,则无论用户是否进行了选择,列表框都会显示出来而脚本将继续运行。呀!为防止这种情况发生,我们使用以下代码块:

Do While objExplorer.Document.Body.All.OUList.Value = ""
    Wscript.Sleep 300
Loop

我们此时要做的就是反复检查我们列表框(您可能想起来了,我们将其命名为 OUList,有位脚本专家给他女儿起了一个相同的名字)的 Value。如果 Value 是空字符串(表示未选择任何项目),我们只需将脚本暂停 300 毫秒,然后循环一次,接着再次进行检查。此过程将持续到:a) 永远;b) 直到用户在列表框中选择某个项目;或者 c) 直到用户关闭 Internet Explorer 窗口。

让我们假定用户确实在列表框中选择了一个 OU。在这种情况下,我们获取 Value(您可能记得,就是 OU 的 ADsPath),并将其赋予名为 strTargetOU 的变量:

strTargetOU = objExplorer.Document.Body.All.OUList.Value

然后,我们按如下所示使用 Quit 方法退出 Internet Explorer 实例:

objExplorer.Quit

至此,我们差不多就结束了。我们首先检查并确定 strTargetOU 是否为空字符串:

If strTargetOU = "" Then
    Wscript.Quit
End If

如果是,则表示用户未选择 OU 就关闭了 Internet Explorer;接着,我们使用 Wscript.Quit 方法来终止脚本。(我们做出的假设是,如果用户未挑选 OU,则他或她不是真正对运行该脚本感兴趣。)但如果 strTargetOU 不等于空字符串,则我们将回显该变量的值:

Wscript.Echo strTargetOU

当然,在真正的脚本中,您可能会继续前进并绑定到 Active Directory 中的该 OU,而不仅仅是回显 ADsPath。但您知道他们在说什么 -- 或者至少知道我们在说什么:这要靠您自己了。

正如我们所提到过的,也正如您在图 2 中所看到的,它不是所创建过的最奇妙的对话框,但它很起作用,而且与必须键入一个 AdsPath(假定您连 AdsPath 都知道)相比,这是一种更简便的方式。另外,它也使您有机会根据需要对代码(及对话框)进行自定义。

Figure 2 A simple script dialog

Figure 2** A simple script dialog **

现在,要是我们对曾经编写的有关显示允许从 Active Directory 选择 OU 的对话框的每个专栏都能得到 5 分镍币该多好啊!这毕竟会为我们带来 5 美分的收入,比 TechNet 杂志通常支付给我们的要多一些。

提醒您,我们并不是在抱怨。

Microsoft 脚本专家是为 Microsoft 效劳的,也就是说受雇于 Microsoft。在没有棒球等各种娱乐活动时,他们偶尔也会经营一下 TechNet 脚本中心。查找所需的信息,网址为:www.scriptingguys.com

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.