2

I am asking this question mainly to ask if there is a better way to do what I have working. I would also like to know if anyone sees any issues with getting this information this way.

I am trying to get the top level OU that a user is in, and any lower level OUs. The main problem is that we have multiple sites, some of which have multiple layers of OUs for user accounts (ou=doctors,ou=Users,ou=Site,dc=example,dc=com), and some sites that just have a single OU (ou=Users,ou=Site,dc=example,dc=com). I used the script below to get the DN path, split it, and rebuild it backwards with the last three pieces. Can anyone see any issues with doing it this way. Something about it just feels wrong....

$user = Get-ADUser CKnutson $user.DistinguishedName # Returns: CN=Cory Knutson,OU=IT,OU=Users,OU=Site,DC=example,DC=com $split = $user.DistinguishedName.Split(',') $path = "$($split[-3]),$($split[-2]),$($split[-1])" Write-Host $path # Returns: OU=Site,DC=example,DC=com 

Just to state, the end goal was for me to get the path to the "Disabled" OU that we have just inside of each of the "Site" OUs. So my scripting could move the object when disabling the account to the proper place, in that site's top level OU (OU=Disabled,OU=Site,DC=example,DC=com).

2
  • Don't think I'd necessarily call anything wrong, but is the final goal to have it in the DN format? If not you could also call the canonical name and split that. I think those two attributes are both going to require some splitting and/or joining but are probably the only way to achieve the stated goal with any kind of ease. Commented Oct 25, 2017 at 2:21
  • The other thought that occurs is simply pattern matching your domain name with regex or with a straight up string match and splitting off only the stuff after -- ahem before -- that to put in another cell in your CSV. Commented Oct 25, 2017 at 2:24

3 Answers 3

2

Can anyone see any issues with doing it this way.

Yes, I see two immediate problems that might arise from your current approach.


1. Escaped commas

Consider an OU with a comma in its name, like: OU=Users\, Admin,DC=corp,DC=example

Your use of string.Split() won't care about the escape sequence and you end up with:

 Admin,DC=corp,DC=example 

Use the -split regex operator with a lookbehind to make sure you ignore escaped commas:

$parts = $user.DistinguishedName -split '(?<!\\),' 

2. Portability

Your code assumes that the NC part of the DN (eg. DC=example,DC=com), will always be just 2 labels wide. This means your code will fail if you use it in scripts you might want to reuse in other domains/environments.

I would grab each part, from right-to-left until I find one without the DC RDN prefix:

$topParts = foreach($part in $parts[-1..-$parts.Length]){ $part if($part -notlike 'DC=*'){ break } } # Remember to reverse the RDNs again $path = $topParts[-1..-$topParts.Length] -join ',' 
2
  • But if I want the top level OU included, the if statement would be if($part -notlike 'DC=*'){$part;break}, correct? Then it would include the first non-DN piece, which would be the top level folder/OU. Commented Oct 25, 2017 at 21:33
  • 1
    Look at the line just before if($part -notlike ... - when we break we've already emitted $part :-) Commented Oct 26, 2017 at 5:17
1

In my opinion it is simpler to use Pathname COM object and simply ask for the parent of the DN. You can put this in a while loop to get the hierarchy of the object. Example using my ADName module:

$dn = Get-ADUser user | Select-Object -ExpandProperty DistinguishedName $parent = $dn | Get-ADName -Format Parent while ( $parent -like "OU=*" ) { $parent $parent = $parent | Get-ADName -Format Parent } 

Example output:

OU=Level 3,OU=Level 2,OU=Level 1,DC=fabrikam,DC=com OU=Level 2,OU=Level 1,DC=fabrikam,DC=com OU=Level 1,DC=fabrikam,DC=com 
0

So you're after the DN of the path to the account? You can do that with a regular expression that uses the (?) ungreedy qualifier. There is no split, so escaped commas are not an issue.

"CN=Cory Knutson,ou=doctors,ou=Users,ou=Site,dc=example,dc=com" -match ".+?,(OU=.+)" $matches[1] ou=doctors,ou=Users,ou=Site,dc=example,dc=com "CN=Knutson\, Cory,ou=doctors,ou=Users,ou=Site,dc=example,dc=com" -match ".+?,(OU=.+)" $matches[1] ou=doctors,ou=Users,ou=Site,dc=example,dc=com "CN=Cory Knutson,ou=Site,dc=example,dc=com" -match ".+?,(OU=.+)" $matches[1] ou=Site,dc=example,dc=com 

Edit
I was unclear from the phrase the top level OU that a user is in, and any lower level OUs. You can also do this:

$dn = "CN=Cory Knutson,ou=doctors,ou=Users,ou=Site,dc=example,dc=com" $last = ($dn.toUpper()).lastIndexOf("OU=") $dn.substring($last) ou=Site,dc=example,dc=com 
1
  • I wanted only the top level OU, so all three should return: ou=Site,dc=example,dc=com Commented Oct 28, 2017 at 2:35

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.