Miko
Miko

Reputation: 21

Replace until a pattern is found in PowerShell

I have been trying to transform the following string:

CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM

to:

FR.CONTOSO.COM

As a first step, I tried to remove everything until ",DC" pattern.

I thought I could use the un-greedy ".+?" to match everything until the first ",DC" pattern:

$str = 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'
$str -replace '.+?,DC', ''

This returns:

=COM

Any idea why it's getting only the last one even with the un-greedy version? How could I do this?

Upvotes: 2

Views: 101

Answers (5)

Maximilian Burszley
Maximilian Burszley

Reputation: 19654

OK, so I took @EBGreen's advice and decided to make a function that does all the work:

#Requires -Version 4
Function ConvertFrom-DistinguishedName
{
    [CmdletBinding()]
    [OutputType('System.Management.Automation.PSCustomObject')]
    Param(
        [Parameter(Position = 0, Mandatory)]
        [Alias('DistinguishedName', 'Name')]
        [ValidatePattern('^CN=.+?,(OU=.+?,)+DC=.+$')]
        [string]
        $Path
    )
    $local:ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
    $WS = $Path -split ',' # working set

    $User = $WS[0] -replace 'CN='
    $Domain = $WS.Where({$PSItem.StartsWith('DC=')}).ToLower() -replace 'dc=' -join '.'
    $OU = $WS.Where({$PSItem.StartsWith('OU=')}) -replace 'OU='
    [array]::Reverse($OU)

    [pscustomobject]@{
        'User'   = $User
        'Domain' = $Domain
        'OU'     = $OU -join '\'
    }
}

PS C:\> ConvertFrom-DistinguishedName 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'

User     Domain         OU
----     ------         --
John Doe fr.contoso.com HQ\Department\Support\IT

The end result? This converts your distinguished AD name to a PSCustomObject you can easily work with.

Upvotes: 2

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200213

Since nobody bothered explaining the behavior yet:

The replacement operation replaces every occurrence of the pattern .+?,DC in the string, so it first removes CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC, then continues where that replacement left off and removes =FR,DC, and then =CONTOSO,DC, leaving you with just =COM.

To avoid this behavior you need to anchor the expression at the beginning of the string (^), as others have already suggested. The second replacement for substituting the remaining ,DC= with dots can be daisy-chained to the first one, so you need just one statement:

$str -replace '^.*?,dc=' -replace ',dc=', '.'

Upvotes: 1

bcjenkins
bcjenkins

Reputation: 121

You should use the ^ to start from the beginning.

$str = 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'
$str = $str -replace '^.+?,DC',''
$str = $str -replace 'DC=',''
$str -replace ',','.'

Upvotes: 1

jrider
jrider

Reputation: 1640

To get the domain out of the Distinguishedname, you will want to use -Split. Finally we can use -join to insert '.' between the DCs

This will store your domain string to $domain:

$dn = "CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM"
$domain = $dn -Split "," | ? {$_ -like "DC=*"}
$domain = $domain -join "." -replace ("DC=", "")

Write-Host "Current Domain: " $domain

Upvotes: 1

EBGreen
EBGreen

Reputation: 37720

Just split the string:

$parts = ('CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM' -split ',')
$newString = '{0}.{1}.{2}' -f $parts[-3].split('=')[1], $parts[-2].split('=')[1], $parts[-1].split('=')[1]

Upvotes: 2

Related Questions