Script to format an LDAP filter for readability
I have automated DLs that use LDAP filters for membership criteria. These filters are stored as binary data in the extensionData attribute of the group object, so they are not easily accessible by users who want to know what filter is being applied to a DL they own.
It was easy enough to extract the LDAP filter from the attribute, convert it to a string value, and display it. But users don’t generally know how to read LDAP filters, let alone represented as a long line of text. So I started looking for utilities or scripts that would take an LDAP filter, parse it, and display it with nesting. Uh, yeah, there aren’t any. I was determined, and so countless hours later I have a function that do such a thing.
The difficult part was keeping track of the level of nesting/indentation at any point. Since a filter can be written in almost any order as long as the resulting equation equals what you want, I couldn’t use any kind of static detection. Just because an open parentheses is following by another one doesn’t mean that you are, say, three levels nested. So the important part of the script keeps track of the indentation level as the cursor position moves through the filter.
I replace ampersands in the filter with crosshatches while working with it because I was having weird results otherwise, most likely because the ampersand is an operator in both LDAP and VBScript. And because the output is to an IE window and the indentation uses non-breaking spaces instead of the traditional tab (which doesn’t exist in HTML), I substitute the HTML string for a non-breaking space with a unique string of letters so the ampersand in that doesn’t get in the way.
Because this is part of a bigger script, I pulled out just the portion that formats the LDAP filter and displays it in an IE window. You just need to provide the "raw" filter, whether directly in the script or some other method. Copy and paste the code below or download it here.
Option Explicit
Dim strLDAPFilter, strFormattedFilter
Dim objIE, objDoc
strLDAPFilter = "YourLDAPFilter"
Set objIE = CreateObject("InternetExplorer.Application") objIE.AddressBar = False
objIE.Menubar = False
objIE.Toolbar = False
objIE.Resizable = True
objIE.Height = 450
objIE.Width = 700
objIE.Visible = True
objIE.Navigate("about:blank")
While objIE.Busy
WScript.Sleep 100
Wend
Set objDoc = objIE.Document
objDoc.Open
objDoc.Write("<TITLE>LDAP Filter Display</TITLE>")
objDoc.Write("<BODY BGCOLOR=#C0C0C0>")
'Parse the LDAP filter and format results for display
'Apply nesting for readability
strFormattedFilter = FormatLDAPDisplay(strLDAPFilter)
objDoc.Write(strFormattedFilter)
'Format single-line LDAP filter to include nesting
Function FormatLDAPDisplay(strLDAPFilter)
'Replace ampersands with crosshatches to keep them from interfering
strLDAPFilter = Replace(strLDAPFilter, Chr(38), Chr(35))
'Iterate through each character in filter and insert CRLF and nesting
Dim intPos, intIndentCount, intWhileIndent
Dim strIndentation, strInsert, strCharacter, strNewLDAPFilter
Dim bolDblClose
intPos = 1
intIndentCount = 0
Do While intPos < Len(strLDAPFilter)
strCharacter = Mid(strLDAPFilter, intPos, 1)
intWhileIndent = 1
strIndentation = ""
Select Case strCharacter
'LDAP operators to watch for to modify nesting level.
'NOT operator ignored because only used in one-off attribute value
Case Chr(35), Chr(124)
'Operator followed by open paren means nesting increase
If Mid(strLDAPFilter, intPos + 1, 1) = Chr(40) Then
intIndentCount = intIndentCount + 1
'Build nest based on number of indentations
Do While intWhileIndent <= intIndentCount
'Use unique string as placeholder for nesting with HTML spaces
strIndentation = strIndentation & "QZNBSPQZNBSPQZNBSPQZNBSP"
intWhileIndent = intWhileIndent + 1
Loop
'Insert new string for formatting
strNewLDAPFilter = Replace(strLDAPFilter, strCharacter, strCharacter & "<br>" & strIndentation, intPos, 1)
'Restore full filter including new string
strLDAPFilter = Left(strLDAPFilter, intPos - 1) & strNewLDAPFilter
'Move current position to next character after inserted string
intPos = intPos + Len(strIndentation) + 6
Else
intPos = intPos + 1
End If
Case Chr(40)
Do While intWhileIndent <= intIndentCount
strIndentation = "QZNBSPQZNBSPQZNBSPQZNBSP" & strIndentation
intWhileIndent = intWhileIndent + 1
Loop
If Not strIndentation = "" Then
'If open paren follows close paren, insert CRLF
If Mid(strLDAPFilter, intPos - 1, 1) = Chr(41) Then
strIndentation = strIndentation & "<br>"
End If
strNewLDAPFilter = Replace(strLDAPFilter, strCharacter, strIndentation & strCharacter, intPos, 1)
strLDAPFilter = Left(strLDAPFilter, intPos - 1) & strNewLDAPFilter
intPos = intPos + Len(strIndentation) +1
Else
intPos = intPos + 1
End If
Case Chr(41)
'Two consecutive close paren means nesting reduces one level
If Mid(strLDAPFilter, intPos + 1, 1) = Chr(41) Then
intIndentCount = intIndentCount - 1
bolDblClose = True
End If
Do While intWhileIndent <= intIndentCount
strIndentation = strIndentation & "QZNBSPQZNBSPQZNBSPQZNBSP"
intWhileIndent = intWhileIndent + 1
Loop
strNewLDAPFilter = Replace(strLDAPFilter, strCharacter, strCharacter & "<br>" & strIndentation, intPos, 1)
strLDAPFilter = Left(strLDAPFilter, intPos - 1) & strNewLDAPFilter
'Adjust position to account for two close paren
If bolDblClose = True Then
intPos = intPos + Len(strIndentation) + 5
bolDblClose = Empty
Else
intPos = intPos + Len(strIndentation) + 6
End If
Case Else
'No paren or operator means move to next character
intPos = intPos + 1
End Select
Loop
'Replace LDAP operators with words
strLDAPFilter = Replace(strLDAPFilter, Chr(35), "<i>AND</i>")
strLDAPFilter = Replace(strLDAPFilter, Chr(124), "<i>OR</i>")
strLDAPFilter = Replace(strLDAPFilter, Chr(33), "<i>NOT </i>")
'Replace spaceholders with HTML spaces
strLDAPFilter = Replace(strLDAPFilter, "QZNBSP", Chr(38) & "nbsp;")
FormatLDAPDisplay = strLDAPFilter
End Function
Set objIE = Nothing