从Active Directory获取所有直接报告

我试图通过递归方式通过Active Directory获取用户的所有直接报告。 因此,给定一个用户,我将得到一个列表,其中列出了所有将此人作为经理或者有一个人作为经理的人,他有一个人作为经理…最终将输入用户作为经理。

我目前的尝试相当缓慢:

private static Collection GetDirectReportsInternal(string userDN, out long elapsedTime) { Collection result = new Collection(); Collection reports = new Collection(); 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 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()的调用很慢。

我发现搜索userPrincipalName要快得多。 我的问题:sr.Properties [“directReports”]只是一个字符串列表,这是distinguishedName,它似乎很难搜索。

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

编辑:谢谢你的回答! 搜索Manager-Field将function从90秒改进为4秒。 这是新的和改进的代码,它更快,更易读(请注意,elapsedTimefunction中很可能存在错误,但该函数的实际核心有效):

 private static Collection GetDirectReportsInternal(string ldapBase, string userDN, out long elapsedTime) { Collection result = new Collection(); 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 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设置为“子树”是不必要的。

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

 (&(objectCategory=user)(manager=)) 

编辑:以下是重要的,但到目前为止只在答案的评论中提到:

如上所示构建filter字符串时,存在使用对DN有效的字符将其分解的风险,但在filter中具有特殊含义。 这些必须转义 :

 * as \2a ( as \28 ) as \29 \ as \5c NUL as \00 / as \2f // Arbitrary binary data can be represented using the same scheme. 

编辑:将SearchRoot设置为对象的DN,将SearchRoot设置为Base也是将单个对象拉出AD的快速方法。