views:

971

answers:

2

I am attempting to query ActiveDirectory via LDAP, but the query may contain spaces or other characters that may cause problems (hyphens?)

(&(objectCategory=person)(objectClass=user)(|(&(sn=Bloggs*)(givenName=Jo*))(displayName=Jo Bloggs))

It is an OR search e.g. in SQL it would be WHERE (sn LIKE 'Bloggs%' AND givenName LIKE 'Jo%') OR displayName = 'Jo Bloggs'

However, when I try the LDAP query, I get an error: System.ArgumentException: The (&(objectCategory=person)(objectClass=user)(|(&(sn=Bloggs*)(givenName=Jo*))(displayName=Jo Bloggs)) search filter is invalid

Code for performing search:

string userName = "Jo Bloggs";
DirectoryEntry adroot = new DirectoryEntry("LDAP://" + Environment.UserDomainName, "user", "password", AuthenticationTypes.Secure);
DirectorySearcher search = new DirectorySearcher(adroot);
search.Filter = string.Format("(&(objectCategory=person)(objectClass=user)(|(&(sn={0}*)(givenName={1}*))(displayName={2}))", userName.Split(' ')[1], userName.Split(' ')[0], userName);

This is just a basic search, I would like to search other columns as well (Job Title, Telephone, Department etc), e.g. WHERE title LIKE '%foo%' OR telephonenumber LIKE '%foo% OR department LIKE '%foo%'

Also, could I cache the search, so ActiveDirectory doesn't get a lot of hits from people searching t for the same thing?

This also only finds one entry, I would like to search and display in a repeater all results that are found.

+1  A: 

You're missing a closing parenthesis. Try this working example:

string userName = "Jo Bloggs";
string baseQuery =
    "(&" +
        "(objectCategory=person)" +
        "(objectClass=user)" +
        "(|" +
            "(&" +
                "(sn={0}*)" +
                "(givenName={1}*)" +
            ")" +
            "(displayName={2})" +
        ")" +
    ")"; // <<< this is missing in your original query

userName = Regex.Replace(userName, @"[\(\)\*\\]", (match) =>
                {   // escape reserved chars
                    return "\\" + ((int)match.Value[0]).ToString("x");
                }, RegexOptions.Compiled);
string query = String.Format(query, userName.Split(' ')[1], 
                                    userName.Split(' ')[0], userName);
using (DirectoryEntry entry = new DirectoryEntry(
    "LDAP://" + Environment.UserDomainName, "user", "password",
    AuthenticationTypes.Secure))
{
    using (DirectorySearcher ds = 
       new DirectorySearcher(entry, query, null, SearchScope.Subtree))
    {
        SearchResultCollection res = ds.FindAll(); // all matches
        if (res != null)
            foreach (SearchResult r in res)
                Console.WriteLine(user.Properties["displayName"].Value);
    }
}

EDIT: About escape sequences, you should refer to this document: Creating a Query Filter. I edit this answer to reflect that information.

If any of the following special characters must appear in the query filter as literals, they must be replaced by the listed escape sequence.

  ASCII     Escape sequence 
character     substitute
    *           "\2a"
    (           "\28"
    )           "\29"
    \           "\5c"
   NUL          "\00"

In addition, arbitrary binary data may be represented using the escape sequence syntax by encoding each byte of binary data with the backslash followed by two hexadecimal digits. For example, the four-byte value 0x00000004 is encoded as "\00\00\00\04" in a filter string.

Rubens Farias
Missing bracket was the reason for the code not working.. writing it in your way (breaking up into lines), makes it easier to understand and debug
Sam
Sam
fixed that, please take a look
Rubens Farias
A: 

Why not use Linq to AD for searching - http://linqtoad.codeplex.com/

Unmesh Kondolikar