Today’s topic is going to be getting rid of unused groups in the forest. Over the last few years I’m seeing a growing trend were administrators or identity groups are creating groups that are never used. Once these groups are created it seems impossible to get these groups removed due to the unknown. These unknowns are several things like; it might be used just empty, or we have no idea what is using it. As part of my continue discussions I started focusing on low hanging fruit (groups). To solve this I started out focusing on if memberof and members are empty and the when change was older than x it must be unused. This seems logical but turns out it was not, I then expanded my search to include if msDS-ReplValueMetaData is null and if the whencreated is older than x. There are several topics around leveraging msDS-ReplValueMetaData and what is it used for, in short this is an attribute that contains all of the replication metadata around linked values (Use PowerShell and Repadmin to Check for Updates to High Privileged Groups). If the attribute is empty more than likely the group has never had any direct members added to it. I have found that at least a fourth of all groups in most Active Directory environments fall into this category.
Here is the script I threw together.
$_default_log = $env:userprofile + 'Documentsnever_used_ad_group_age.csv'
If ($(Try { Test-Path $_default_log} Catch { $false })){Remove-Item $_default_log -force}
(get-adforest).domains | foreach {$_domain = $_
get-adgroup -LDAPFilter "(&(!(member=*))(!(memberof=*)))" -Properties "msDS-ReplValueMetaData",whencreated,groupscope,groupcategory -server $_domain | `
where {(!($_."msDS-ReplValueMetaData"))} | select `
@{name='Domain';expression={$_domain}},name,samaccountname,groupcategory,groupscope,whencreated,`
@{name='AgeinDays';expression={(new-TimeSpan($($_.whencreated)) $(Get-Date)).days}},isCriticalSystemObject,distinguishedname,`
@{name='ParentOU';expression={$($_.distinguishedname -split '(?<![\]),')[1..$($($_.distinguishedname -split '(?<![\]),').Count-1)] -join ','}} | `
export-csv $_default_log -Append -NoTypeInformation
}
write-host "Report Can be found here $_default_log"
This will run through all the domains in a forest.
Once the script is complete open it in excel and pivot on the data of your choice. Here is some examples on how I would
Select the data
select Insert Pivot Table, make the pivot table fields look like the following:
Should have a nice little view like this
*Consider filtering out OU’s or Containers like Builtin and Users.
Make the Pivot Table Fields look like this
A nice view of each ou and the age and count of groups should be displayed.
Now that you have this data hopefully it will be enough to clean out some of the bloat in Active Directory. In a next blog post we will tackle getting the last change from the msDS-ReplValueMetaData to figure out the last time an object was added or removed. Hope you find this useful and have a good day.
-Chad