New version of LDAP formatting script

Articles in the "Format LDAP Filter for Readability" series

  1. Script to format an LDAP filter for readability
  2. 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.)

#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 '&', 'AND'
	$infilter = $infilter -replace '#', 'OR'
	$infilter = $infilter -replace '!', 'NOT '

	#'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)

Leave a Reply

Your email address will not be published. Required fields are marked *

*