2008-10-10 28 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工作?

編輯:感謝您的答案!搜索管理器字段將功能從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 2008-10-10 09:35:19

+0

不再。我沒有說的:我在Sharepoint環境中使用這個函數,調用被封裝在SPSecurity.RunWithElevatedPrivileges調用中,這意味着ref參數是不可能的,我不確定是否將它作爲普通參數傳遞(奇怪Sharepoint安全) – 2008-10-10 09:59:31

回答

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. 

編輯:設置SearchRoot到對象的DN和SearchScopeBase也就是拉一個對象了AD的快速方式。

相關問題