Learning Active Directory and LDAP Filters in PowerShell

Stuart Squibb

Stuart Squibb

Read more posts by this author.

One of the most common hangups when querying Active Directory with PowerShell is how to properly build filter syntax. The Filter and LDAP Filter parameters on all ActiveDirectory PowerShell module cmdlets is a black box to many.

In this blog post, we’re going to dive deep into understanding how to use Active Directory filters. I hope by the end of this post, you’ll no longer be attempted to use that Where-Object and filter right!

Prerequisites

For any of the code I’m about to show you to work, I’ll be assuming a few things:

There are two different filter languages you can use when searching for objects using many of the Active Directory cmdlets: PowerShell filters and LDAP filters.

PowerShell Filters

PowerShell filters use the standard PowerShell expression syntax. This is commonly referred to as Active Directory search filter syntax.

These filters are used with the the Filter parameter. The Filter parameter syntax

Operators

While building a filter for the Filter parameter, you’ll need to use at least one operator. The operators used here are the familiar operators you may be used to when using commands like Where-Object.

Inside of the Filter parameter, you can use the following operators.

OperatorExplanation
-eqEqual to
-leLess than or equal to
-geGreater than or equal to
-neNot equal to
-ltLess than
-gtGreater than
-approxApproximately equal to
-borBitwise OR
-bandBitwise AND
-recursivematchRecursive match
-likeLike
-notlikeNot like
-andBoolean AND
-orBoolean OR
-notBoolean NOT

Reference AD Object Properties

Inside of the filter, you will compare various AD object properties using operators. For example, the Get-AdUser cmdlet returns a Name property. If you’d like to find all users matching a specific name, you’d use:

PS51> Get-Aduser -Filter "Name -eq 'Adam Bertram'"

Property names can be the name or LDAP name of the property returned with the AD cmdlet.

Property values are normally wrapped in single or double quotes. The only wildcard accepted is the asterisk (*). You can see above that the filter is surrounded by double quotes yet Adam Bertram is surrounded with single quotes.

Certain characters must be ‘escaped’ when used in filters. These are:

CharacterEscaped AsNotes
`”Only required if the data is enclosed in double quotes.
\’Only required if the data is enclosed in single quotes.
NUL\00This is a standard LDAP escape sequence.
\\5cThis is a standard LDAP escape sequence.
*\2aAutomatically escaped. Only in -eq and -ne comparisons. You should use -like and -notlike operators for wildcard comparison.
(/28Automatically escaped.
)/29Automatically escaped.
//2fAutomatically escaped.

LDAP Filters

Active Directory implements LDAP, the Lightweight Directory Access Protocol. Using the LDAPFilter parameter with the cmdlets allows you to use LDAP filters, such as those created in Active Directory Users and Computers.

The syntax for LDAP search filters is defined in RFC number 4515 .

Each filter rule is surrounded by parentheses ( ). Filter rules can be grouped by surrounding the group in parentheses and including a comparator from the following:

OperatorFunction
&and
|or
!not

LDAP filters also have a special matching rule Object IDentifiers (OIDs):

OIDPurpose
1.2.840.113556.1.4.803Bitwise AND
1.2.840.113556.1.4.804Bitwise OR
1.2.840.113556.1.4.1941Chain matching (for distinguished name attributes)

There are four filter types:

OperatorExplanation
=Equal to
~=Approximately equal to
>=Greater than or equal to
<=Less than or equal to

There are four item types:

TypeExplanation
=Simple
=*Present
=something*Substring
Extensiblevaries depending on type

The LDAP search filter rules must be used with the LDAP names of attributes, and certain character values must be ‘escaped’ if used in an LDAP filter. These are:

CharacterEscaped As
*\2a
(\28
)\29
\\5c
NUL\00

Property values for comparison do not normally need to be wrapped in quotes.

LDAP Filter Examples

Building LDAP filters can be challenging. Here are some examples using active directory group filters you can use as a base to begin creating your own.

  • All groups with a name (cn) of ‘Professional Services Department’

    'cn -eq "Professional Services Department"' or `'(cn=Professional Services Department)'

  • All groups with a name of ‘Professional Services Department’ and a description of ‘Live’

    '(cn -eq "Professional Services Department") -and (description -eq "Live")' or '(&(cn=Professional Services Department)(description=Live))'

  • All groups with a name of either ‘Professional Services Department’ or ‘All Departments Share Access’

    '(cn -eq "Professional Services Department") -or (cn -eq "All Departments Share Access")' or '(|(cn=Professional Services Department)(cn=All Departments Share Access))'

  • All groups not having a description of ‘Live’. Includes those with no description field at all

    '(!(description=Live))'

  • All groups not having a description of ‘Live’. Excludes those with no description field at all

    'description -ne "Live"'

  • All groups with a description of ‘Live’ but not with a name of ‘Professional Services Department’

    '(description -eq "Live") -and (cn -ne "Professional Services Department")' or '(&(description=Live)(!(cn=Professional Services Department)))'

  • All groups whose description is ‘\\fileserver1\fileshare’

    'description -eq "\5c\5cfileserver1\5cfileshare"' or '(description=\5c\5cfileserver1\5cfileshare)'

