Working with complex ldap filters in Powershell

Page content

When working with Active Directory and Powershell using ldap filters is a great way of searching the directory with great performance. The only problem is that ldap filters tend to be a bit hard to read and sometimes they appear to be a jitter of parentheses with some cryptic values in between.

When I write ldap filters I usually write them as multiline indented text, for example let say I wanted to search for all users (not contacts or computers) that is enabled and not set to expire. In a powershell script that would look like this:

$filter = '(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(accountExpires=0)(accountExpires=9223372036854775807))(userAccountControl:1.2.840.113556.1.4.803:=65536))'

Not really that easy to read is it? But if I use a here-string and split it up on multiple lines and add indention:

$filter = @'
(&
    (objectCategory=person)
    (objectClass=user)
    (!
        (userAccountControl:1.2.840.113556.1.4.803:=2)
    )
    (|
        (accountExpires=0)
        (accountExpires=9223372036854775807)
    )
    (userAccountControl:1.2.840.113556.1.4.803:=65536)
)
'@

This might still seem a bit complex but it is a lot easier to read. Sadly enough this format is not a valid ldap filter so when I’m done writing my filter I have to remove all line breaks and any space that follows. This is where powershell and regular expressions really comes in handy.

A regular expression is a string that defines a text-pattern that can be used to match parts of text. There is a great regex reference at MSDN. In this case we want to search a text for any linebreak followed by zero or more spaces and replace any match with nothing, or an empty string. Looking at the reference sheet we can see that n will match a new line character (linebreak) and s will match any white-space character (that is our spaces). There is also a quantifier (*) that will match the previous element zero or more times. That being said, “ns*” will match any linebreak followed by zero or more spaces. Adding a replace with this regex pattern to our here-string will make our $filter variable a valid ldap filter:

$filter = @'
(&
    (objectCategory=person)
    (objectClass=user)
    (!
        (userAccountControl:1.2.840.113556.1.4.803:=2)
    )
    (|
        (accountExpires=0)
        (accountExpires=9223372036854775807)
    )
    (userAccountControl:1.2.840.113556.1.4.803:=65536)
)
'@ –replace 'ns*','

 

This is a great little trick when writing my own ldap filter, but it wont help much when I’m reading an ldap filter that someone else wrote. For that I wrote a small powershell script that will take an ldap filter as a string and reformat it to a more readable state. Here is an example of how the ldap-filter in our last example is rewritten:

show-swldapfilter

I posted the script at Technet Galleries.