welcome to 's blog...


公告

我的分类(专题)

日志更新

最新评论

留言板

链接

搜索


Blog信息




Windows Powershell+ADSI
aku1 发表于 2007-12-29 11:49:44

使用 Active Directory


如果您曾经玩过 Windows PowerShell,那么您一定尝试过 Get-WMIObject cmdlet — 也称为 gwmi,这是它更为方便的别名。如我在上个月的专栏中所述,此 cmdlet 展示了 Windows PowerShell 相对于以前的脚本语言和命令行外壳的一项重要改进

(请参阅 technetmagazine.com/issues/2007/05/PowerShell)。通过 Gwmi 可以快速、方便地访问 Windows® Management Instrumentation (WMI),从而可以完成许多令人难以置信的工作,而无需编写复杂的脚本。

Get-WMIObject 就是尽显 Windows PowerShell™ 能力的一个最佳例证,每当我在课堂上展示它时,学生们总是能够将它的功能拓展到 Windows 管理的其他方面。但是,通常人们提出的第一个问题总是围绕着“存在 Get-ADSIObject cmdlet 吗?”。


Windows PowerShell 中的 ADSI 支持

ADSI 是 Active Directory® 服务接口的缩写。尽管其名称如此,但实际上 ADSI 并不是特定于 Active Directory 的。该名称更为精确的解读应该是“Active(停顿)Directory Services Interface”(活动的目录服务接口),因为 ADSI 可以连接到各种目录服务,其中包括 Windows NT® 样式的目录 — 注意,不仅仅是 Windows NT 域,还可以连接到独立的或成员计算机上的本地安全帐户管理器 (SAM)。凭借这种灵活性,Get-ADSIObject cmdlet 无疑用途广泛。但遗憾的是,Windows PowerShell 团队未能在其第一版中纳入该 cmdlet。

但这并不是说 Windows PowerShell 缺乏 ADSI 支持。事实上,Windows PowerShell 中的 ADSI 支持是如此优秀,您甚至不会注意到 Get-ADSIObject cmdlet 的缺失!

这一切始于 [ADSI] 类型适配器。我们需要对类型适配器稍加解释。我们知道 Windows PowerShell 是在 Microsoft® .NET Framework(具体而言,是 2.0 或更高版本)上构建的。因此,Windows PowerShell 中的几乎所有内容 — 从 WMI 对象到文件和文件夹 — 都表示为该 Framework 中的对象。但是,Windows PowerShell 团队并不喜欢只将原始的 Framework 对象呈现给 Windows 管理员。例如,许多 Framework 对象的使用都有一定的不一致性,而一致性是 Windows PowerShell 的一个主要设计目标。另一个原因是某些 Framework 对象在涉及 Windows 管理时有些多余,而简洁性也是 Windows PowerShell 设计思想的一个主要方面。这样就诞生了类型适配器。

顾名思义,类型适配器将 .NET Framework 对象类型“适配”为一种更一致、有时也是更简单的格式。例如,假设您创建一个如下所示的新字符串变量:

[string]$var = “Hello”

您使用了一个由 .NET 适配器处理的 System.String 类型的实例。[ADSI] 类型适配器连接至 .NET Framework DirectoryServices 类,其中包括 DirectoryEntry 类型。


从目录中检索对象

连接到目录对象比较直接。例如,要连接到 Contoso.com 域的 IT 组织单位 (OU) 中名为 Don 的用户,可使用如下代码:

$user = [ADSI]”LDAP://cn=Don,ou=IT,dc=
Contoso,dc=com”

如果您在 VBScript 或其他语言中使用过 ADSI,对此应当并不陌生。它是一个标准轻型目录访问协议 (LDAP) 查询字符串,是访问 Active Directory 的本机方式。您无需指定域控制器 (DC) 名称或任何其他详细信息;此完全限定域名 (FQDN) 已包含足够信息来定位 DC 和检索对象(当然,假设您具有相应权限)。

本地安全帐户的处理过程基本相同,只是这时要使用 WinNT 提供程序,而不是 LDAP 提供程序:

$user = [ADSI]”WinNT://don-pc/don”

