J'essaie d'obtenir tous les rapports directs d'un utilisateur via Active Directory, de manière récursive. Donc, vu un utilisateur, je finirai avec une liste de tous les utilisateurs qui ont cette personne en tant que manager ou qui ont une personne en tant que manager qui a une personne en tant que manager ... qui a finalement l'utilisateur en entrée en tant que manager.Obtention de tous les rapports directs à partir d'Active Directory
Ma tentative actuelle est plutôt lent:
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;
}
Essentiellement, cette fonction prend un nom distinctif en entrée (CN = Michael Stum, OU = test, DC = sous, DC = domain, DC = com) , et avec cela, l'appel à ds.FindOne() est lent.
J'ai trouvé qu'il est beaucoup plus rapide de rechercher le userPrincipalName. Mon problème: sr.Properties ["directReports"] est juste une liste de chaînes, et c'est le distinguishedName, qui semble lent à chercher.
Je me demande, existe-t-il un moyen rapide de convertir entre distinguishedName et userPrincipalName? Ou y a-t-il un moyen plus rapide de rechercher un utilisateur si je n'ai que le distinguishedName avec lequel travailler?
Modifier: Grâce à la réponse! La recherche dans Manager-Field a amélioré la fonction de 90 secondes à 4 secondes. Voici le nouveau et l'amélioration du code, ce qui est plus rapide et plus lisible (notez qu'il ya très probablement un bug dans la fonctionnalité elapsedTime, mais le véritable noyau de la fonction fonctionne):
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;
}
Vous pouvez obtenir une vitesse supplémentaire en supprimant DirectoryEntry et DirectorySearcher de la récursivité. Ils ne changent pas entre eux, n'est-ce pas? – Tomalak
Plus maintenant. Ce que je n'ai pas dit: Je l'utilise dans un Sharepoint Environment où l'appel est enveloppé dans un appel SPSecurity.RunWithElevatedPrivileges, ce qui signifie que ref Parameters n'est pas possible, et je ne suis pas sûr que le passer comme un paramètre normal fonctionne (bizarre Sharepoint Security) –
Je pense que ça devrait marcher. Les objets sont toujours passés comme ref, AFAIK. Voir: http://stackoverflow.com/questions/186891/why-use-ref-keyword-when-passing-an-object – Tomalak