2008-10-10 4 views
11

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

,이 기능은 입력으로 고유 이름을 사용합니다 (CN = 마이클 방부제로 발효를 막다, OU = 테스트, DC = 서브, DC = 도메인, 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; 
} 
+0

DirectoryEntry 및 DirectorySearcher를 재귀에서 제외하면 속도가 향상 될 수 있습니다. 그들은 변화하지 않는다. – Tomalak

+0

더 이상 없습니다. 내가 말하지 않은 것은 :이 매개 변수는 SPSecurity.RunWithElevatedPrivileges 호출로 둘러싸인 Sharepoint 환경에서 사용됩니다. 즉, ref 매개 변수가 가능하지 않으며 일반적인 매개 변수로 전달하는 것이 확실하지 않습니다. 이상한 Sharepoint Security) –

+0

나는 그것이 작동해야한다고 생각한다. 객체는 항상 ref, AFAIK로 전달됩니다. 참조 : http://stackoverflow.com/questions/186891/why-use-ref-keyword-when-passing-an-object – Tomalak

답변

10

첫째을, 범위 설정 찾고있는 DN이 ​​이미있는 경우 "하위 트리"로 이동하는 것은 불필요합니다.

"관리자"속성을 찾는 모든 객체를 찾은 다음 반복합니다. 일반적으로 다른 방법보다 빠릅니다.

(&(objectCategory=user)(manager=<user-dn-here>)) 

편집 : 그것을 파괴의 위험이있다, 위에 표시된대로 필터 문자열을 빌드 할 때

: 다음은 중요하지만 지금까지이 답변에 코멘트에 언급 된 DN에는 유효하지만 필터에서는 특별한 의미를 갖는 문자가 사용됩니다. 이 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. 

편집 : 또한 AD에서 단일 개체를 끌어 빠른 방법은 개체의 DN에 SearchRootBaseSearchScope 설정.

+0

. 서브 트리없이 어떻게 동작하는지 보겠습니다. 두 번째 제안에 대해서는 흥미로운 것 같습니다. 함수를 반복해야 할 필요가 있기 때문에 조금 두뇌를 감쌀 필요가 있지만 즉시 테스트 할 것입니다. –

+1

10 번 투표 할 수 있다면 그렇게 할 것입니다. 관리자 검색 기능을 사용하면 90 초에서 4 초로 향상되었습니다. –

+0

이 방법을 사용하면 DN에서 유효하지만 필터 문자열에 예약 된 문자로 필터 문자열을 깨뜨릴 위험을 마이그레이션해야합니다. 내 머리 꼭대기에서 최소한 "#"은 탈출해야합니다. – Tomalak

관련 문제