获得从Active Directory中的所有直接报告 [英] Getting all direct Reports from Active Directory

查看:223
本文介绍了获得从Active Directory中的所有直接报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想获得一个用户的所有直接报告通过Active Directory,递归。 所以,有了用户,我将结束与谁拥有该人为经理或谁拥有人以经理人谁拥有人以经理人......谁最终拥有输入用户作为经理的所有用户的列表。

我现在的尝试是相当缓慢的:

 私有静态收集和LT;字符串> GetDirectReportsInternal(字符串用户DN,出长elapsedTime)
{
    收藏<字符串>结果=新的集合<字符串>();
    收藏<字符串>报告=新的集合<字符串>();

    秒表SW =新的秒表();
    sw.Start();

    长allSubElapsed = 0;
    串生成PrincipalName =的String.Empty;

    使用(的DirectoryEntry的DirectoryEntry =新的DirectoryEntry(的String.Format(LDAP:// {0},用户DN)))
    {
        使用(DirectorySearcher从DS =新DirectorySearcher从(的DirectoryEntry))
        {
            ds.SearchScope = SearchScope.Subtree;
            ds.PropertiesToLoad.C​​lear();
            ds.PropertiesToLoad.Add(directReports);
            ds.PropertiesToLoad.Add(的UserPrincipalName);
            ds.PageSize = 10;
            ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
            信息搜索结果SR = ds.FindOne();
            如果(SR!= NULL)
            {
                生成PrincipalName =(字符串)sr.Properties [的UserPrincipalName] [0];
                的foreach(字符串s在sr.Properties [directReports])
                {
                    reports.Add(多个);
                }
            }
        }
    }

    如果(!string.IsNullOrEmpty(生成PrincipalName))
    {
        result.Add(生成PrincipalName);
    }

    的foreach(字符串s在报告中)
    {
        长subElapsed = 0;
        收藏<字符串>子结果= GetDirectReportsInternal(S,出subElapsed);
        allSubElapsed + = subElapsed;

        的foreach(在子结果字符串s2)
        {
        result.Add(S2);
        }
    }



    sw.Stop();
    elapsedTime = sw.ElapsedMilliseconds + allSubElapsed;
    返回结果;
}
 

从本质上讲,这个功能需要一个专有名称作为输入(CN =迈克尔葡萄汁,OU =测试,DC =子,DC =域,DC = COM),并与中,调用ds.FindOne()是缓慢的

我发现它是快了很多搜索的UserPrincipalName。我的问题:sr.Properties [directReports]只是一个字符串列表,那就是distinguishedName来,这似乎慢搜索

我不知道,有没有快速的方法来distinguishedName来和的UserPrincipalName之间的转换?或者是有搜索用户,如果我只有distinguishedName来一起工作呢?一个更快的方法

编辑:多亏了答案!搜索管理器场改善从90秒的功能到4秒。这是新的和改进的code,这是更快,更可读的(注意,是最有可能在elapsedTime功能中的错误,但是功能的实际核心工程):

 私有静态收集和LT;字符串> GetDirectReportsInternal(字符串ldapBase,字符串用户DN,出长elapsedTime)
{
    收藏<字符串>结果=新的集合<字符串>();

    秒表SW =新的秒表();
    sw.Start();
    串生成PrincipalName =的String.Empty;

    使用(的DirectoryEntry的DirectoryEntry =新的DirectoryEntry(ldapBase))
    {
        使用(DirectorySearcher从DS =新DirectorySearcher从(的DirectoryEntry))
        {
            ds.SearchScope = SearchScope.Subtree;
            ds.PropertiesToLoad.C​​lear();
            ds.PropertiesToLoad.Add(的UserPrincipalName);
            ds.PropertiesToLoad.Add(的distinguishedName);
            ds.PageSize = 10;
            ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
            ds.Filter =的String.Format((及(objectCategory属性=用户)(经理= {0})),用户DN);

            使用(SearchResultCollection SRC = ds.FindAll())
            {
                收藏<字符串> TMP = NULL;
                长subElapsed = 0;
                的foreach(在SRC信息搜索结果SR)
                {
                    result.Add((串)sr.Properties [的UserPrincipalName] [0]);
                    TMP = GetDirectReportsInternal(ldapBase,(串)sr.Properties [的distinguishedName] [0],出subElapsed);
                    的foreach(字符串s在TMP)
                    {
                    result.Add(多个);
                    }
                }
            }
          }
        }
    sw.Stop();
    elapsedTime = sw.ElapsedMilliseconds;
    返回结果;
}
 

解决方案

首先,设定范围为树是不必要的,当你已经拥有你所寻找的DN。

另外,如何寻找到的所有对象的经理属性是你找的人,然后遍历它们。这一般应比其他方式更快。<​​/ P>

 (及(objectCategory属性=用户)(经理=&lt;使用者-DN-这里&GT;))
 

编辑:下面是重要的,但只被提到的意见,这个答案至今:

在过滤字符串是建立如上所述,不存在具有该有效期为一个DN字符打破它的危险性,但有在过滤器中的特殊含义。这些必须转义

  *作为\ 2A
(如\ 28
)作为\ 29
\为\ 5C
NUL为\ 00
/为\ 2F

//使用相同的方式任意的二进制数据可以被重新presented。
 

编辑:设置 SearchRoot 为对象的DN,而 SearchScope的基本也是一个快速的方法来拉一个对象了AD的。

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;
}

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.

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.

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?

Edit: 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;
}

解决方案

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

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>))

EDIT: The following is important but has only been mentioned in the comments to this answer so far:

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  \00
/   as  \2f

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

EDIT: 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中的所有直接报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