76

I just noticed that the return list for results is limited to 1000. I have more than 1000 groups in my domain (HUGE domain). How can I get more than 1000 records? Can I start at a later record? Can I cut it up into multiple searches?

Here is my query:

DirectoryEntry dirEnt = new DirectoryEntry("LDAP://dhuba1kwtn004");
string[] loadProps = new string[] { "cn", "samaccountname", "name", "distinguishedname" };
DirectorySearcher srch = new DirectorySearcher(dirEnt, "(objectClass=Group)", loadProps);
var results = srch.FindAll();

I have tried to set srch.SizeLimit = 2000;, but that doesn't seem to work. Any ideas?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
naspinski
  • 34,020
  • 36
  • 111
  • 167
  • It is important to know _what_ we are trying to loop through. We might want to loop through a list of LDAP records (aka DirectoryEntry) **OR** the value (of _list_ type) of an attribute of _single_ LDAP record. Looping through values of an attribute of an LDAP record is required when it is of _list_ type i.e. a list of key-value pairs e.g. Value of _memberOf_ attribute is of _list_ type. This answer explains it : _paging_ through DirectoryEntry records **vs** _Range retrieval_ for list values of an attribute of a DirectoryEntry record - https://stackoverflow.com/a/12274460/465053 – RBT Apr 17 '23 at 05:53

1 Answers1

188

You need to set DirectorySearcher.PageSize to a non-zero value to get all results.

BTW you should also dispose DirectorySearcher when you're finished with it

using(var srch = new DirectorySearcher(dirEnt, "(objectClass=Group)", loadProps))
{
    srch.PageSize = 1000;
    var results = srch.FindAll();
}

The API documentation isn't very clear, but essentially:

  • when you do a paged search, the SizeLimit is ignored, and all matching results are returned as you iterate through the results returned by FindAll. Results will be retrieved from the server a page at a time. I chose the value of 1000 above, but you can use a smaller value if preferred. The tradeoff is: using a small PageSize will return each page of results faster, but will require more frequent calls to the server when iterating over a large number of results.

  • by default the search isn't paged (PageSize = 0). In this case up to SizeLimit results is returned.

As Biri pointed out, it's important to dispose the SearchResultCollection returned by FindAll, otherwise you may have a memory leak as described in the Remarks section of the MSDN documentation for DirectorySearcher.FindAll.

One way to help avoid this in .NET 2.0 or later is to write a wrapper method that automatically disposes the SearchResultCollection. This might look something like the following (or could be an extension method in .NET 3.5):

public IEnumerable<SearchResult> SafeFindAll(DirectorySearcher searcher)
{
    using(SearchResultCollection results = searcher.FindAll())
    {
        foreach (SearchResult result in results)
        {
            yield return result;        
        } 
    } // SearchResultCollection will be disposed here
}

You could then use this as follows:

using(var srch = new DirectorySearcher(dirEnt, "(objectClass=Group)", loadProps))
{
    srch.PageSize = 1000;
    var results = SafeFindAll(srch);
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Joe
  • 122,218
  • 32
  • 205
  • 338
  • 4
    What if the there is an early termination in the foreach? Does the result collection still get released? – kerem Jan 02 '12 at 13:06
  • @kerem Perhaps this is not a timely response to your question, but the `using` causes `Dispose()` to be called on even if there was an exception (uses a `finally` block [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#remarks](to do so) ) – GuacoIV Oct 23 '20 at 18:14
  • @Joe For some reason I'm finding that "by default the search isn't paged (PageSize = 0). In this case up to SizeLimit results is returned." doesn't appear to be true when using a `PrincipalSearcher` that has underlying `DirectorySearcher`. It just keeps right on enumerating results. Perhaps the server side or `PrincipalSearcher` overrides this somehow... – GuacoIV Oct 23 '20 at 18:18
  • 1
    @GuacoIV - it's quite likely that `PrincipalSearcher` is overriding the default behavior, especially since it doesn't expose the `PageSize` and `SizeLimit` properties. You could probably confirm this by examining the `DirectorySearcher` returned by `PrincipalSearcher.GetUnderlyingSearcher` method to see how it's been configured. – Joe Oct 23 '20 at 20:12
  • You will find a lot of posts on the web about this. Some are really confusing and seem to suggest that no matter what you do there is a server side setting to ruin your day. In AD 2012 onwards, this is the correct answer to retrieve any number of objects using DirectorySearcher. I've tried it for 18k results. srch.PageSize = int.MaxValue. Works a treat. – NadimAJ Nov 22 '20 at 15:04