ActiveDirectory with Range 不改变使用 DirectorySearcher 的结果

问题描述 投票:0回答:2

所以我基本上是在尝试枚举 AD 的结果,由于某种原因我无法提取新结果,这意味着它会不断提取前 1500 个结果,即使我告诉它我想要一个额外的范围。

有人可以指出我在哪里犯了错误吗?代码永远不会跳出循环,但更重要的是,即使我说我想要用户 1500-3000,它也会吸引 1-1500 的用户。

uint rangeStep = 1500;   
uint rangeLow = 0;   
uint rangeHigh = rangeLow + (rangeStep - 1);   
bool lastQuery = false;   
bool quitLoop = false;   

do   
{                       
    string attributeWithRange;   
    if (!lastQuery)   
    {   
        attributeWithRange = String.Format("member;Range={0}-{1}", rangeLow, rangeHigh);   
    }   
    else   
    {   
        attributeWithRange = String.Format("member;Range={0}-*", rangeLow);   
    }   
    DirectoryEntry dEntryhighlevel = new DirectoryEntry("LDAP://OU=C,OU=x,DC=h,DC=nt");   
    DirectorySearcher dSeacher = new DirectorySearcher(dEntryhighlevel,"(&(objectClass=user)(memberof=CN=Users,OU=t,OU=s,OU=x,DC=h,DC=nt))",new string[] {attributeWithRange});   
    dSeacher.PropertiesToLoad.Add("givenname");   
    dSeacher.PropertiesToLoad.Add("sn");   
    dSeacher.PropertiesToLoad.Add("samAccountName");   
    dSeacher.PropertiesToLoad.Add("mail");   
    dSeacher.PageSize = 1500;   
    SearchResultCollection resultCollection = resultCollection = dSeacher.FindAll();   
    dSeacher.Dispose();   

    foreach (SearchResult userResults in resultCollection)   
    {   

        string Last_Name = userResults.Properties["sn"][0].ToString();   
        string First_Name = userResults.Properties["givenname"][0].ToString();   
        string userName = userResults.Properties["samAccountName"][0].ToString();   
        string Email_Address = userResults.Properties["mail"][0].ToString();   
        OriginalList.Add(Last_Name + "|" + First_Name + "|" + userName + "|" + Email_Address);   
    }   
    if(resultCollection.Count == 1500)   
    {   
        lastQuery = true;   
        rangeLow = rangeHigh + 1;   
        rangeHigh = rangeLow + (rangeStep - 1);   
    }   
    else   
    {   
        quitLoop = true;   
    }   

}   
while (!quitLoop);
c# active-directory
2个回答
2
投票

你混淆了两个概念,这是给你带来麻烦的原因。这是 SO 论坛上的一个常见问题解答,所以我可能应该写博客来尝试把事情弄清楚。

让我先解释一下概念,然后在概念出来后更正代码。

概念一是获取大量对象。当你取到很多对象时,你需要分批去取。 这通常称为 paging 通过结果。当您执行此操作时,您将取回一个分页 cookie,并可以在后续搜索中传回分页控件,以便每次通过时都能获得“页面价值”的结果。

第二个概念是从单个属性中获取大量值。一个简单的例子是从一个组中读取成员属性(例如:对该组进行基本搜索)。 这叫做远程检索。在这种搜索模式下,您正在针对大型属性(如成员)对该对象进行基本搜索,并在每次通过搜索时询问值的“范围”。

上面的代码混淆了这些概念。您正在执行成员范围逻辑,就像您正在执行范围检索一样,但实际上您正在执行一个搜索,该搜索被构造为返回大量对象,如分页搜索。这就是为什么你一遍又一遍地得到相同的结果。

要解决这个问题,您需要先选择一种方法。 :) 我建议针对组对象进行范围检索,并要求范围中的大成员属性。这将使您获得该组中的所有成员。 如果沿着这条路走下去,您会注意到您不能为这些值请求属性。您获得的唯一值是成员列表,然后您可以搜索他们。 如果您选择像上面那样使用分页搜索,那么您最终会切换到分页搜索。

如果您选择坚持分页搜索,那么您需要:

  • 摆脱范围逻辑,以及所有提及 1500
  • 将页面大小设置为 1000
  • 而不是范围,查找如何使用您的 API 进行分页搜索(使用页面搜索控件)

如果您选择范围,您将从这样的 memberOf 搜索切换到以下形式的搜索:

  • 范围:基地

  • 过滤器:(对象类=*)

  • 基础 DN:OU=C,OU=x,DC=h,DC=nt

  • 属性:成员;范围=0-*...

然后您将在获取值范围时递增 0(即,对每个后续值范围反复执行此搜索,仅将 0 更改为后续整数)

您会在我的逻辑中注意到的其他要点:

  • 我没有设置页面大小......你不是在进行分页搜索,所以没关系。
  • 我从来没有在这里硬编码值 1500。没关系。知道甚至计算它都没有任何价值。关键是你要求 0-*(即全部),你得到 1500,然后你说 1500-,然后 3000-,依此类推。你不需要知道范围大小,只需要知道到目前为止你已经得到的。

我希望这能完全回答...

根据我在下面的评论,这是进行分页搜索 的代码片段(这是您使用 System.DirectoryServices.Protocols 命名空间类需要执行的操作,沿着您在上面开始的逻辑路径(分页搜索, 不是远程检索)):

        string searchFilter = "(&(objectClass=user)(memberof=CN=Users,OU=t,OU=s,OU=x,DC=h,DC=nt))";
        string baseDN = "OU=C,OU=x,DC=h,DC=nt";
        var scope = SearchScope.Subtree;
        var attributeList = new string[] { "givenname", "sn", "samAccountName", "mail" };
        PageResultRequestControl pageSearchControl = new PageResultRequestControl(1000);
        do
        {
            SearchRequest sr = new SearchRequest(baseDN, searchFilter, scope, attributeList);
            sr.Controls.Add(pageSearchControl);

            var directoryResponse = ldapConnection.SendRequest(sr);
            if (directoryResponse.ResultCode != ResultCode.Success)
            {
                // Handle error
            }

            var searchResponse = (SearchResponse)directoryResponse;

            pageSearchControl = null; // Reset!
            foreach (var control in searchResponse.Controls)
            {
                if (control is PageResultResponseControl)
                {
                    var prrc = (PageResultResponseControl)control;
                    if (prrc.Cookie.Length > 0)
                    {
                        pageSearchControl = new PageResultRequestControl(prrc.Cookie);
                    }
                }
            }

            foreach (var entry in searchResponse.Entries)
            {
                // Handle the search result entry
            }
        } while (pageSearchControl != null);

-1
投票

您的问题是由循环创建目录搜索器的新对象引起的。每次都会有新对象获取前 1500 条记录。在循环外创建搜索器实例,并对所有查询使用相同的实例。

© www.soinside.com 2019 - 2024. All rights reserved.