Active Directory Service Interface

Active Directory Service Interface (ADSI) 是一组植基于 COM 技术上的应用程序开发接口,程序开发人员可以利用这些接口来连接并访问 Active Directory,并执行查询,更新或删除等管理功能,ADSI同时可支持以LDAP(轻量级目录访问协议)为主的目录服务(例如Novell Directory Service),以及以 Windows NT 网域为主所组成的 WinNT 网域目录。

接口结构

ADSI 由 COM 以及原生函数库所组成,并封装在 activeds.dll 文件中,部分则被封装在 advaip32.dll 中,以 COM 原生接口方式呈现,以提供给 C/C++ 编程语言透过 COM 接口来取用,不过由于所有的原生接口均支持 COM Automation,因此 Visual Basic 或是 .NET Framework 的语言也可以利用 COM Interop 能力访问 ADSI 中的接口。

原生接口 (Native interfaces)

activeds.dll 中封装了几个 ADSI 中最核心的接口:

  • IADs:作为所有 Active Directory 对象最顶层的接口,拥有最基础的功能,
  • IADsContainer:作为所有可收纳 Active Directory 对象的收纳器 (Container) 最顶层的接口,具有收纳器的基础功能。
  • IADsOpenDSObject:连接 Active Directory 之用(它只有 OpenDSObject() 一个方法),同时它会缓存住用来连接的安全信息内容。
  • IADsNamespace:由目录服务提供者 (directory service provider) 提供,用来识别目录结构的命名空间之用。

activeds.dll 亦提供了几个依对象不同而实现的接口,像是:

  • IADsComputer:提供目录服务中的电脑 (computer) 对象。
  • IADsDomain:提供目录服务中的网域 (domain) 对象。
  • IADsUser:提供目录服务中的用户 (user) 对象。
  • IADsGroup:提供目录服务中的用户组 (group) 对象。
  • IADsOU:提供目录服务中的组织单元 (organization unit) 对象。
  • IADsCollection:提供目录服务对象集合。

在使用 ADSI 之时,有时会需要一些工具型功能,像是 DOMAIN\user 和 User Principal Name 间的转换,或是获取系统信息等,ADSI 也提供了这类的接口:

  • IADsNameTranslate:在目录服务中在不同的名称间转换。
  • IADsWinNTSystemInfo:在目录服务中获取 Windows NT Directory Service 系统信息。
  • IADsADSystemInfo:在目录服务中获取 LDAP Directory Service 系统信息。
  • IADsPathname:剖析 X.500 名称与路径。

这些接口多是使用 C/C++ 编程语言来访问,若是使用 VB 或是 Scripting Language 时,则可以使用另外的方法来访问。

' Get user object from Active Directory.
Dim mach As IADsContainer
Dim usr as IADsUser

On Error GoTo Cleanup
Set mach = GetObject("WinNT://MyMachine,Computer")
Set usr = mach.Create("user","jeffsmith")
usr.SetInfo

Cleanup:
    If(Err.Number<>0) Then
        MsgBox("An error has occurred. " & Err.Number)
    End If
    Set mach = Nothing
    Set usr = Nothing
// binding Active Directory using C++ and native interface.
IADs *pObject;
HRESULT hr;

// Initialize COM.
CoInitialize(NULL);

hr = ADsGetObject(L"LDAP://CN=jeffsmith,DC=fabrikam,DC=com", 
        IID_IADs,
        (void**) &pObject);
if(SUCCEEDED(hr))
{
    // Use the object.

    // Release the object.
    pObject->Release()
}

// Uninitialize COM.
CoUninitialize();

函数

ADSI 除了接口以外,也将部分功能使用函数方式显露,以简化调用原生接口需要处理的工作,较重要且经常被使用的有:

  • ADsOpenDSObject(),封装获取 IADs 或 IADsContainer 等对象的工作。
  • ADsGetObject(),封装利用已开启的 Active Directory Session 获取对象的工作。
  • ADsGetLastError(),获取在 ADSI 作业中,最后一个引发的错误。
  • AllocADsMem(), FreeADsMem(), AllocADsStr(), FreeADsStr(),配置与释放 ADSI 使用的资源。
  • ADsBuildEnumerator(), ADsEnumerateNext(), ADsFreeEnumerator():处理 ADSI 对象的枚举工作。

下列的例子,是使用 ADsOpenDSObject() 获取 IADs 对象的示例代码:

IADs *pObject;
LPWSTR szUsername = NULL;
LPWSTR szPassword = NULL
HRESULT hr;

// Insert code to securely retrieve the username and password.

hr = ADsOpenObject(L"LDAP://CN=Jeff,DC=Fabrikam,DC=com",
                   "jeffsmith",
                   "etercespot",
                   ADS_SECURE_AUTHENTICATION, 
                   IID_IADs,
                   (void**) &pObject);

.NET Framework 原生接口

.NET Framework 中,另外提供了一个 .NET 专用的 ADSI 接口程序库 System.DirectoryService.dll,程序开发人员可以加入此程序库的参考来获取 ADSI 的功能,在这个原生类别库中,封装了两个类别,作为访问 Active Directory 的入口之用。

  • DirectoryEntry:此类别封装了 IADs 以及 IADsContainer 等原生接口,用来访问 Active Directory 的对象资料,以及 Schema 封装的信息等等。
  • DirectorySearcher:此类别封装了 IDirectorySearch 接口,作为搜索 Active Directory 的主要工具,并使用 SearchResult 对象封装搜索结果,让 .NET 开发人员可以简化处理搜索结果的工作。

