Thursday, June 17, 2021

How to convert a CanonicalName (cn) to a DistinguishedName (dn) in Powershell

This was surprisingly not easily found on the internet, so when a coworker asked me how to convert a CanonicalName (cn) to a DistinguishedName (dn) in Powershell, I was surprised I had to roll my own code for them, below is the function.


Usage is easy, it's

$cn = "dc3.dc2.dc1.com/ChildOUName1/ChildOUName2/ChildOUName3/ChildOUName4/ChildOUName5/Lastname, FirstName";
Write-Host "CN is:" $cn;
$dn = cnToDn($cn);
Write-Host "DN is:" $dn;

and you should see:

DN is: CN=Lastname\, FirstName,OU=ChildOUName5,OU=ChildOUName4,OU=ChildOUName3,OU=ChildOUName2,OU=ChildOUName1,DC=dc3,DC=dc2,DC=dc1,DC=com

It should work for object accounts and not just user accounts, the object part was not as thoroughly tested, but if you've come this far you can probably figure out any tweaks needed and report back here your improvements.

 

function  cnToDn($cn)
{
    $cnReversedSections = $null;
    $cnSplit = $cn.Split("/");
    for ($i = ($cnSplit.Count - 1); $i -ge 0;, $i--)
    {
        if ($i -gt 0)
        {
            $cnReversedSections += $cnSplit[$i] + "/";
        }
        else
        {
            $cnReversedSections += $cnSplit[$i];
        }
    }

    $objectValue = $null;
    $dcValues = $null;
    $ouValues = $null;
    $cnReversedSectionsSplitTemp = $cnReversedSections.Split("/");
    $cnReversedSectionsSplit = New-Object System.Collections.ArrayList;
    foreach ($cnReversedSectionsTemp in $cnReversedSectionsSplitTemp) #account for empty array entries because of extra slashes
    {
        if ($cnReversedSectionsTemp -ne "")
        {
            $cnReversedSectionsSplit.Add($cnReversedSectionsTemp) | Out-Null;
        }
    }


    if ($cnReversedSectionsSplit[0].Contains(",")) # user object
    {
        for($i = 0; $i -lt $cnReversedSectionsSplit.Count; $i++)
        {
            if ($i -eq 0) # user object name
            {
                $objectValue = "CN=" + $cnReversedSectionsSplit[$i]; 
                if ($objectValue.Contains(","))
                {
                    $objectValue = $objectValue -replace [RegEx]::Escape(","), "\,";
                }
                $objectValue = $objectValue + ",";            
            }
            elseif ($i -eq ($cnReversedSectionsSplit.Count - 1)) # domain
            {
                $dcValuesArr = $cnReversedSectionsSplit[$i].Split(".");           
                for ($j = 0; $j -lt $dcValuesArr.Count; $j++)
                {
                    if ($j -eq ($dcValuesArr.Count - 1))
                    {
                        $dcValues += "DC=" + $dcValuesArr[$j];
                    }
                    else
                    {
                        $dcValues += "DC=" + $dcValuesArr[$j] + ",";
                    }
                }
            }
            else # the rest in the middle
            {
                $ouValues += "OU=" + $cnReversedSectionsSplit[$i] + ",";
            }
        }
    }
    else # non user object
    {
        for($i = 0; $i -lt $cnReversedSectionsSplit.Count; $i++)
        {
            if ($i -eq ($cnReversedSectionsSplit.Count - 1)) # domain
            {
                $dcValuesArr = $cnReversedSectionsSplit[$i].Split(".");           
                for ($j = 0; $j -lt $dcValuesArr.Count; $j++)
                {
                    if ($j -eq ($dcValuesArr.Count - 1))
                    {
                        $dcValues += "DC=" + $dcValuesArr[$j];
                    }
                    else
                    {
                        $dcValues += "DC=" + $dcValuesArr[$j] + ",";
                    }
                }
            }
            else
            {
                $ouValues += "OU=" + $cnReversedSectionsSplit[$i] + ",";
            }
        }
    }
    $dn = $objectValue + $ouValues + $dcValues;
    return $dn;
}