3

我正在尝试将 LDAP / AD 搜索从仅在当前登录的域中搜索扩展到搜索 AD 中的所有域。该方法接收带有查询的字符串,并返回并返回一个 LDAPInformation 对象。

虽然我在问,有没有比这种方式更好的方法来搜索名称?由于在按姓氏查找人时需要使用通配符(例如:Doe*),因此对用户不友好。

    public static LDAPInformation[] GetGlobalAddressListVIAName(string nameQuery)
    {
        var currentForest = Forest.GetCurrentForest();
        var globalCatalog = currentForest.FindGlobalCatalog();

        using (var searcher = globalCatalog.GetDirectorySearcher())
        {
            using (var entry = new DirectoryEntry(searcher.SearchRoot.Path))
            {
                searcher.Filter = "(&(mailnickname=*)(objectClass=user)(displayName=" + nameQuery + "))";
                searcher.PropertyNamesOnly = true;
                searcher.SearchScope = SearchScope.Subtree;
                searcher.Sort.Direction = SortDirection.Ascending;
                searcher.Sort.PropertyName = "displayName";
                return searcher.FindAll().Cast<SearchResult>().Select(result => new LDAPInformation(result.GetDirectoryEntry())).ToArray();
            }
        }
    }

这是对象:

    class LDAPInformation
{
    internal LDAPInformation(DirectoryEntry entry)
    {
        //Section: HASH
        this.sAMAccountName = (string)entry.Properties["sAMAccountName"].Value;

        //Section: Email
        this.Mail = (string)entry.Properties["mail"].Value;

        //Section: Organziation
        this.Description = (string)entry.Properties["description"].Value;
        this.Company = (string)entry.Properties["company"].Value;
        this.Title = (string)entry.Properties["title"].Value;
        this.Department = (string)entry.Properties["department"].Value;

        //Section: Name
        this.DisplayName = (string)entry.Properties["displayName"].Value;
        this.FirstName = (string)entry.Properties["firstName"].Value;
        this.MiddleName = (string)entry.Properties["middleName"].Value;
        this.LastName = (string)entry.Properties["lastName"].Value;

        //Section: Address
        this.StreetAddress = (string)entry.Properties["streetAddress"].Value;
        this.City = (string)entry.Properties["city"].Value;
        this.State = (string)entry.Properties["state"].Value;
        this.PostalCode = (string)entry.Properties["postalCode"].Value;
        this.TelephoneNumber = (string)entry.Properties["telephoneNumber"].Value;
    }

    public string DisplayName
    {
        get;
        private set;
    }

    public string Mail
    {
        get;
        private set;
    }

    public string sAMAccountName
    {
        get;
        private set;
    }

    public string Description
    {
        get;
        private set;
    }

    public string Company
    {
        get;
        private set;
    }

    public string Title
    {
        get;
        private set;
    }

    public string Department
    {
        get;
        private set;
    }

    public string FirstName
    {
        get;
        private set;
    }

    public string MiddleName
    {
        get;
        private set;
    }

    public string LastName
    {
        get;
        private set;
    }

    public string StreetAddress
    {
        get;
        private set;
    }

    public string City
    {
        get;
        private set;
    }

    public string State
    {
        get;
        private set;
    }

    public string PostalCode
    {
        get;
        private set;
    }

    public string TelephoneNumber
    {
        get;
        private set;
    }
}
4

2 回答 2

4

@Brian Desmond 和 @lordzero。可能有点晚了,但我最近自己一直在做这类事情,所以我想我分享一下。

为了回答您的问题“您的搜索根是什么?”,lordzero,您可以在不知道 AD 服务器的情况下从这些服务器中找到它。域注册的 PC 将知道 AD 基础设施/森林等。

首先,您为“GC://rootDSE”创建一个 DirectoryEntry,从中提取命名上下文、rootDomainNamingContext 或其他。您可以转储第一个根 DSE DirectoryEntry 的所有属性以查看可用的内容。

这是我对我们使用的目录服务服务提供商的实现。

这取自 DirectorySearcherWrapper 类

我有一个成员变量。并在构造函数中实例化它。

DirectorySearcher directorySearcher;

在我的初始化方法中,我这样做

        using (DirectoryEntry directoryEntry = new DirectoryEntry(DirectoryConstants.RootDSE))
        {
            // Create a Global Catalog Directory Service Searcher
            string strRootName = directoryEntry.Properties[DirectoryConstants.RootDomainNamingContext].Value.ToString();
            using (DirectoryEntry usersBinding = new DirectoryEntry(DirectoryConstants.GlobalCatalogProtocol + strRootName))
            {
                directorySearcher.SearchRoot = usersBinding;
                directorySearcher.ClientTimeout = timeout;
                directorySearcher.CacheResults = true;
                result = true;
                initialized = true;
            }
        }

DirectoryConstants 类属性

public static string RootDSE { get { return @"GC://rootDSE"; } }
public static string RootDomainNamingContext { get { return "rootDomainNamingContext"; } }
public static string GlobalCatalogProtocol { get { return @"GC://"; } }

我确信这仅适用于登录到域注册 PC 的域用户。身份验证在幕后自动处理。如果您的用户登录到本地帐户或计算机不在域中,您很可能会收到 DirectoryServicesCOMException。

希望这可以帮助。如果您不担心处置和 StyleCop/Sonar 编码违规,请放弃“使用”结构!

上面代码所在的 DirectorySearcherWrapper 类然后由服务提供者代码使用。它是这样分离的,因此可以很容易地模拟出来,因为不能保证构建机器在执行我们的单元测试时注册到域。

...其中大部分来自 MSDN/.Net 文档。

于 2012-09-20T12:31:46.500 回答
2

查询全局编录是正确的方法。

您可能想查看不明确的名称解析 (ANR) - http://support.microsoft.com/kb/243299

于 2012-04-23T19:44:53.647 回答