截至 .NET Framework 3.5 为止,ADSI 在 Managed Class Library 中有四个命名空间:

  • System.DirectoryServices:原生的 ADSI Managed 接口,封装 DirectoryEntry 和 DirectorySearcher 与工具类别。
  • System.DirectoryServices.AccountManagement:封装对 IADsUser, IADsComputer, IADsGroup 等接口,简化处理对象的工具。
  • System.DirectoryServices.ActiveDirectory:封装对 Active Directory 结构对象的工具。
  • System.DirectoryServices.Protocol:封装对 LDAP 协议与目录服务通信的工具与基类。

下列为使用 C# 访问 DirectoryEntry 的示例代码:

DirectoryEntry ent = new DirectoryEntry();
DirectoryEntry ou = ent.Children.Find("OU=Consulting");

// Use the Add method to add a user to an organizational unit.
DirectoryEntry usr = ou.Children.Add("CN=New User","user");
// Set the samAccountName, then commit changes to the directory.
usr.Properties["samAccountName"].Value = "newuser"; 
usr.CommitChanges();

目录服务提供者 (directory service provider)

ADSI 因为是使用了 LDAP 以及开放式目录等标准,因此只要目录服务的平台是以开放式目录标准实现 IADsNamespace 与其他目录服务提供者接口时,即可由 ADSI 来支持,目前 ADSI 有五种提供者:

  • ADSI LDAP Provider:Active Directory 官方主要的支持接口,连接字符串使用 LDAP:// 为主。
  • ADSI WinNT Provider:以 Windows NT 为主的支持接口,连接字符串使用 WinNT:// 为主。
  • ADSI NDS Provider:支持 Novell Directory Service,连接字符串使用 NDS:// 为主。
  • ADSI NWCOMPAT Provider:支持 Novell Netware 3.x 的网络服务,连接字符串使用 NWCOMPAT:// 为主。
  • ADSI IIS Provider:支持 IIS 内部的提供者,连接字符串以 IIS:// 为主,用于访问 IIS Metabase。

OLE DB Provider for Directory Services

除了 ADSI 原生接口外,微软也为了 SQL Server 或是 ADO 应用程序开发人员发展了可使用 ADO 来访问 Active Directory 的驱动程序,此驱动程序使用 OLE DB 来开发,并且使用类似 SQL 指令的方式来访问 Active Directory,此驱动程序称为 OLE DB Provider for Directory Service,其 COM 的 Prog ID 为 ADsDSOObject

下例为使用 ADO 访问 Active Directory 的示例代码:

Dim Con As New Connection
Dim rs As New Recordset
Dim command As New Command
Dim usr As IADsUser

' Replace department for all users in OU=sales.
Set con = Server.CreateObject("ADODB.Connection")
con.Provider = "ADsDSOObject"
 
Set command = CreateObject("ADODB.Command")
Set command.ActiveConnection = con
 
command.CommandText = "SELECT AdsPath, cn FROM 'LDAP://OU=Sales,DC=Fabrikam,DC=com' WHERE objectClass = 'user'"
 
command.Properties("searchscope") = ADS_SCOPE_ONELEVEL
Set rs = command.Execute
While Not rs.EOF
    Set usr = GetObject(rs.Fields("AdsPath").Value)
    usr.Put "department", "1001"
    usr.SetInfo
    rs.MoveNext
Wend

下列指令为使用 SQL Server 查询来合并访问 Active Directory 的脚本[1]

-- create a linked server to active directory interface
EXEC sp_addlinkedserver 'ADSI', 'Active Directory Services 2.5', 'ADSDSOObject', 'adsdatasource' 

-- configure SQL Server to allow ad-hoc query and openquery statement.
EXEC sp_configure 'show advanced options', 1
reconfigure with override

EXEC sp_configure 'Ad Hoc Distributed Queries', 1 
reconfigure 

-- execute query via OpenQuery() statement
SELECT * FROM OpenQuery(ADSI, 'SELECT * FROM ''LDAP://DC=kodyaz,DC=com'' WHERE objectCategory=''user'' ') 

SELECT * FROM OpenQuery(ADSI, 'SELECT mail, displayName, userPrincipalName FROM ''LDAP://DC=kodyaz,DC=com'' WHERE objectCategory=''user'' ')

开发 Directory-Enabled 应用程序时可用的工具

由于 ADSI 和 Active Directory 的特性,开发人员若没有使用适当的工具时,很难发展与目录服务链接 (directory-enabled) 的应用程序,因此微软为 Active Directory 提供了两种工具:

  • Active Directory Explorer:由 Sysinternals 团队所开发[2],现已并入 Microsoft TechNet 团队中,可用来浏览 AD 网域或树系的 LDAP 层次结构字符串,以及对象的属性资料。
  • ADSIEdit:在 Windows 2000 和 Windows Server 2003 时,由 Resource Kit Support Tools 安装包提供,到了 Windows Server 2008 时,则内置在系统中[3]

参考资料

内容参考:

  1. ^ Running Active Directory Services Queries Using MS SQL Server OPENQUERY Command. [2009-01-01]. (原始内容存档于2009-01-05). 
  2. ^ AD Explorer. [2009-01-01]. (原始内容存档于2008-12-18). 
  3. ^ Adsiedit Overview: Active Directory. [2009-01-01]. (原始内容存档于2008-12-30). 

文章参考:

  1. MSDN Library: Active Directory Service Interface页面存档备份,存于互联网档案馆
  2. Directory Service in .NET Framework页面存档备份,存于互联网档案馆