Getting all direct Reports from Active Directory(从 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"属性是您要查找的人的所有对象,然后迭代它们.这通常应该比其他方式更快.</p>
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 获取所有直接报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:从 Active Directory 获取所有直接报告
				
        
 
            
        - 是否可以在 .Net 3.5 中进行通用控件? 2022-01-01
 - 使用 rss + c# 2022-01-01
 - Azure Active Directory 与 MVC,客户端和资源标识同一 2022-01-01
 - 带问号的 nvarchar 列结果 2022-01-01
 - C# 通过连接字符串检索正确的 DbConnection 对象 2022-01-01
 - 在 LINQ to SQL 中使用 contains() 2022-01-01
 - 在 C# 中异步处理项目队列 2022-01-01
 - CanBeNull和ReSharper-将其用于异步任务? 2022-01-01
 - Windows 喜欢在 LINUX 中使用 MONO 进行服务开发? 2022-01-01
 - 为什么 C# 中的堆栈大小正好是 1 MB? 2022-01-01
 
						
						
						
						
						