Wednesday, January 4, 2017

Finding Stale SIDs on GPOs

One of my clients has a tool from Microsoft that scans the AD infrastructure and generates a report of items that can fixed/improved. One of the items on a recent report was stale SIDs on GPOs that could affect GPO processing. However, the tools didn't give us the stales SIDs. Just said we had them.

First, let's talk about what a stale SID is...

All Windows security is based on a Security Identifier (SID) that is unique for each user or group. In the Access Control List (ACL) for an resource, it is the SID that is assigned permissions, not the name of a user or group. The Windows tools just translate that SID back to a user or group name for use to manage them easier.

A stale SID occurs when a user or group has been assigned permissions to access a resource and the user or group is later deleted. There is no link back from the user or group to where the permissions have been assigned. So, Windows cannot go back and remove the SID from the ACL. The SID that's left behind without a matching user or group object is a stale SID. When you are using graphical tools to view permissions and it shows a SID instead of a user or group name, that's typically a stale SID.

NOTE: Just because a graphical tool is showing a SID does not 100% guaranteed that the SID is stale. It could be a user or group from a trusted domain that the tool is having trouble resolving. If you have trusted forests or domains, you should verify that SID is in your domain.

If there were only a few GPOs, it would be fairly fast to use the Group Policy Management Console to find the stale SIDs. However, this client had about 500 GPOs and manually verifying the permissions would have been quite painful.

To find the stale SIDs on GPOs, I wrote up a small script that scans the GPOs and finds any security permissions that are unknown:

 Import-Module GroupPolicy  
 $gpo = Get-GPO -All  
 Foreach ($g in $gpo) {  
   $permissions = $g.getsecurityinfo()  
   Foreach ($p in $permissions) {  
     If ($p.Trustee.SidType -eq "unknown") {  
       Write-Host "Policy with unknown SID: $($g.DisplayName)"  
       Write-Host "Trustee SID: $($p.Trustee.Sid)"  
     } #end if  
   } #end foreach permissions  
 } #end foreach gpo  

Here is what the script does:
  • Loads the GroupPolicy module (required for Windows Server 2008 R2, Windows Server 2012 will do that automatically.
  • Pulls all GPOs into the variable $gpo.
  • Starts a foreach loop to process each gpo in $gpo.
  • Pulls the permissions for the current GPO into the $permissions variable by suing the getsecurityinfo() function for gpo objects.
  • Starts a foreach loop to process each permission in $permissions.
  • Tests whether the SidType for the trustee in the permissions is unknown. An unknown SidType identifies a SID that couldn't be resolved to a user or group.
  • The name of the gpo and the SID of the trustee are written to screen.
 This script writes output to screen, but you could easily modify it to dump the output to fine instead.


  1. I'm one of those MS guys who delivers the AD infrastructure check; I've been looking for an updated method to ID the stale SIDs for my customers. Thanks!