请注意,LDAP 和 WinNT 别名都区分大小写。虽然 Windows PowerShell 本身通常不区分大小写,但这些 ADSI 资源却区分 — 因此在键入时应当注意。

图 1 显示了获取所得到的 $user 变量并将其通过管道传送至 Get-Member 时发生的情况:我将得到一个对象属性列表。但是,这不是所有用户属性的完整列表,并且其中不含用户对象的任何方法。从这个角度讲,基础 System.DirectoryServices.DirectoryEntry Framework 类的工作方式有些奇怪,并且 Windows PowerShell 只能显示 Framework 类所提供的内容。


图 1 检索对象属性列表 (单击该图像获得较大视图)

检索对象主要是为了了解如何构造查询字符串。WinNT 提供程序的使用非常简单。只需指定一个计算机名或域名、一条斜线,再加上一个对象名即可。此技术非常适合 Active Directory 域(毕竟这些域与 Windows NT 域向后兼容)。事实上,有时使用 WinNT 提供程序从 Active Directory 中检索对象是最简单的方式,因为 WinNT 提供程序提供了一个域的平面视图。这意味着,您无需知道对象位于哪个 OU 中,因为 WinNT 提供程序看不到这些 OU。

LDAP 对象的检索要求更为精确些。首先要尽可能提供最精确的信息,如对象的规范名称 (cn) 或 OU 的名称。然后,应提供对象的完整路径,从其父容器开始,直至域本身。例如,检索位于 Sales OU(位于 Contoso.com 域的 West OU 中)中的用户 Don 应如下所示:

LDAP://cn=Don,ou=Sales,ou=West,dc=Contoso,
dc=com

此格式需要一点点的实践并要求您知道对象所在位置。图 2 汇总了 FQDN 的各种组件。


来自朋友的一些帮助

创建和删除对象通常要求首先连接到对象的容器(如 OU),然后请求容器创建或删除该对象。我总不记得正确的语法,幸运的是,Microsoft 脚本专家可以通过 ADSI Scriptomatic 助我们一臂之力。

虽然 ADSI Scriptomatic 最初是为 VBScript 创建的,但它仍是 Windows PowerShell 的一个非常有用的指南,因为实际的 ADSI 语法是相同的。例如,在下载该工具后,我选择了创建新用户的选项。我忽略了该工具生成的所有脚本代码,直至“End connect to a container”代码之后,如下所示:

Set objUser = 
 objContainer.Create(“user”, “cn=” & strName)
objUser.Put “sAMAccountName”, strName
objUser.SetInfo

转换到 Windows PowerShell 很简单。首先,我连接到要在其中创建用户的容器。为与 Scriptomatic 代码保持一致,我将使用变量 $objContainer 来表示 OU。我还要创建一个变量 $strName,用于存储新用户的名称:

$strName = “Don”
$objContainer = “LDAP//ou=Test,dc=Contoso,
dc=com”

接下来,我复制所有 Scriptomatic 代码,删除任何 VBScript Set 语句的所有痕迹,并向变量名添加 $:

$objUser = $objContainer.Create(“user”, 
  “cn=” & $strName)
$objUser.Put “sAMAccountName”, $strName
$objUser.SetInfo()

这就是所需的全部工作 — 一个新用户在 Contoso .com 域的 Test OU 中创建完毕。


修改目录对象

连接到对象后 — 例如一个用户或组 — 您可以修改它。使用 WinNT 提供程序,您可以直接修改许多属性,如图 1 中所示的那些属性。例如,要显示然后更改用户的 Description 属性,可以编写如下代码:

Write-Host $user.Description 
$user.Description = “New Description”
$user.SetInfo()

有一点必须牢记,属性更改在本地属性缓存中进行,这是 ADSI 在计算机上维护的一个临时存储区域。调用 SetInfo 方法会将缓存写回您从中检索对象的计算机或域,其实质是将您的更改保存回目录。

对于多数对象属性,Active Directory 对象并不直接提供属性。实际上,您应当使用 Get 和 Put 方法:

Write-Host $user.Get(“Description”)
$user.Put(“Description”,”New Description”)
$user.SetInfo()

