Search code examples
c#active-directoryuserprincipaldirectorysearcher

PrincipalSearcher not following underlying DirectorySearcher's Filter


I've been working on a bit of code to search Active Directory using C# and the System.DirectoryServices.AccountManagement namespace.

The issue I've encountered is that PrincipalSearcher cannot do an OR query, so if I wanted to search for users by their email address OR SamAccountName, it isn't possible.

To get around this, it seems that PrincipalSearcher uses DirectorySearcher in the background, so you can access the DirectorySearcher and set it up however you'd like (using GetUnderlyingSearcher), for some reason though it won't follow the DirectorySearcher filter that I've specified.

PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "localhost");
UserPrincipal usrPrinc = new UserPrincipal(ctx);

PrincipalSearcher searchPrinc = new PrincipalSearcher { QueryFilter = usrPrinc };
DirectorySearcher searchdirectory = searchPrinc.GetUnderlyingSearcher() as DirectorySearcher;

searchdirectory.Filter = "(&(objectClass=user)(objectcategory=person)(|(name=*admin*)(samaccountname=*admin*)))";
searchdirectory.Sort.PropertyName = "name";
searchdirectory.SizeLimit = 10;

var results = searchPrinc.FindAll();

The above returns the correct amount of results based on the SizeLimit (10) and does sort it correctly by the PropertyName, but it won't use the Filter option at all.

Is there any way to set up a PrincipalSearcher to use an OR filter (without querying all users and filtering client side) or get it to properly use the Filter option?

I have a working method using DirectoryEntry and DirectorySearcher but was looking for the simplicity and methods that a UserPrincipal provides.


Solution

  • It seems you can't.

    I'm looking a the source code of the .NET Core implementation, but I think we can assume the .NET 4.x implementation is similar, if not exactly the same.

    PrincipalSearcher.FindAll() calls ADStoreCtx_Query.Query(), which calls an internal method called PushFilterToNativeSearcher(), which starts messing with the filter, overwriting whatever you might have put there.

    I've done a bit of searching for an alternative, but there's nothing good. You're better off using DirectorySearcher directly.

    The AccountManagement namespace sometimes makes things easy, but I keep coming back to DirectoryServices for reasons like this. Even performance - AccountManagement can perform much worse in some cases.