Recently, I wanted to provide a client with a list of groups that related to some work he was doing. I wanted the group names as well as their location with AD. Although I often use the ds* commands or excellent ADfind tool for this type of task, I had been working in PowerShell on another project, so I decided to use the PowerShell ActiveDirectory module.
The Get-ADGroup Cmdlet pulled out the groups easily enough, but the there wasn’t a property representing the group object’s parent, nor is there an LDAP property that I could request (AFAIK). The object’s parent is contained within the DistinguishedName (DN) property, though.
For a group with the following DN:
CN=FOO-FileServices Administrators,OU=FOO,OU=Departments,DC=uvm,...
I just need to strip off the CN. I could split the DN on commas, remove the first element, and then reassemble what’s left to get the parent. I also needed to avoid splitting on an LDAP-escaped comma where a value actually contains a comma (e.g., CN=).
PS> $dn -split '(?<![\\]),'
I’ve used a regular expression construct called a zero-width negative look-behind assertion to match commas only where the aren’t preceeded by a slash.
I put together a small function to break up the DN on non-escaped commas, and then used -join operator to construct the DN of the parent.
function Get-ADParent ([string] $dn) { $parts = $dn -split '(?<![\\]),' $parts[1..$($parts.Count-1)] -join ',' }
FYI: In my function, I used $parts.Count-5 in the array slice to trim the ‘DC=’ domain components, which of course are the same for every object in my domain.
With that function, I then used a calculated property to include the parent in an output pipeline. For each object in the pipeline, I need to call Get-ADParent with the object’s DistinguishedName property. I like to store calculated properties in a variable:
PS> $parent = @{Name='Parent'; Expression={ Get-ADParent $_ } }
This works because the ToString() method for AD objects returns the DN. I could also have been specific in the Expression like so:
PS> $parent = @{Name='Parent'; Expression={ Get-ADParent $_.DistinguishedName } }
Now, I can create a PowerShell-ish pipeline to create the info that I want:
PS> Get-ADGroup -filter {cn -like 'Foo*'} | sort Name | ft Name,$parent -A
which returns results like this:
Name Parent ---- ------ FOO-FileServices Administrators OU=FOO,OU=Departments,... FOO-FileServices-BrowseTop OU=FOO,OU=Departments,... FOO-FileServices-HR OU=FOO,OU=Departments,... FOO-FileServices-Marketing OU=FOO,OU=Departments,... FOO-FileServices-THAC0 OU=FOO,OU=Departments,... FOO-GroupAdmins OU=OU Admins,OU=Groups,...
This function and calculated property should work with any AD objects that have a DistinguishedName property; users, computers, OUs, anything.
I hope you have found this helpful.
I used this technique again, and wanted to show the location relative to the domain root, and using abbreviated notation like a filesystem path. I came up with the following modification:
function Get-ADParent ( [string] $dn) {
# get rid of ‘OU=’
$parts = $dn.Replace(‘OU=’,”) -split ‘(?