WinNT 对象倾向于简洁化,因为 Windows NT 目录服务没有存储有关对象(如用户和组)的许多信息。相反,Active Directory 存储了众多信息,要找出正确的属性名称会有些难度。例如,如果要更改用户的姓氏,则必须更改 Sn 属性。为什么必须更改 Sn 呢?因为它代表姓氏。

幸运的是,Microsoft 提供了一个很好的交叉引用,您可以通过 msdn2.microsoft.com/ms677286.aspx 在线获得该引用。该引用显示了“Active Directory Users & Computers”(Active Directory 用户和计算机)控制台每个主要区域的属性名称,因此如果您知道要在控制台中进行哪些更改,则可以找出基础属性名称。请注意,Cade Fassett 所著的“ADSI Scripting:TFM”(ADSI 脚本:TFM)(SAPIEN Press, 2007) 一书中提供了更完整的控制台至属性交叉引用。


不能完成的任务

遗憾的是,Windows PowerShell 中的 ADSI 支持不像对其他技术(如 WMI)的支持那样强。例如,枚举本地计算机的组成员就有些困难。在处理 Active Directory 时,同样会遇到一些困难情况。根据我的经验,基本的对象检索、创建和删除比较容易。修改对象属性也相对简单,虽然有些属性不可访问。最大的难度来自通过 WinNT 提供程序对本地对象和组的处理。

这并不是说没有一点办法,只是有些事情要更困难一些,或者不那么直观。请看下面的例子:

$group = [ADSI]”LDAP://cn=Techs,cn=users,
  dc=contoso,dc=com” 
$group.Member.Add(“cn=user1,cn=users,
  dc=contoso , dc=com”) 
$group.psbase.CommitChanges()

该示例将名为 User1 的用户添加到 Techs 组中。它非常明了。它使用 FQDN 来检索该组,然后使用该组的 Member 集合 — 具体而言,是该集合的 Add 方法 — 来添加所需用户的 FQDN。但是,最后一步并不那么显而易见。它调用隐藏的 PSBase 类的 CommitChanges 方法来保存更改。

PSBase 是一个特殊类,直接代表基本的 .NET Framework 对象。在本例中,没有直接在 Windows PowerShell 中公开 CommitChanges(实际上,ADSI 适配器没有公开任何方法),因此您必须转向基础类。尽管这不是不可能的,但显然不够直观。这也表明目录服务功能尚未完全适合 Windows PowerShell。

这有许多原因。首先,在整个开发周期中,Windows PowerShell 团队向外壳添加当前 ADSI 支持的时机有些晚。就像外壳架构师 Jeffrey Snover 经常说的“提供就是选择”。该团队用来开发和交付外壳的时间是固定的,他们必须做出决定要为下一版本保存哪些内容。如果不是这样,他们可以轻易地花上几年时间来添加新功能,而永远不会实际发布一款支持的产品。

不过,还有一个原因就是基础 .NET Framework。它的 DirectoryServices 类非常复杂,使那种复杂性与 Windows PowerShell 相配需要大量时间和认真规划。在我看来,Framework 类也有些侧重于 Active Directory,并且没有为 WinNT 提供程序提供有力支持 — 当然,Windows PowerShell 会从 Framework 继承任何这类局限性。

我预计 Windows PowerShell 会逐渐拥有广泛的目录服务支持 — 甚至是可以不通过 ADSI 层,而是通过 .NET Framework 中的基本改进获得的支持。同时,Windows PowerShell 中的 ADSI 支持还允许您执行绝大部分管理任务,如创建用户、修改通用用户属性等。

请不要忘记,许多目录服务任务可通过 WMI 完成。请查阅 microsoft.com/technet/scriptcenter/scripts 中提供的某些优秀脚本示例,它们使用 WMI 提供有关本地组的更多信息,比 ADSI 本身提供的信息还要广泛。



Don Jones 是 SAPIEN Technologies 的首席脚本权威,也是 ScriptingTraining.com 的一名讲师。您可以通过网站 ScriptingAnswers.com 与 Don 联系。

摘自 June 2007 期刊 TechNet Magazine.

阅读全文 | 回复(0) | 引用通告 | 编辑


发表评论:

    昵称:
    密码: (游客无须输入密码)
    主页:
    标题:



Powered by Oblog.