While developing a self-service password reset application, I encountered a frustrating issue. The application worked perfectly for regular users, but consistently failed when trying to reset passwords for administrative accounts. Even though my service account had Account Operator privileges, which should allow password resets, certain admin accounts would throw cryptic errors or simply refuse to cooperate.
After extensive troubleshooting and log analysis, I discovered the culprit: the admincount attribute and Active Directory's AdminSDHolder protection mechanism.
What is AdminCount?
The adminCount attribute is a special flag in Active Directory that gets set to 1 when a user account is (or was previously) a member of certain privileged groups, including:
- Domain Admins
- Enterprise Admins
- Schema Admins
- Account Operators
- Backup Operators
- And several other high-privilege groups
The AdminSDHolder Protection Mechanism
When adminCount=1, Active Directory applies special security protections to the account:
- Inheritance is disabled - The account stops inheriting permissions from parent containers
- Protected ACL applied - A standardized, restrictive Access Control List (ACL) is applied based on the AdminSDHolder template
- Ongoing protection - The AdminSDHolder process runs every 60 minutes to ensure these protections remain in place
This mechanism exists to prevent privilege escalation attacks and accidental permission changes on administrative accounts.
Why This Breaks Password Resets
The protected ACL applied by AdminSDHolder is more restrictive than normal user permissions. Even though Account Operators have the right to reset passwords on regular user accounts, the AdminSDHolder protection can block these operations on protected accounts.
The irony is that this security feature designed to protect admin accounts can actually prevent legitimate administrative operations like password resets.
Enhanced Logging for Diagnosis
The first step in solving this issue was implementing comprehensive logging to detect when accounts have adminCount=1 I added diagnostic logging to my password reset application:
// Check if adminCount is set to 1 (for logging purposes only)
WriteToLog(string.Format("Checking adminCount attribute for user: {0}", username));
if (userEntry.Properties["adminCount"].Value != null)
{
int adminCount = (int)userEntry.Properties["adminCount"].Value;
WriteToLog(string.Format("Account {0} has adminCount={1}", username, adminCount));
if (adminCount == 1)
{
hasAdminCount = true;
WriteToLog(string.Format("Account {0} has adminCount=1. This may cause password reset issues due to AdminSDHolder protection.", username));
}
}
else
{
WriteToLog(string.Format("Account {0} has no adminCount attribute (normal user account)", username));
}
This logging helped me confirm that accounts failing password resets consistently had adminCount=1 while successful resets were on accounts without this attribute.
AdminSDHolder Permissions
The proper solution isn't to try to modify the adminCount attribute or bypass the protection mechanism. Instead, the solution is to grant the service account appropriate permissions on the AdminSDHolder container itself.
Delegation does not work!!
When Microsoft documentation suggests using the Delegation Wizard for AdminSDHolder, understand that the wizard creates inheritance-based permissions that don't work for this specific use case. Use DSACLS to create direct permissions that actually function as intended.
"Use the Delegation of Control Wizard to add Reset Password and Change Password permissions to AdminSDHolder"
When you use the Delegation of Control Wizard on AdminSDHolder:
- Select: "Only the following objects in the folder" → "User objects"
- Choose: "Change Password" and "Reset Password"
- Result: Permissions are created with inheritance flags
Check ACL Permissions
First we need to check the permissions with the service account used for this action with this command:
# Check permissions on a test AdminCount=1 user
Get-Acl "AD:\CN=svc.password.reset,OU=Managed.Accounts,DC=bear,DC=local" |
Select-Object -ExpandProperty Access |
Where-Object {$_.IdentityReference -like "*ServiceAccount*"}
What permission does this grant to the ACL
ActiveDirectoryRights : ListChildren, ReadProperty, GenericWrite
InheritanceType : Descendents
PropagationFlags : InheritOnly
InheritanceFlags : ContainerInherit
ObjectFlags : InheritedObjectAceTypePresent
PropagationFlags set to Inherit only means these permissions only apply to future child objects created under AdminSDHolder, not to existing user objects elsewhere in the domain.
Fixing it with dsacls
The correct method here is to use dsacsl with the syntax below, obviously match the values for your environment and run those commands from a account with access to run them:
dsacls "CN=AdminSDHolder,CN=System,DC=bear,DC=local" /G "BEAR\svc.password.reset:RPWP"
dsacls "CN=AdminSDHolder,CN=System,DC=bear,DC=local" /G "BEAR\svc.password.reset:CA;Reset Password"
dsacls "CN=AdminSDHolder,CN=System,DC=bear,DC=local" /G "BEAR\svc.password.reset
:CA;Change Password"
Waiting for SDProp to apply
Important: After running the SDProp command, wait 15-30 minutes before testing. While the command triggers immediate propagation, it still takes time for:
- The SDProp process to start and complete
- Permissions to replicate across domain controllers
- Active Directory caches to refresh
Don't test immediately - you'll get false negatives if you try to reset passwords before the permissions have fully propagated throughout your domain.
What do the new ACL permission look like?
PropagationFlags set to "None" means these permissions apply directly and will be copied correctly to user objects by SDProp.
ActiveDirectoryRights : ReadProperty, WriteProperty
InheritanceType : None
PropagationFlags : None
InheritanceFlags : None
ObjectFlags : None
ActiveDirectoryRights : ExtendedRight
InheritanceType : None
ObjectType : 00299570-246d-11d0-a768-00aa006e0529 (Change Password)
PropagationFlags : None
InheritanceFlags : None
ActiveDirectoryRights : ExtendedRight
InheritanceType : None
ObjectType : ab721a53-1e2f-11d0-9819-00aa0040529b (Reset Password)
PropagationFlags : None
InheritanceFlags : None
Real world error messages
I have also kept in the code so when this is not set the user gets a valid error messages, however if you use the code above this problem will not occur, but keeping in is a good idea:
else if (errorMessage.Contains("access") || errorMessage.Contains("denied") || errorMessage.Contains("permission"))
{
WriteToLog(string.Format("Access denied error for user: {0}", username));
// If this account has adminCount=1, provide specific guidance
if (hasAdminCount)
{
WriteToLog(string.Format("AdminCount=1 detected - this account requires proper AdminSDHolder permissions"));
throw new Exception("This administrative account requires elevated privileges to reset. Please contact a Domain Administrator to configure AdminSDHolder permissions.");
}
else
{
throw new Exception("Insufficient permissions to reset password. Contact IT support.");
}
}
Conclusion
The adminCount attribute and AdminSDHolder protection mechanism serve critical security purposes in Active Directory. However, they can create unexpected obstacles for legitimate administrative operations like password resets.
The key insight is that the solution isn't to fight against these mechanisms, but to understand and work with them. By configuring appropriate permissions on the AdminSDHolder container, I was able to create a robust password reset system that handles all types of user accounts while maintaining Active Directory's intended security protections.