Audit Membership in Privileged Active Directory Groups. A Second Look.



AskPFEPlat is in the process of a transformation to the new Core Infrastructure and Security TechCommunity, and will be moving by the end of March 2019 to our new home at (hosted at Please bear with us while we are still under construction!

We will continue bringing you the same great content, from the same great contributors, on our new platform. Until then, you can access our new content on either as you do today, or at our new site Please feel free to update your bookmarks accordingly!

Why are we doing this? Simple really; we are looking to expand our team internally in order to provide you even more great content, as well as take on a more proactive role in the future with our readers (more to come on that later)! Since our team encompasses many more roles than Premier Field Engineers these days, we felt it was also time we reflected that initial expansion.

If you have never visited the TechCommunity site, it can be found at On the TechCommunity site, you will find numerous technical communities across many topics, which include discussion areas, along with blog content.

NOTE: In addition to the AskPFEPlat-to-Core Infrastructure and Security transformation, Premier Field Engineers from all technology areas will be working together to expand the TechCommunity site even further, joining together in the technology agnostic Premier Field Engineering TechCommunity (along with Core Infrastructure and Security), which can be found at!

As always, thank you for continuing to read the Core Infrastructure and Security (AskPFEPlat) blog, and we look forward to providing you more great content well into the future!


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 14th 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.