AdminSDHolder, Protected Groups, SDProp and moving mailboxes in Exchange

When you move a mailbox in Exchange 2000 or newer, you sometimes encounter an error saying that you have insufficient permissions to move the mailbox. Although that may be the case, usually this error is caused by the user object associated with the mailbox you are trying to move not having inheritable permissions enabled in Active Directory. This is also known as that the DACL is protected, i.e. it is special and should not be changed. But why is it protected?

Usually it is protected because the user was once a member of one of the protected administrative groups in Active Directory. (Notice the word ‘once’, it will be important later!) These groups are (per Windows Server 2008 R2):

  • Enterprise Admins
  • Schema Admins
  • Domain Admins
  • Administrators
  • Account Operators
  • Server Operators
  • Print Operators
  • Backup Operators
  • Cert Publishers

Any user who is a direct or indirect member of any of these groups will get a protected DACL (inheritable permissions turned off) and the attribute adminCount set to 1. SDProp, or the Security Descriptor Propagator, thread within the LSASS.EXE process is responsible for checking and applying these settings once an hour. Any change you make to a protected object will be reset within the hour.

So back to moving mailboxes.

If the user is a member of any of the protected groups, the move mailbox process completes successfully since Exchange is aware of how to handle that scenario. But if the user has been removed from all protected groups the move process fails (remember I said “once a member of”).

The reason is that the user still has a protected DACL and the adminCount attribute set to 1. SDProp does not reverse its changes when you remove a user from a protected group. This is a scenario that Exchange does not know how to handle and so throws the insufficient permissions error. The easiest way to resolve the problem is to go into the Security tab of the user object, select Advanced and hit the Restore Defaults button. That will enable inheritance of permissions and remove any ACEs that SDProp (or any other process) has set explicitly. One important thing to know is that the Restore Defaults button does not reset the adminCount attribute back to 0, so you still have a user object in a non-consistent state (it is inheriting permissions, but still flagged as a special object). The best practice would be to manually clear adminCount with you favorite DS tool when you also enable permission inheritance.

Now that we know this it would be a good idea to find all the users that would fail when we tried to move them. To do this we would need to construct a query with the following criteria:

  • Not a member of any of the protected groups
  • Has a mailbox
  • Has a protected DACL

My choice would be PowerShell. Here is an example using the Quest Active Directory cmdlets:

  1. Put all the known protected groups in an array:
    $ADProtectedGroups = @(“Enterprise Admins”,”Schema Admins”,”Domain Admins”,”Administrators”,”Account Operators”,”Server Operators”,”Print Operators”,”Backup Operators”,”Cert Publishers”)
  2. Find all the users and put them in an array:
    $mismatchedUsers = Get-qaduser -sizelimit 0 -securitymask DACL –NotIndirectMemberOf $ADProtectedGroups -IncludedProperties homeMDB | Where-Object {(($_.DirectoryEntry.PSBase.ObjectSecurity.AreAccessRulesProtected) –
    and ($_.homeMDB -ne $null))}
  3. View the users if you like:
    $mismatchedUsers | ft
  4. Fix the users:
    $mismatchedUsers | ForEach { Set-QADObjectSecurity $_ –UnLockInheritance | Set-QADObject -ObjectAttributes @{adminCount=$null} }

Note: You may also want to include adminCount=1 in your search to see which objects have it set, but you could then get back users that have been fixed before by pressing Restore Defaults or enabling inheritable permissions.

To search for users with adminCount=1:

$admincountUsers = Get-qaduser -sizelimit 0 -NotIndirectMemberOf $ADProtectedGroups -IncludedProperties homeMDB,adminCount | Where-Object {(($_.adminCount -eq 1) -and ($_.homeMDB -ne $null))}

Or to just find everything with adminCount=1:

Get-ADObject –LDAPFilter “(adminCount=1)”

Join the Conversation

3 Comments

  1. I found this helpful for my issue, though I didn’t like that you used a proprietary cmdlet. Here is a script that I wrote up that does something very similar:
    #Accidental SD Prop Fixer
    #Wrote by Mujizac
    #Resets admincount to null. Sets the user object to include inheritable permissions.
    #Created because I accidently added all my users to printer operators group which jacked up thier user objects
    Import-Module ActiveDirectory
    #Be sure to edit the target ou to fit your domain and target.
    $targetou=”OU=Users,DC=domain,DC=local”
    get-aduser -ldapfilter “(objectcategory=person)(samaccountname=*)(admincount=1)” -SearchScope Subtree -SearchBase $targetou | foreach-object{
    Set-AdObject -identity $_ -clear admincount
    $dn = $_.DistinguishedName
    $user = [ADSI]”LDAP://$dn”
    $acl = $user.objectSecurity
    write-host “######################”
    write-host $dn
    write-host “Current Setting of Access Rules Protection:”
    write-host $acl.AreAccessRulesProtected
    $isProtected = $false
    $preserveinheritance = $true
    $acl.SetAccessRuleProtection($isProtected,$preserveinheritance)
    $inherited = $acl.AreAccessRulesProtected
    $user.commitchanges()
    write-host “Changed to:”
    write-host $acl.AreAccessRulesProtected
    }

  2. Works fine!! Thank you for use quest cmdlet! My domain is 2k3 😉

Leave a comment

Your email address will not be published. Required fields are marked *