Microsoft Entra Suite Tech Accelerator
Aug 14 2024, 07:00 AM - 09:30 AM (PDT)
Microsoft Tech Community
Audit Membership in Privileged Active Directory Groups: A Second Look
Published Sep 19 2018 03:49 PM 1,717 Views

First published on TechNet on Apr 08, 2013


Some months ago, I shared a PowerShell script to enumerate the membership of privileged groups (including membership in nested groups) and report membership as well as password ages. Like most scripts, it works well in most environments, but has some limitations. One glaring limitation that I’ve found, for example, is that it searches for privileged groups by name. However, in some environments the groups may have been renamed. Or even more problematic are instances where built-in group names are different in non-English versions of the OS.


Since the built-in privileged groups all have well known SIDs, the logical solution was to re-write the script to search for groups based-on SIDs rather than names. So I started by identifying the well-known SIDs for the built-in privileged groups. There’s a KB for that. As it turns out, some of the well-known SIDs are constructed from the domain SID or the forest root domain SID. For example, the SID for Enterprise Admins is the root domain SID with “-591” appended to it.


Consequently, I had to re-work my script to identify the SID for every domain in the forest. Then, I had to construct all the SIDs for the privileged groups and enumerate their memberships.


To add another degree of difficulty, I wrote the entire script without using the AD PowerShell Cmdlets. As I’ve mentioned before, I still run into customers who can’t use the AD Powershell Cmdlets because they still have all 2003 domain controllers (without the AD web services installed). So instead of using one line of PowerShell to generate a list of domain SIDs:


(Get-ADForest).domains | forEach {Get-ADDomain $_} | Select-Object Name,DomainSid


I had to use about twenty lines of code to generate my list of SIDs. Most interesting was the use of .Net methods to convert SIDs to string values:


$RootDomainSid = New-Object System.Security.Principal.SecurityIdentifier($AdObject.objectSid[0], 0)


So I began talking to my peers about the beauty of the AD PowerShell Cmdlets and how they’ve saved us from writing lines and lines of code. I thought, “Let me re-write my script and show people how much more succinct the code could be.”


What started out as a noble effort, has turned into my White Whale. While sections of my script can be obliterated with single line Cmdlets, there are holes in the AD PowerShell Cmdlets that are frustratingly difficult to address. So here’s a challenge for you PowerShell junkies out there (and who have environments where the Cmdlets work), tear down my script and replace sections with AD Cmdlets.


I’m already working on my next blog, tentatively titled “Who’s the tool – PowerShell or Me?” where I’ll detail some of the different ways of using PowerShell with AD – including the AD Cmdlets. I’ll point out the differences and some of the relative strengths and weaknesses of each way.


Meanwhile, I’m counting the days until July 14 th 2015 when Windows Server 2003 is no longer supported, so I can leverage the AD Cmdlets in every environment I visit.


Since I’ve taken you off on a tangent, let’s get back to the original purpose of this post. You’ll find an updated version of the script on the TechNet Script Center. As before, it will enumerate membership in privileged groups and report password ages. While it’s not perfect, it better than the original in the following ways:


1. It targets groups based on well-known SIDs, so it will work in more environments.

2. It also reports on members that may not be users (computers or managed service accounts)


The syntax is straight-forward. Launch PowerShell. No special privileges are necessary, but you’ll have to run as a domain account, so we can read the directory. You’ll also need connectivity to DCs in the forest so we can enumerate group memberships. Simply run the script.




It’ll dump output to the screen and in a CSV file (that will dump in the same directory from which you launch the script).


Don’t forget to review the original blog for information on how (and why) to use the script.

Doug Symalla


A note on all of our AskPFEPlat scripts.  We’ve removed all script attachments to our blogs and posted them on the TechNet Script Center.  The blog will contain a hyperlink to the relevant location.  You can find all of our scripts on the Script Center by searching for the keyword AskPFEPlat.

Version history
Last update:
‎Feb 19 2020 03:27 PM
Updated by: