How LDAP filters are built
An LDAP filter describes which objects a search returns. Every condition is in parentheses and operators come first: (&(a)(b)) means “a and b”, (|(a)(b)) “a or b”, (!(a)) “not a”. That is quick to write and quick to get wrong, hence the builder.
What is different in Active Directory
- Finding users correctly:
(objectClass=user)alone also returns computers, because computer accounts inherit from “user”. Reliable is(&(objectCategory=person)(objectClass=user)). - Bits in userAccountControl: whether an account is disabled is stored in a single bit. It is queried with the matching rule
1.2.840.113556.1.4.803(bitwise AND), e.g.(userAccountControl:1.2.840.113556.1.4.803:=2). The tool shows what the bits mean. - Nested groups:
memberOf=…only finds direct members.1.2.840.113556.1.4.1941(LDAP_MATCHING_RULE_IN_CHAIN) also finds members of subgroups. - Time values:
lastLogonTimestamp,pwdLastSetandaccountExpirescount 100-nanosecond steps since 1601 (FILETIME). The converter below turns a date into that number.lastLogonTimestampis only replicated about every 14 days, which is fine for “inactive for 90 days”.
Special characters in values
The characters *, (, ), \ and NUL must be written as \2a, \28, \29, \5c and \00 in values (RFC 4515). The builder does this automatically. A group name such as “Sales (North)” becomes Sales \28North\29. In PowerShell the filter goes into single quotes so that $ and ` are not evaluated.
More tools for everyday admin work: tcpdump filter, subnet calculator and DNS lookup.
FAQ
Why does my filter with objectClass=user also return computers?
Because the “computer” class in AD derives from “user”. Add (objectCategory=person) and only users remain. It is also faster because objectCategory is indexed.
How do I find all members of a group including subgroups?
With (memberOf:1.2.840.113556.1.4.1941:=CN=Group,OU=…,DC=…). The value must be the group’s full distinguished name. Very deep nesting can make the query slow.
How do I query disabled or locked-out accounts?
Disabled: (userAccountControl:1.2.840.113556.1.4.803:=2). Locked out: (lockoutTime>=1). AD no longer maintains the lockout bit 16 in userAccountControl. lockoutTime stays set after the lockout duration ends until the user logs on.
Are my filters sent anywhere?
No. Builder, check and conversion run entirely in your browser. Only the address bar holds the current filter so you can share it as a link.
Does this work with OpenLDAP?
Yes, the syntax is standardised (RFC 4515). OpenLDAP does not know the AD-specific matching rules for bits and nested groups, though, and attributes are often named differently, e.g. uid instead of sAMAccountName.