Using RecursiveMatch or Chain Matching

Using a matching rule OID, or the RecursiveMatch parameter is a powerful way of solving a question often asked about querying AD: ‘How can I tell all of the groups a user is a member of, both directly and indirectly?’ You use the Active Directory Search Filter memberOf property to find out.

Using a simple LDAP matching rule can be far more efficient than a large script. Using our example domain domain.local, Kristin Diaz is a direct member of the Professional Services Department security group. Looking at her memberOf property in AD reflects this; only Professional Services Department is shown.

PS51> Get-ADUser -Identity Kristin.Diaz -Property memberOf

DistinguishedName : CN=Diaz Kristin,OU=Professional Services,OU=All User Accounts,DC=domain,DC=local
Enabled           : True
GivenName         : Kristin
MemberOf          : {CN=Professional Services Department,OU=All Groups,DC=domain,DC=local}
Name              : Diaz Kristin
ObjectClass       : user
ObjectGUID        : 04fe6336-c541-4e71-b7ed-6fee7db23482
SamAccountName    : Kristin.Diaz
SID               : S-1-5-21-447422785-3715515833-3878445295-1186
Surname           : Diaz
UserPrincipalName :

By using the matching rule OID, or RecursiveMatch parameter you will find that they are indirectly a member of All Departments Share Access. This is because the Professional Services Department group is a member of All Departments Share Access.

PS51> Get-ADGroup -LDAPFilter '(member:1.2.840.113556.1.4.1941:=CN=Diaz Kristin,OU=Professional Services,OU=All User Accounts,DC=domain,DC=local)'
PS51> Get-ADGroup -Filter 'member -RecursiveMatch "CN=Diaz Kristin,OU=Professional Services,OU=All User Accounts,DC=domain,DC=local"'

Both return the following:

DistinguishedName : CN=All Departments Share Access,OU=All Groups,DC=domain,DC=local
GroupCategory     : Security
GroupScope        : Universal
Name              : All Departments Share Access
ObjectClass       : group
ObjectGUID        : 8ac0e0b7-9225-40a4-b168-a0330960e182
SamAccountName    : All Departments Share Access
SID               : S-1-5-21-447422785-3715515833-3878445295-1254

DistinguishedName : CN=Professional Services Department,OU=All Groups,DC=domain,DC=local
GroupCategory     : Security
GroupScope        : Universal
Name              : Professional Services Department
ObjectClass       : group
ObjectGUID        : a8432583-7cac-4e8e-8d94-51e1c5bb1989
SamAccountName    : Professional Services Department
SID               : S-1-5-21-447422785-3715515833-3878445295-1255

The SearchBase and SearchScope Parameters

In large environments, AD can contain many thousands of objects. A way of improving performance and reducing the number of objects returned for any query is to scope the search.

The SearchBase parameter determines where in the AD hierarchy any search begins. When using the cmdlets this is a string representation of a distinguished name (and by default is the ‘top’ of the domain). There are also three levels of SearchScope:

  1. Base – The object that has been specified as the SearchBase.
  2. OneLevel – searches for objects immediately contained by the SearchBase but not in any sub containers.
  3. SubTree – searches for objects contained by the SearchBase and in any subcontainers, recursively down through the AD hierarchy.
Carisbrookelabs.local OU Structure
Example OU Structure

In the above example, with the SearchBase set to OU=All User Accounts,DC=domain,DC=local, a SearchScope of Base would try to query the OU object itself, a SearchScope of OneLevel would search the All User Accounts OU only, and a SearchScope of SubTree would search both the All User Accounts and Professional Services OUs.

Summary

You should now have a good understanding of how to filter with the Active Directory PowerShell cmdlets. You can see there’s a lot to crafting that perfect filter syntax. It’s a lot harder building the appropriate filter than using the Where-Object cmdlet.

But spend the time learning the ‘right’ way to filter AD objects and reap the rewards of great performance and efficiency!

Further Reading

Subscribe to Adam the Automator

Get the latest posts delivered right to your inbox

Looks like you're offline!