Ich versuche, alle direkten Berichte eines Benutzers rekursiv über Active Directory abzurufen. Also gegeben ein Benutzer, ich werde mit einer Liste aller Benutzer enden, die diese Person als Manager haben oder die eine Person als Manager haben, der eine Person als Manager hat ... wer hat schließlich den eingegebenen Benutzer als Manager.Alle direkten Berichte aus Active Directory abrufen
Mein aktueller Versuch ist ziemlich langsam:
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;
}
Im Wesentlichen diese Funktion nimmt einen Distinguished Name als Eingang (CN = Michael Stum, OU = Test, DC = sub, DC = Domain, DC = com) und damit ist der Aufruf von ds.FindOne() langsam.
Ich fand, dass es viel schneller ist, nach dem userPrincipalName zu suchen. Mein Problem: sr.Properties ["directReports"] ist nur eine Liste von Strings, und das ist der distinguishedName, der langsam zu suchen scheint.
Ich frage mich, gibt es eine schnelle Möglichkeit, zwischen DistinguishedName und UserPrincipalName zu konvertieren? Oder gibt es eine schnellere Möglichkeit, nach einem Benutzer zu suchen, wenn ich nur den distinguishedName zur Verfügung habe?
Bearbeiten: Dank der Antwort! Durch die Suche im Manager-Feld wurde die Funktion von 90 Sekunden auf 4 Sekunden verbessert. Hier ist die neue und verbesserte Code, die schneller und besser lesbar ist (beachten Sie, dass es wahrscheinlich ein Fehler in der elapsedTime Funktionalität, aber der eigentliche Kern der Funktion funktioniert):
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;
}
Sie können zusätzliche Geschwindigkeit gewinnen, indem Sie DirectoryEntry und DirectorySearcher aus der Rekursion nehmen. Sie ändern sich nicht dazwischen, oder? – Tomalak
Nicht mehr. Was ich nicht gesagt habe: Ich verwende dies in einer Sharepoint-Umgebung, in der der Aufruf in einen SPSecurity.RunWithElevatedPrivileges-Aufruf eingeschlossen ist, was bedeutet, dass ref-Parameter nicht möglich sind, und ich bin mir nicht sicher, ob die Übergabe als normaler Parameter funktioniert (komisch) Sharepoint Security) –
Ich denke, es sollte funktionieren. Objekte werden immer als ref übergeben, AFAIK. Siehe: http://stackoverflow.com/questions/186891/why-use-ref-keyword-when-passing-an-object – Tomalak