4

I have a list of folks and their DN from AD (I do not have direct access to that AD). Their DNs are in format:

$DNList = 'CN=Bob Dylan,OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com',
          'CN=Ray Charles,OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com',
          'CN=Martin Sheen,OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com'

I'd like to make $DNList return the following:

OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • 2
    There are already a lot of good answers here. I just want to point out that the "fields" in a DN can themselves contain a comma, and when they do it's escaped with a backslash so you can have `CN=Dylan\, Bob,OU=Users`. Just be careful that whichever method you choose handles this. – briantist May 01 '15 at 14:41

4 Answers4

8

I decided to turn my comment into an answer:

$DNList | ForEach-Object {
    $_ -replace '^.+?(?<!\\),',''
}

Regular expression visualization

Debuggex Demo

This will correctly handle escaped commas that are part of the first component.

We do a non-greedy match for one or more characters at the beginning of the string, then look for a comma that is not preceded by a backslash (so that the dot will match the backslash and comma combination and keep going).

briantist
  • 45,546
  • 6
  • 82
  • 127
  • 1
    Oh crap that's true isn't it. – Matt May 01 '15 at 15:14
  • My job uses `Last, First` display names in AD so I see this all the time :) – briantist May 01 '15 at 15:15
  • 1
    Tried to salvage my answer with this fact. – Matt May 01 '15 at 15:19
  • I did go with this answer and the resulting data looks good, at least on a random spot check. It was odd, however... running against a list of 1600ish items, the first dozen or so, it seemed like the whole process timed out and/jammed up. But waited about 20+ seconds and a quick flash with the correct results. Odd as it looked, it worked clean and clear. Thank you very, very much! – Mark Smith Marcus T May 01 '15 at 19:24
  • I think this may fail, when a value ends with an escaped backslash '\\' before the comma to the next OU will follow. E.g. OU=\\myOU\\,OU=mycompany\, inc. – Carsten Aug 22 '23 at 15:38
3

You can remove the first element with a replacement like this:

$DNList -replace '^.*?,(..=.*)$', '$1'

^.*?, is the shortest match from the beginning of the string to a comma.
(..=.*)$ matches the rest of the string (starting with two characters after the comma followed by a = character) and groups them, so that the match can be referenced in the replacement as $1.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • Nice - I think the split/join might be more readable if you're less familiar with powershell (or regular expressions) but is the regex faster? (wouldn't matter for this example but thinking of where there more are items to work on than the 3 here) – Graham Gold May 01 '15 at 12:23
  • 2
    @GrahamGold About factor 10 faster, according to a quick test I just ran on a larger sample (1300 elements). Also, simply splitting the DNs might cause problems when the first element contains a comma. – Ansgar Wiechers May 01 '15 at 12:37
  • I had a feeling it might be :-) Kudos for testing that out – Graham Gold May 01 '15 at 12:41
2

Similar to Grahams answer but removed the hardcoded array values so it will just remove the CN portion without worrying how long the DN is.

$DNList | ForEach-Object{($_ -split "," | Select-Object -Skip 1) -join ","}

Ansgar most likely has a good reason but you can just use regex to remove every before the first comma

$DNList -replace "^.*?,"

Update based on briantist

To maintain a different answer but one that works this regex can still have issues but I doubt these characters will appear in a username

$DNList -replace "^.*?,(?=OU=)"

Regex uses a look ahead to be sure the , is followed by OU=

Similarly you could do this

($DNList | ForEach-Object{($_ -split "(,OU=)" | Select-Object -Skip 1) -join ""}) -replace "^,"
Matt
  • 45,022
  • 8
  • 78
  • 119
  • With powershell there's more than one way to achieve the same objective - the answers on this question are proof positive :-) Why I love (and sometimes hate) powershell! – Graham Gold May 01 '15 at 12:44
  • 1
    @GrahamGold very true. It how I learn other approaches. Seeing what other people do. – Matt May 01 '15 at 12:46
1

You have 7 items per user, comma separated and you want rid of the first one.

So, split each item in the array using commas as the delimiter, return matches 1-6 (0 being the first item that you want to skip), then join with commas again e.g.

$DNList = $DNList|foreach{($_ -split ',')[1..6] -join ','}

If you then enter $DNList it returns

OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com
Graham Gold
  • 2,435
  • 2
  • 25
  • 34
  • When I try that, I get a result that's not what the OP is looking for :- OU=Users,CN=Bob Dylan,DC=com OU=Contractors,CN=Ray Charles,DC=com OU=Users,CN=Martin Sheen,DC=com – Graham Gold May 01 '15 at 12:42
  • You're right. What I head in mind was meant for a different scenario. Please disregard this suggestion. @Matt's suggestion is a better way to handle variable lengths. – Ansgar Wiechers May 01 '15 at 13:00