Mic*_*tum 12 c# ldap active-directory
我试图通过递归方式通过Active Directory获取用户的所有直接报告.因此,给定一个用户,我最终会得到一个列表,其中列出了所有以此人为经理的人或者有一个人作为经理,他有一个人作为经理......他最终将输入用户作为经理.
我目前的尝试相当缓慢:
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;
}
Run Code Online (Sandbox Code Playgroud)
本质上,此函数将一个可分辨的名称作为输入(CN = Michael Stum,OU = test,DC = sub,DC = domain,DC = com),因此,对ds.FindOne()的调用很慢.
我发现搜索userPrincipalName要快得多.我的问题:sr.Properties ["directReports"]只是一个字符串列表,这就是distinguishedName,它似乎很难搜索.
我想知道,有没有一种快速的方法来在distinguishedName和userPrincipalName之间进行转换?或者,如果我只使用distinguishedName,那么搜索用户的方法是否更快?
编辑:谢谢你的回答!搜索Manager-Field将功能从90秒提高到4秒.这是新的和改进的代码,它更快,更易读(请注意,elapsedTime功能中很可能存在错误,但该函数的实际核心有效):
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;
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*lak 10
首先,如果您已经拥有要查找的DN,则无需将Scope设置为"子树".
此外,如何查找"manager"属性是您查找的人的所有对象,然后迭代它们.这应该通常比其他方式更快.
(&(objectCategory=user)(manager=<user-dn-here>))
Run Code Online (Sandbox Code Playgroud)
编辑:以下是重要的,但到目前为止只在答案的评论中提到:
如上所述构建过滤器字符串时,存在使用对DN有效的字符将其分解但在过滤器中具有特殊含义的风险.这些必须转义:
* as \2a
( as \28
) as \29
\ as \5c
NUL as \00
/ as \2f
// Arbitrary binary data can be represented using the same scheme.
Run Code Online (Sandbox Code Playgroud)
编辑:设置SearchRoot对象的DN,而SearchScopeto Base也是从AD中拉出单个对象的快速方法.
| 归档时间: |
|
| 查看次数: |
15793 次 |
| 最近记录: |