Removing Unresolved SIDs in Exchange 2010

In this post, I'm going to describe how to remove unresolved SIDs from public folders in Exchange 2010. But first, let’s talk about what they are and why we care about them.

What are unresolved SIDs?

When you view the permissions on a file in Windows or an object in Active Directory, you get a nice friendly list of names, each one with its associated access rights displayed. However, the security descriptor does not actually contain the names of the users – it only contains their SIDs. When an application such as Explorer or ADUC displays the permissions, it attempts to resolve each SID to a name, so when you look at it you can make some sense of what you’re seeing.

An unresolved SID is a SID that no longer resolves, usually because the user has been deleted. If you look at an object in ADUC, it looks like this:

sec1

In Exchange, folders have security descriptors that are very similar to the ones in Windows, except that things are ordered differently. But you still have SIDs and rights, and when a SID doesn’t resolve anymore, you’ll see that in Outlook:

sec2

Why do we care about them?

Unresolved SIDs don’t cause a problem; they just look ugly. Some customers want to remove them for that reason alone, and some customers have other reasons. A lot of customers used PFDAVAdmin for this, but there was a specific reason PFDAVAdmin removed these.

Back in Exchange 2000 and Exchange 2003, it was possible to expose the Information Store database as a drive in Windows. This was the infamous M: drive. It became infamous because applications that were not Exchange-aware would access folders through the M: drive and mess up the permissions. Above, I briefly mentioned that things are ordered differently in an Exchange ACL than a Windows ACL. Applications that looked at the folders in M: and thought they were plain old Windows folders would reorder the stuff in the security descriptor to fit the Windows format. This meant it no longer matched the Exchange canonical format, and the permissions wouldn’t work as expected.

After an application had run through the M: drive and made all the ACLs non-canonical, it was a huge pain to go through and manually correct them. This was one of the main reasons I wrote the PFDAVAdmin tool. PFDAVAdmin provided an easy way to put all the ACLs back in canonical order.

One thing about Exchange canonical order is that the SIDs need to go in a particular order based on the object type. Users need to be at the top of the ACL, followed by groups. If you’re trying to reorder the ACL to make it canonical again, and you run into an unresolved SID, this presents a problem. Since you can’t resolve the SID, you don’t know what type of object it is, so where should it go?

There are a few ways you could approach this problem. For instance, you could just pretend it’s a user SID. If the object has been deleted, then the SID will never again resolve, so it won’t matter. If the SID is only unresolvable because of a temporary issue with a DC or something, then this could result in the ACL becoming non-canonical once the SID resolves again.

However, the approach I took with PFDAVAdmin was to have it remove the unresolved SIDs. I couldn’t be sure what they were and why they were unresolvable, and the whole point was to force the ACL into a canonical state, so this seemed like a sensible approach.

Why doesn’t ExFolders remove them?

When I rewrote the guts of PFDAVAdmin for Exchange 2010, I renamed it ExFolders. While the GUI looks almost identical, the code underneath is not the same and required a lot of rewriting. When it came time to look at the “Fix Folder DACL” code and decide whether to move it into ExFolders, I just didn’t see any need for it. The widespread non-canonical ACL issues from the Exchange 2000/2003 days were gone, so I left this functionality out of ExFolders entirely. Unresolved SID removal was a side-effect of fixing the DACL, so it likewise fell by the wayside.

How can I remove them now?

OK, so you want to remove them from your public folders in Exchange 2010, but there’s no tool to do that anymore. Fortunately, it’s easy to remove them with a simple script. I’ve included one below. This script will be far slower than PFDAVAdmin was, but it will get the job done.

If you run it with the following syntax, it will only report the unresolved SIDs:

.\Check-UnresolvedSIDs.ps1 -Server MyPFServer

If you want it to actually remove them, you must add the –Remove parameter:

.\Check-UnresolvedSIDs.ps1 -Server MyPFServer -Remove $true

The output will look something like this:

\Folder1: Checking folder
\Folder2: Checking folder
\Folder2 has unresolved SIDs:
     NT User:S-1-5-21-1016452943-3003584382-490080582-2161
\Folder3: Checking folder
\MyNewFolder: Checking folder
\SomeOtherFolder: Checking folder
\SomeOtherFolder has unresolved SIDs:
     NT User:S-1-5-21-1016452943-3003584382-490080582-1136
     NT User:S-1-5-21-1016452943-3003584382-490080582-1135

If you add the –Remove parameter, it will also tell you that it’s removing them.

Here’s the script. Enjoy!

# Check-UnresolvedSIDs.ps1
#
# This script will remove all unresolved SIDs from public folder permissions.
# This will take quite some time to run against a large hierarchy.

param([string]$Server, [bool]$Remove)

if ([System.String]::IsNullOrEmpty($Server))
{
"You must specify a server."
return
}

function CheckUnresolvedForFolder($folder)
{
($folder.Identity.ToString() + ": Checking folder")
$unresolved = Get-PublicFolderClientPermission -Identity $folder -Server $Server| WHERE { $_.User -like "NT User:S-*" }
if ($unresolved -ne $null)
{
($folder.Identity.ToString() + " has unresolved SIDs:")
foreach ($item in $unresolved)
{
(" " + $item.User.ToString())
}

        if ($Remove)
{
(" Removing the unresolved SIDs...")
foreach ($item in $unresolved)
{
$item | Remove-PublicFolderClientPermission -Identity $folder -Server $Server -Confirm:$false
}
(" Unresolved SIDs were removed.")
}
}
}

function DoFolderRecursive($folder)
{
CheckUnresolvedForFolder($folder)
$subfolders = Get-PublicFolder -Identity $folder -GetChildren
if ($subfolders -ne $null)
{
foreach ($subfolder in $subfolders)
{
DoFolderRecursive($subfolder)
}
}
}

$ipmSubtree = Get-PublicFolder "\" -Server $Server
DoFolderRecursive($ipmSubtree)
$nonIpmSubtree = Get-PublicFolder "\NON_IPM_SUBTREE" -Server $Server
DoFolderRecursive($nonIpmSubtree)

"Done!"