8

I use this code:

DirectoryEntry objEntry;
DirectorySearcher objSearchEntry;
SearchResultCollection objSearchResult;
string strFilter = "(&(objectCategory=User))";
objEntry = new DirectoryEntry(conOUPath, conUser, conPwd, AuthenticationTypes.Secure);
objEntry.RefreshCache();
objSearchEntry = new DirectorySearcher(objEntry);
objSearchEntry.Filter=strFilter;
objSearchEntry.SearchScope=SearchScope.Subtree;
objSearchEntry.CacheResults=false;
objSearchResult=objSearchEntry.FindAll();

Each time, it only return 1000 users, but there are 3000 users in that OU.

How can i find all of them ?

skaffman
  • 398,947
  • 96
  • 818
  • 769
cciikk
  • 115
  • 2
  • 2
  • 5

2 Answers2

10

If you're on .NET 3.5 or newer, you should check out the PrincipalSearcher and a "query-by-example" principal to do your searching:

// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");

// define a "query-by-example" principal - here, we search for a UserPrincipal 
// and with the first name (GivenName) of "Bruce"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "Bruce";

// create your principal searcher passing in the QBE principal    
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);

// set the PageSize on the underlying DirectorySearcher to get all 3000 entries
((DirectorySearcher)srch.GetUnderlyingSearcher()).PageSize = 500;

// find all matches
foreach(var found in srch.FindAll())
{
    // do whatever here - "found" is of type "Principal" - it could be user, group, computer.....          
}

If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement

Update:

Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:

  • Surname (or last name)
  • DisplayName (typically: first name + space + last name)
  • SAM Account Name - your Windows/AD account name
  • User Principal Name - your "username@yourcompany.com" style name

You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher.

Update #2: If you want to search just inside a given OU, you can define that OU in the constructor of the PrincipalContext.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • but i want to filter by OU ,and get a result of all type is user in that OU, here is no keyword to search – cciikk Jul 17 '11 at 10:01
  • @cciikk: see my update - you can limit your search to a specific container by defining that in the constructor of the `PrincipalContext` – marc_s Jul 17 '11 at 10:31
  • O my god! the efficiency is too low ... 20 thousand users spand more than 30 minutes – cciikk Jul 17 '11 at 14:20
  • 1
    @cciikk, my experience with LDAp searching has been that the fastest way is to use DirectorySearcher and iterate through the results. Also don'tforget the using keyword or you will get a memory leak. – Can Gencer Jul 17 '11 at 16:38
  • 2
    @cciikk - Principal Searcher is slow, as you noticed. The reason why is because after it internally runs a DirectorySearcher of it's own it enumerates through each of the returnted items and retrieves the directoryentry. So the total number of LDAP calls is 1+n (n=result count). I found that Can Gencer and I think alike, I too just settled for using the DirectorySearcher and putting all of the attributes I wanted to have returned, way way faster that way. – Peter Jul 29 '11 at 14:35
  • @Patricker, yes getting a DirectoryEntry for each result is extremely slow compared to just iterating through the results of the DirectorySearcher. I've had the same experience with it as well. – Can Gencer Jul 30 '11 at 09:07
6

You need to set the DirectorySearcher.PageSize property to be able to return all the results. For example:

objSearchEntry.PageSize = 500;

Otherwise the number of items returned will be limited by the limit on the server side, which is 1000 by default. There is also something called SizeLimit, which you can set if you want to explicitly limit the number of returned items. If both SizeLimit and PageSize are 0 (default values) then it will use the server side default SizeLimit. A bit counter-intuitive in my opinion.

If you want to return all the results, the only way is to set PageSize to a non-zero value and SizeLimit to 0.

Can Gencer
  • 8,822
  • 5
  • 33
  • 52
  • it return all user in the AD ,can it filter by OU's objectGUID ? – cciikk Jul 17 '11 at 10:26
  • Then you need to bind the DirectorySearcher to the DirectoryEntry that is the OU you want. i.e. the objEntry should be the OU that you want to search for users under. – Can Gencer Jul 17 '11 at 11:17