如何从本地Win32(即不是.NET)代码查询ActiveDirectory

如果我想从.NET中的Active Directory获取用户信息,我可以使用DirectorySearcher类。

例如,要查找我要调用的用户的电子邮件地址

 public String GetUserEmailAddress(String accountName) { DirectorySearcher searcher = new DirectorySearcher(); searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName); searcher.PropertiesToLoad.Add("mail"); SearchResult searchResult = searcher.FindOne(); return searchResult.Properties["mail"][0]; } 

查询Active Directory的本地方法是什么?

注意

  • 没有指定域名
  • 没有指定服务器名称

我们甚至可以扩展我们的function来允许查询任何通用的任意信息:

 public Object GetUserAttribute(String accountName, String propertyName) { DirectorySearcher searcher = new DirectorySearcher(); searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName); searcher.PropertiesToLoad.Add(propertyName); SearchResult searchResult = searcher.FindOne(); return searchResult.Properties[propertyName][0]; } 

AD具有可以作为propertyName传递的各种信息。 例如:

  • displayName (Display-Name):对象的显示名称。 这通常是用户的名字,中间的名字和姓氏的组合。 (如Ian A. Boyd
  • mail (电子邮件地址):联系人的电子邮件地址列表。 (例如ianboyd@stackoverflow.com
  • cn (通用名称):表示对象的名称。 用于执行search。
  • name (RDN):对象的相对专有名称。 (如Ian Boyd
  • sn (姓氏):此属性包含用户的姓氏或姓氏。
  • givenName (Given-Name):包含用户的名字(名字)。
  • sAMAccountName (SAM-Account-Name):用于支持运行较早版本操作系统(如Windows NT 4.0,Windows 95,Windows 98和LAN Manager)的客户端和服务器的login名。 此属性必须less于20个字符才能支持较早的客户端。
  • objectGUID (Object-Guid):对象的唯一标识符。 (例如{3BF66482-3561-49a8-84A6-771C70532F25}
  • employeeID (Employee-ID):员工的ID。 ///“description”(描述):包含要显示的对象的描述。 该值被系统视为单值。

Solutions Collecting From Web of "如何从本地Win32(即不是.NET)代码查询ActiveDirectory"

第一步是查看Windows IT Pro上的文章系列An ADSI入门 。 它给出了一个相当不错的ADSI基础知识和IADs接口以及如何使用它们(从VBScript,我相信)。

Delphi中的第二步是导入Active_Ds类型库 – 这应该生成一个ActiveDs_TLB.pas文件,其中包含使用ADSI从本机语言处理Active Directory的基本类型,接口和方法。

为了访问本地函数,你需要为每个你想要的函数使用一个所谓的函数导入 – 在这里只有一个代码 – ADsGetObject

 type TADsGetObject = function(aPathName: PWideChar; const aRIID: TGUID; out aObject): HResult; safecall; var ADsGetObject : TADsGetObject = nil; initialization hActiveDS := LoadLibrary(PChar('ActiveDS.dll')); // don't localize if (hActiveDS = 0) then raise Exception.Create(rc_CannotLoadActiveDS); LoadProcAddress(hActiveDS, 'ADsGetObject', @ADsG 

etObject);

一旦你从外部库中创建了这些函数,你可以去调用它们 – 就像这样:

 var hr : HRESULT; oIADs : IADs; wsTemp : WideString; begin wsTemp := 'LDAP://cn=IanBoyd,cn=Users,dc=YourCompany,dc=com'; // try to bind to the ADSI object using the "sanitized" path hr := ADsGetObject(PWideChar(wsTemp), IID_IADs, oIADs); if Succeeded(hr) then begin // successful - now retrieve all properties into property cache try oIADs.GetInfo; except on EOleSysError do begin Exit; end; end; // get the object's GUID wsTemp := oIADs.GUID; // do more stuff here..... 

接下来,也看到我的ADSI德尔福技巧和窍门页面 – 信息的过时,虽然(如链接到德尔福杂志的集合CD – 似乎不再可用)。

用本地代码来搜索ADSI是非常重要的 – 这肯定会超出这个帖子的范围。 我写了一篇相当广泛的文章 – 包括示例代码 – 这可以应要求从我(我的个人资料中发送电子邮件到我的地址)。

marc_s被删除的答案被证明是最有用的; 但是这里是在伪代码中的问题的答案:

 public GetUserEmailAddress(String accountName): String; { //Get the distinguished name of the current domain String dn = GetDefaultDistinguishedName(); //eg "dc=stackoverflow,dc=com" //Construct the ldap table name (eg "LDAP://dc=stackoverflow,dc=com") String ldapTableName := "LDAP://"+dc; //ADO connection string String connectionString := "Provider=ADsDSOObject;Mode=Read;Bind Flags=0;ADSI Flag=-2147483648"; //The sql query to execute String sql := "SELECT mail"+CRLF+ "FROM "+QuotedStr(ldapTableName)+CRLF+ "WHERE objectClass = "+QuotedStr("user")+CRLF+ "AND sAMAccountName = "+QuotedStr(userName); ADOConnection conn := new ADOConnection(connectionString); try Recordset rs := conn.Execute(sql); try if (rs.Eof) return ""; return rs["mail"].Value; finally rs.Free; end; finally conn.Free; end; } 

真正的秘密是与“域”交谈,而不是任何特定的服务器:

 //get the distinguished name of the current domain public GetDefaultDistinguishedName(): string; { String path := "LDAP://rootDSE"; IADs ads; ADsGetObject(PWideChar(path), IADs, out ads); //eg on the "stackoverflow.com" domain, returns "DC=stackoverflow,DC=com" return (String)ads.Get("defaultNamingContext"); } 

注意 :任何代码都被释放到公共领域。 不需要归属

本地编程是LDAP,您可以在.NET中使用System.DirectoryServices.Protocols(S.DS.P) 。


编辑

如果您对如何从本地代码查询活动目录感兴趣,可以参考RFC 1823中所述的LDAP C绑定API,Microsoft支持它,请参阅轻量级目录访问协议(LDAP)的MS策略 。 您将在轻量目录访问协议中找到Microsoft API的使用和参考手册。

您将在这里找到一种在网络上查找Active Directory的方法,但不提供任何信息,而是提供正确的DNS服务器。 您可以在ldap_open函数中使用域名DNS名称,这样您就不必知道域名服务器地址。