LDAP query prettifier

For some reason I have spent a lot of time looking at LDAP queries in the last few weeks. The simple queries are easy to "decode" but for the more complex ones you really need to format them properly to follow the flow. I wrote a little PowerShell script to do that, and I don't mind admitting that it was a little harder than I expected. Here is the code; save it as Prettify-LDAP.ps1 and it's ready for use.

[powershell]
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$ldapquery
)

$tabLevel = 0
$formatted = [string]::Empty

# remove whitespace, convert to array, process each character
($ldapquery -replace "[\s\n]", '').ToCharArray() | ForEach-Object {
if ($_ -eq '(')
{
$formatted += "`n$(" " * $tabLevel)("
$tabLevel++
} elseif ($_ -eq ')') {
$tabLevel--
$formatted += "$(" " * $tabLevel))`n"
} else {
$formatted += $_
}
}

# remove extra empty lines after ending bracket,
# then remove spaces before ending bracket IF there is non-whitespace before it
($formatted -replace '\)\n\n', ")`n") -replace "(\S)[ ]+\)", '$1)' -split "`n"
[/powershell]

It takes the LDAP query as a mandatory string argument. Next, whitespace is stripped because the script needs to insert its own.  To work with individual characters, I find it handy to convert the input string to an array of characters, and push those into the pipeline. For the output format each opening bracket starts on a new line, with its closing bracket lining up. To keep track of the indentation level the counter $tabLevel is used. As a final step, superfluous whitespace is stripped again. The regular expressions do look a bit like line noise, but I find them really handy for this sort of text manipulation.

On to an example. This one is unsurprisingly related to Exchange Server:

[code]
.\Prettify-LDAP -ldapquery "(&(&(&(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*))) )))(objectCategory=user)(department=IT)(physicalDeliveryOfficeName=Amsterdam)))"

The output:

 (&
  (&
    (&
      (&
        (mailnickname=*)
        (|
          (&
            (objectCategory=person)
            (objectClass=user)
            (|
              (homeMDB=*)
              (msExchHomeServerName=*)
            )
          )
        )
      )
    )
    (objectCategory=user)
    (department=IT)
    (physicalDeliveryOfficeName=Amsterdam)
  )
)

Much better, isn't it? Almost comprehensible, even.