Troubleshooting: Custom Active Directory Permissions Aren't Effective

Symptoms

This can manifest in many different ways. Here are some of the most common:
  • Support personnel report they can't unlock or reset the password for a user even though the target user's account is in the same OU as many other accounts that are behaving normally.
  • Support personnel report they can't change the membership of a group even though the target group is in the same OU as many other groups that are behaving normally.
  • Support personnel report they can't modify an attribute for a user even though the target user's account is in the same OU as many other accounts that are behaving normally.
The primary identifying characteristic of the situation described here is the resetting of the security of whatever object they're trying to modify. IE, you may be able to grant support personnel rights to modify it, and it will work, but the next time they go back to do the same, the permissions are missing again.

To confirm the underlying issue is the one covered in this article, navigate to the the object in Active Directory Users and Computer and look at the Attribute Editor tab. Check the adminCount attribute, and if it's anything but blank, keep reading for the resolution. If not, it's probably something else, though some of the resolution steps here may help you temporarily fix the problem.

Resolution

Before you fix the object itself, you must first remove the conditions that are causing the behavior. Check the link in the Cause section for a full explanation, but for now, remove the user/group/computer from any "protected groups" listed here for your version of Active Directory. This includes nested groups, so don't just look at the Member Of tab. I'd recommend simply working backward from the protected groups, removing all accounts/groups that are unnecessary. Keep in mind that removing them from these groups will likely remove some access, so make sure you know the affected users have required permissions assigned using other ACLs/groups.

After removing all the appropriate objects from the protected groups, wait long enough for the changes to propagate across your entire domain.

Manual

  1. Open Active Directory Users and Computers. Under the main window menu, click View, and ensure there's a check next to Advanced Features.
  2. Navigate to the target object. Don't search.
  3. Right-click on the target object and select Properties.
  4. Go to the Attribute Editor tab.
  5. Highlight the adminCount attribute and click Edit.
  6. Click the Clear button.
  7. Click OK twice. You should be back at the OU where the target object lives.
  8. Right click on the target object and select Properties again.
  9. Got to the Security tab.
  10. Click the Advanced button.
  11. Enable security inheritance. Depending on your version of Windows/ADUC, this will be a checkbox near the bottom of the dialog box that is unchecked (check it) or a button near the bottom of the dialog box that says Enable inheritance (click it). Confirm any prompts here.
  12. Click OK twice. You should be back at the OU where the target object lives.

Script

Twelve steps per user is pretty daunting if you're dealing with a badly designed domain that has dozens or hundreds of users who are affected by this configuration. Thankfully, there is a script option.
## Performs the following tasks for all objects returned from the query:
## 1. Clears the adminCount attribute.
## 2. Enables security inheritance.

Import-Module ActiveDirectory

$users = Get-ADuser -SearchBase “DISTINGUISHEDNAME” -LDAPFilter “(adminCount=1)”

ForEach($user in $users)
  {
  ## Clearing the adminCount attributes
  Set-ADObject $user -clear adminCount

  ## Binding the users to DS
  $ou = [ADSI]("LDAP://" + $user)
  $sec = $ou.psbase.objectSecurity

  ## Inherit security if necessary
  if ($sec.get_AreAccessRulesProtected())
    {
    ## Allow inheritance
    $isProtected = $false
    
    ## Preserve inherited rules
    $preserveInheritance = $true

    ## Commit changes
    $sec.SetAccessRuleProtection($isProtected, $preserveInheritance)
    $ou.psbase.commitchanges()

    ## Write confirmation output
    Write-Host "$user is now inherting permissions";
    }
  else
    {
    ## Write confirmation output without permission reset
    Write-Host "$User Inheritable Permission already set"
    }
  }
  • Replace DISTINGUISHEDNAME with the distinguishedName attribute of the OU or container where you want the script to start. As written, it will process all user objects under that path.
  • If you want to adapt the script to different object types, change the Get-ADUser line that populates the $users array to something else (and I'd recommend changing the array/iterative variables to keep things neat and clear). It's possible other commands may have to be changed as well; I've only used this script for users and groups.
  • The text output should list all objects processed and whether they were adjusted or left alone. You can use the Out-File cmdlet to send it to a file for review if you anticipate processing a large number of users.

Cause

If you want to know the full details (and, if you're reading this, you probably should know most of the details at some point), here's a TechNet link.

In short, during the development of Active Directory, someone must have asked how they were planning to protect objects in the domain that have had highly elevated rights. The solution they came up with was to have a process that runs once an hour (by default) to reset the permissions for all members of those elevated groups to the default. This process writes a value to adminCount, then queries that data to do the security reset. This is actually pretty clever: it means that no matter where a user in Domain Admins is moved in the directory (even an OU that grants support personnel elevated rights over child objects), only other members of highly elevated groups will be able to modify it. Nifty.

However, problems arise when usage of those protected groups gets too high. I've seen domains where the majority of users were simply added to Enterprise Admins so everything just worked for everyone. This is technically effective, but when my team came in to do a reorganization and apply the least permissions principle, it was very common to run into issues like the ones described in the Symptoms section. Here's the fun part: the hourly scan doesn't recognize when a user is removed from a protected group. Even if you take the object out, its adminCount attribute will still be set, so it will continue to have its security reset by the hourly process. So even though my team went through all the trouble to get all those users out of Enterprise Admins, we still got calls when the support reps couldn't reset their passwords.

So, out of necessity, we found and cleaned up the script supplied in the Resolution section. Once we got everything organized in our standard directory structure, we could safely run the script against huge swath of users. Technically, if you have your security set up correctly, you could run this script on the entire domain without any real concern. All members of all protected groups will inherit security, but again, if you've designed things correctly, nobody should have elevated rights on their parent OUs anyway. So in an hour or less, the members of protected groups will again have their permissions reset and security inheritance disabled.

This is a very common scenario that not many people truly understand. Always keep it in the back of your mind when working on object permissions issues, especially in domains taken over from other teams.

Comments