从 Active Directory 获取所有直接报告

时间:2022-11-26
本文介绍了从 Active Directory 获取所有直接报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我正在尝试通过 Active Directory 递归地获取用户的所有直接报告.所以给定一个用户,我最终会得到一个所有用户的列表,这些用户有这个人作为经理,或者有一个人作为经理,有一个人作为经理......最终将输入用户作为经理.

I'm trying to get all the direct reports of a User through Active Directory, recursively. So given a user, i will end up with a list of all users who have this person as manager or who have a person as manager who has a person as manager ... who eventually has the input user as manager.

我目前的尝试相当缓慢:

My current attempt is rather slow:

private static Collection<string> GetDirectReportsInternal(string userDN, out long elapsedTime)
{
    Collection<string> result = new Collection<string>();
    Collection<string> reports = new Collection<string>();

    Stopwatch sw = new Stopwatch();
    sw.Start();

    long allSubElapsed = 0;
    string principalname = string.Empty;

    using (DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("LDAP://{0}",userDN)))
    {
        using (DirectorySearcher ds = new DirectorySearcher(directoryEntry))
        {
            ds.SearchScope = SearchScope.Subtree;
            ds.PropertiesToLoad.Clear();
            ds.PropertiesToLoad.Add("directReports");
            ds.PropertiesToLoad.Add("userPrincipalName");
            ds.PageSize = 10;
            ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
            SearchResult sr = ds.FindOne();
            if (sr != null)
            {
                principalname = (string)sr.Properties["userPrincipalName"][0];
                foreach (string s in sr.Properties["directReports"])
                {
                    reports.Add(s);
                }
            }
        }
    }

    if (!string.IsNullOrEmpty(principalname))
    {
        result.Add(principalname);
    }

    foreach (string s in reports)
    {
        long subElapsed = 0;
        Collection<string> subResult = GetDirectReportsInternal(s, out subElapsed);
        allSubElapsed += subElapsed;

        foreach (string s2 in subResult)
        {
        result.Add(s2);
        }
    }



    sw.Stop();
    elapsedTime = sw.ElapsedMilliseconds + allSubElapsed;
    return result;
}

本质上,这个函数将一个可分辨的名称作为输入(CN=Michael Stum,OU=test,DC=sub,DC=domain,DC=com),因此,对 ds.FindOne() 的调用很慢.

Essentially, this function takes a distinguished Name as input (CN=Michael Stum, OU=test, DC=sub, DC=domain, DC=com), and with that, the call to ds.FindOne() is slow.

我发现搜索 userPrincipalName 的速度要快得多.我的问题:sr.Properties["directReports"] 只是一个字符串列表,也就是distinguishedName,搜索起来似乎很慢.

I found that it is a lot faster to search for the userPrincipalName. My Problem: sr.Properties["directReports"] is just a list of strings, and that is the distinguishedName, which seems slow to search for.

我想知道,有没有一种快速的方法可以在 distinctName 和 userPrincipalName 之间进行转换?或者,如果我只有可使用的专有名称,是否有更快的方法来搜索用户?

I wonder, is there a fast way to convert between distinguishedName and userPrincipalName? Or is there a faster way to search for a user if I only have the distinguishedName to work with?

感谢您的回答!搜索经理字段将功能从 90 秒改进为 4 秒.这是新的和改进的代码,它更快、更易读(请注意,elapsedTime 功能中很可能存在错误,但该函数的实际核心是有效的):

Thanks to the answer! Searching the Manager-Field improved the function from 90 Seconds to 4 Seconds. Here is the new and improved code, which is faster and more readable (note that there is most likely a bug in the elapsedTime functionality, but the actual core of the function works):

private static Collection<string> GetDirectReportsInternal(string ldapBase, string userDN, out long elapsedTime)
{
    Collection<string> result = new Collection<string>();

    Stopwatch sw = new Stopwatch();
    sw.Start();
    string principalname = string.Empty;

    using (DirectoryEntry directoryEntry = new DirectoryEntry(ldapBase))
    {
        using (DirectorySearcher ds = new DirectorySearcher(directoryEntry))
        {
            ds.SearchScope = SearchScope.Subtree;
            ds.PropertiesToLoad.Clear();
            ds.PropertiesToLoad.Add("userPrincipalName");
            ds.PropertiesToLoad.Add("distinguishedName");
            ds.PageSize = 10;
            ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
            ds.Filter = string.Format("(&(objectCategory=user)(manager={0}))",userDN);

            using (SearchResultCollection src = ds.FindAll())
            {
                Collection<string> tmp = null;
                long subElapsed = 0;
                foreach (SearchResult sr in src)
                {
                    result.Add((string)sr.Properties["userPrincipalName"][0]);
                    tmp = GetDirectReportsInternal(ldapBase, (string)sr.Properties["distinguishedName"][0], out subElapsed);
                    foreach (string s in tmp)
                    {
                    result.Add(s);
                    }
                }
            }
          }
        }
    sw.Stop();
    elapsedTime = sw.ElapsedMilliseconds;
    return result;
}

推荐答案

首先,当您已经拥有要查找的 DN 时,不需要将 Scope 设置为subtree".

First off, setting Scope to "subtree" is unnecessary when you already have the DN you are looking for.

此外,如何查找manager"属性是您要查找的人的所有对象,然后迭代它们.这通常应该比其他方式更快.

Also, how about finding all objects whose "manager" property is the person you look for, then iterating them. This should generally be faster than the other way around.

(&(objectCategory=user)(manager=<user-dn-here>))

以下内容很重要,但到目前为止仅在对此答案的评论中提及:

当过滤器字符串按上述方式构建时,存在用对 DN 有效但在过滤器中具有特殊含义的字符破坏它的风险.这些必须转义:

When the filter string is built as indicated above, there is the risk of breaking it with characters that are valid for a DN, but have special meaning in a filter. These must be escaped:

*   as  2a
(   as  28
)   as  29
   as  5c
NUL as  0
/   as  2f

// Arbitrary binary data can be represented using the same scheme.

SearchRoot 设置为对象的 DN,将 SearchScope 设置为 Base 也是一种快速提取单个对象的方法对象脱离 AD.

Setting the SearchRoot to the DN of an object, and the SearchScope to Base also is a fast way to pull a single object out of AD.

这篇关于从 Active Directory 获取所有直接报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:System.DirectoryServices - 服务器无法运行 下一篇:使用 DirectoryServices.AccountManagement 从 OU 获取组

相关文章

最新文章