Articles in the "Format LDAP Filter for Readability" series
- Script to format an LDAP filter for readability [This article]
- New version of LDAP formatting script
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