Search code examples
c#active-directoryadsi

Active directory Query to narrow down results better than my attempt


My specific Question: How to I narrow down my search for active directory accounts that DO NOT have employeeNumber attribute set (is not null or empty)?

My work around is to go over the results and check the employeeNumber and removing those accounts. However, I would like my query to narrow down the results before I have to filter then manually.

The line that I think is not even firing a filter : ((DirectorySearcher)ps.GetUnderlyingSearcher()).Filter = "(&(objectCategory=Person)(objectClass=User)(!employeeNumber=*))";// I would like for it to return only Ad Accounts that have an employeeNumber set

 PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "myDomain");
                UserPrincipal user = new UserPrincipal(domainContext);
                user.SamAccountName = ParamSamAccountName;
                user.Enabled = true;//only enabled users
                user.PasswordNeverExpires = false; //this should get rid of service accounts

                PrincipalSearcher pS = new PrincipalSearcher();
                pS.QueryFilter = user;

                PrincipalSearcher ps = new PrincipalSearcher(user);
                ((DirectorySearcher)ps.GetUnderlyingSearcher()).PageSize = 500;
               ((DirectorySearcher)ps.GetUnderlyingSearcher()).Filter = "(&(objectCategory=Person)(objectClass=User)(!(employeeNumber=*)))";//this doesnt seem to be working... bug...
                var searchResults = SafeFindAll(ps);



      private static IEnumerable<Principal> SafeFindAll(PrincipalSearcher searcher)
            {
                using (var results = searcher.FindAll())
                {
                    foreach (var result in results)
                    {
                        yield return result;
                    }
                } // SearchResultCollection will be disposed here
            }

Solution

  • Your question is a bit confusing. If you want WITHOUT employeeNumber set, then you are correct, if you want WITH employeeNumber set then you need this: (&(objectCategory=Person)(objectClass=User)(employeeNumber=*))

    Additionally you need to make sure you get the LDAP connection. Some code below that might be helpful, also see this blog: http://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C#20

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace LDAPCSharp
    {
    
        using System.DirectoryServices;
        using System.DirectoryServices.ActiveDirectory;
    
        class Program
        {
            static void Main(string[] args)
            {
                var ldapDomain = FriendlyDomainToLdapDomain("domainRemoved");
    
    
                var allResults = FindAllWithEmployeeNumber(ldapDomain);
    
                foreach (var searchResult in allResults)
                {
                    using (var entry = searchResult.GetDirectoryEntry())
                    {
                        foreach (var value in entry.Properties.PropertyNames)
                        {
                            Console.WriteLine(value);
                        }
                    }
                }
            }
    
            /// <summary>
            /// The find all.
            /// </summary>
            /// <param name="ldapDomain">
            /// The ldap domain.
            /// </param>
            /// <returns>
            /// The <see cref="IEnumerable"/>.
            /// </returns>
            public static IEnumerable<SearchResult> FindAllWithEmployeeNumber(string ldapDomain)
            {
                string connectionPrefix = "LDAP://" + ldapDomain;
                DirectoryEntry entry = new DirectoryEntry(connectionPrefix);
                DirectorySearcher mySearcher = new DirectorySearcher(entry);
    
                // all that have employeenumber set
                mySearcher.Filter = "(&(objectCategory=Person)(objectClass=User)(employeeNumber=*))";
    
                // all WITHOUT employeenumber set
                // mySearcher.Filter = (&(objectCategory=Person)(objectClass=User)(!(employeeNumber=*)))";
                mySearcher.PageSize = 10;
    
                var results = SafeFindAll(mySearcher);
    
                mySearcher.Dispose();
                return results;
            }
    
            public static string FriendlyDomainToLdapDomain(string friendlyDomainName)
            {
                string ldapPath = null;
                try
                {
                    DirectoryContext objContext = new DirectoryContext(
                        DirectoryContextType.Domain, friendlyDomainName);
                    Domain objDomain = Domain.GetDomain(objContext);
                    ldapPath = objDomain.Name;
                }
                catch (DirectoryServicesCOMException e)
                {
                    ldapPath = e.Message.ToString();
                }
                return ldapPath;
            }
    
            private static IEnumerable<SearchResult> SafeFindAll(DirectorySearcher searcher)
            {
                using (var results = searcher.FindAll())
                {
                    foreach (var result in results)
                    {
                        yield return (SearchResult)result;
                    }
                } // SearchResultCollection will be disposed here
            }
        }
    }