Articles in the "Format LDAP Filter for Readability" series
- Script to format an LDAP filter for readability
- New version of LDAP formatting script [This article]
Over two years ago, I posted a script (in VBScript) that formats an LDAP filter for readability and outputs it in an IE window. I seldom use VBScript anymore since Exchange is all about the PowerShell. I still work with LDAP filters all the time to control membership in automated DLs (Exchange’s query-based DLs are very limited), so I was working in PowerShell to do that and still hopping over to my old script to format it for myself or others.
I thought it was time to update that script to work in PowerShell. While some things port from VBScript to PowerShell quite easily, I got stuck in several places doing this one. Working with the InternetExplorer.Application COM object is one, but researching the changes allowed me to improve the formatting. The font is smaller and I have added pipes to show where the indenting occurs, which helps with the flow when the filter is long and you have to scroll.
A sticking point was working with the search and replace. You can’t use the parameters for the starting position and the number of replacements to make when using the replace operator in PowerShell. You can, however, do it with the RegularExpressions class (RegEx), but then I had to accommodate the special characters in the regex world. That was offset by the lack of a need to escape as many characters in PowerShell as in VBScript.
The main issue, though, was interpreting my old code. It is documented well, but I could not figure out why I was doing certain things to manipulate the filter as the indentations were being added and keeping track of the correct position in the characters. I spent a fair number of hours trying to figure out if certain lines were just superfluous or were actually needed for it to work. I was able to remove lines of code that were at least not needed in PowerShell, though I still don’t know why I used them in them VBScript version.
In the end, the results are the same as the old version except for the formatting changes (which are an improvement). I have thought about changing the formatted filter to XML so that each indentation can be collapsed when viewing in IE, but that is more work than needed at this time. The full code is below, but you can also just download the script via the link at the end. (I have also included the old VBScript version in the download.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
#Takes an LDAP filter from the clipboard and formats it for readability #v1.0 11/12/10 #http://www.flobee.net function GetClipBoard { Add-Type -AssemblyName System.Windows.Forms $tb = New-Object System.Windows.Forms.TextBox $tb.Multiline = $true $tb.Paste() $tb.Text } function FormatLDAPDisplay($infilter) { #Replace pipes with crosshatches to keep them from interfering in regex $infilter = $infilter.Replace('|','#') #Iterate through each character in filter and insert line breaks and nesting $iPos = 0 $iIndentCount = 0 while ($iPos + 1 -lt $infilter.Length) { $currCharacter = $infilter.Substring($iPos, 1) $iWhileIndent = 1 $sIndentation = '' switch -regex ($currCharacter) { #LDAP operators to watch for to modify nesting level. #NOT operator ignored because only used in one-off attribute value "[&#]" { #Operator followed by open paren means nesting increase if ($infilter.Substring($iPos + 1, 1) -eq '(') { $iIndentCount ++ #Build nest based on number of indentations while ($iWhileIndent -le $iIndentCount) { #Use unique string as placeholder for nesting with HTML spaces $sIndentation += 'QZNBSPQZNBSPQZNBSPQZNBSP' $iWhileIndent ++ } #Insert new string for formatting $regx = [regex]$currCharacter $infilter = $regx.Replace($infilter, "$currCharacter $sIndentation", 1, $iPos) #Move current position to next character after inserted string $iPos += $sIndentation.Length + 5 } else { $iPos ++ } } "[\(]" #Escape paren to be treated literally in regex { while ($iWhileIndent -le $iIndentCount) { $sIndentation += 'QZNBSPQZNBSPQZNBSPQZNBSP' $iWhileIndent ++ } if ($sIndentation -ne '') { if ($iPos -ne 0) { #If open paren follows close paren, insert line break if ($infilter.Substring($iPos - 1, 1) -eq ')') { $sIndentation += ' ' $regx = [regex]'\(' $sNewLDAPFilter = $regx.Replace($infilter, "$sIndentation$currCharacter", 1, $iPos) $infilter = $infilter.Substring(0, $iPos - 1) + $sNewLDAPFilter $iPos += $sIndentation.Length + 1 } else { $iPos ++ } } else { $iPos ++ } } else { $iPos ++ } } "[\)]" #Escape paren to be treated literally in regex { #Two consecutive close paren means nesting reduces one level if ($infilter.Substring($iPos + 1, 1) -eq ')') { $iIndentCount -- $bDblClose = $true } while ($iWhileIndent -le $iIndentCount) { $sIndentation += 'QZNBSPQZNBSPQZNBSPQZNBSP' $iWhileIndent ++ } $regx = [regex]'\)' $infilter = $regx.Replace($infilter, "$currCharacter $sIndentation", 1, $iPos) #Adjust position to account for two close paren if ($bDblClose) { $iPos += $sIndentation.Length + 5 $bDblClose = $null } else { $iPos += $sIndentation.Length + 6 } } default { #No paren or operator means move to next character $iPos ++ } } } #Replace LDAP operators with words $infilter = $infilter -replace '&', '<i>AND</i>' $infilter = $infilter -replace '#', '<i>OR</i>' $infilter = $infilter -replace '!', '<i>NOT </i>' #'Replace spaceholders with HTML spaces $infilter = $infilter -replace 'QZNBSP', ' ' $infilter } $string = GetClipboard $htmlbody = FormatLDAPDisplay $string #Launch IE window $ie = New-Object -ComObject "InternetExplorer.Application" $ie.AddressBar = $false $ie.Menubar = $false $ie.Toolbar = $false $ie.Resizable = $true $ie.Height = 450 $ie.Width = 500 $ie.Visible = $true $ie.Navigate('about:blank') do { Sleep -Milliseconds 100 } while ($ie.Busy) $doc = $ie.Document $doc.title = "Formatted LDAP Filter" $doc.body.style.fontSize = '10pt' $doc.body.innerHTML = $htmlbody |
Format-LDAPFilter.zip (3.0 KiB)