Active Directory (AD) delegation is critical part of many organizations' IT infrastructure. By delegating administration, you can grant users or groups only the permissions they need without adding users to privileged groups (e.g., Domain Admins, Account Operators). The simplest way to accomplish delegation is by using the Delegation of Control Wizard in the Microsoft Management Console (MMC) Active Directory Users and Computers snap-in.
Related: Managing Active Directory with PowerShell
Although the Delegation of Control Wizard provides an easy way to delegate permissions, there's no corresponding wizard for removing delegated permissions. Somebody at Microsoft must have noticed this shortcoming and created a command-line program named Dsrevoke.exe that can remove the permission entries added by the Delegation of Control Wizard.
However, the Dsrevoke.exe program has two important technical limitations, which are documented in the Microsoft article "When you use the Dsrevoke command-line tool to report permissions for all the organizational units in a Windows Server 2003-based domain, the tool may not return all the access control entries." These limitations are:
- Dsrevoke.exe can find only up to 1,000 OUs in a single search. The suggested workaround for this limitation is to start the program's search in a more deeply nested organizational unit (OU) to reduce the number of results.
- Dsrevoke.exe fails if any OUs contain a forward slash (/) character in their names. There's no workaround for this limitation other than to rename the offending OUs.
When working with Dsrevoke.exe recently, I was able to work around the first problem, but then I ran into the second problem. For organizational reasons, renaming the OUs to remove the slash character wasn't an option. Besides, the slash is a valid character in an OU name, and Dsrevoke.exe should work no matter whether an OU contains a slash in its name or not. Also, working around the 1,000 OU limit in my environment was time-consuming.
Because of these problems, I decided to see if there were any built-in alternatives to Dsrevoke.exe. Starting in recent versions of Windows, the Dsacls.exe program provides a way of removing the permissions added by the Delegation of Control Wizard. Although it doesn't fail if an OU contains a slash in its name, Dsacls.exe can't search subcontainers for permissions like Dsrevoke.exe does.
I first decided to just write a simple script to search for OUs and call Dsacls.exe to remove the delegated permissions from each OU. However, as I thought about how I wanted to design such a script, it occurred to me that I would also like to see a list of which OUs had permissions delegated to a particular user or group. Dsrevoke.exe and Dsacls.exe can produce a list of permissions, but the output is very long and technical. I wanted something simpler.
Due to the limitations in Dsrevoke.exe and Dsacls.exe, and my desire to get shorter output, I decided to write a Windows PowerShell script to get the functionality I wanted. The result is Remove-DSACE.ps1. Before I discuss this script, though, I need to provide some background information about what happens when you use the Delegation of Control Wizard as well as cover some basic Windows security concepts.
Adding Delegated Permissions with the Wizard
As I previously mentioned, the Delegation of Control Wizard provides an easy way to delegate permissions. For example, suppose you want members of the Password Reset group to be able to reset passwords for users in the All Users OU in your AD domain. To do this, you need to perform these steps:
- Open the Active Directory Users and Computers console.
- Right-click the All Users OU and choose Delegate Control, as shown in Figure 1. Click the Next button to advance past the wizard's welcome page.
- On the wizard's Users or Groups page, click the Add button.
- In the Select Users, Computers, or Groups dialog box, enter the group's name (Password Reset), click the Check Names button to make sure the group's name is correct, and click OK, as shown in Figure 2.
- After making sure the group's name is listed on the Users or Groups page, click Next, as shown in Figure 3.
- On the Tasks to Delegate page, select Reset user passwords and force password change at next logon and click Next, as shown in Figure 4.
- Verify the information in the final page of the wizard and click Finish.
When you click the Finish button, the Delegation of Control Wizard adds the requested permissions to the All Users OU. You can view the effects of the delegation by right-clicking the All Users OU, choosing Properties, and selecting the Security tab. (If the Security tab isn't visible, enable the Advanced Features option on the View menu of the Active Directory Users and Computers console.) For a detailed view, you can click the Advanced button. Figure 5 shows the Advanced Security Settings dialog box that appears.
ACLs, ACEs, and Trustees—Oh My!
To understand the information being provided in the Advanced Security Settings dialog box, you need to know about the following Windows security concepts: access control list (ACL), access control entry (ACE), trustee, and inheritance. You also need to understand these concepts to use Remove-DSACE.ps1.
ACL. There are two kinds of ACLs: discretionary ACLs (DACLs) and system ACLs (SACLs). A DACL identifies the accounts that are allowed or denied access to an object. A SACL describes how an administrator wants to log attempts to access an object (i.e., auditing).
ACE. An ACL is composed of ACEs. Each ACE identifies a trustee and specifies the trustee's access (allow, deny, or audit) for the object. The Delegation of Control Wizard adds ACEs to an AD container's DACL. Figure 5 shows the DACL for the All Users OU. In this figure, the term permission entry is synonymous with ACE.
Trustee. A trustee is the entity (a user, security group, or logon session) to which an ACE applies. Each ACE applies to a single trustee. In Figure 5, the term Principal is synonymous with trustee. Figure 5 shows that there are two ACEs assigned to the Password Reset group. In other words, the Password Reset group is the trustee (principal) for these two ACEs.
Inheritance. An ACE can be applied directly to an object, or it can be inherited from the resource's parent object. In Figure 5, the two ACEs for the All Users OU that contain the Password Reset group as a trustee aren't inherited from the parent container (i.e., the Inherited from column reads None) because the Delegation of Control Wizard added them directly to the DACL. Figure 6 shows the DACL for the Accounting OU. The Accounting OU's DACL contains two ACEs for the Password Reset group, but these ACEs are inherited from the All Users OU (i.e., the Inherited from column reads OU=All Users,DC=fabrikam,DC=local).
Introducing Remove-DSACE.ps1
I wrote Remove-DSACE.ps1 (short for remove directory service ACEs) to accomplish the following goals:
- Find OUs containing non-inherited ACEs containing a trustee.
- Recurse into sub-OUs if requested.
- Remove non-inherited ACEs containing a trustee.
- Produce concise output.
The script's syntax is as follows:
[-Trustee name] [-Recurse] [-ServerName name]
[-Credential credential] [-Confirm]
The -Report or -Remove parameter determines whether the script will list or remove non-inherited ACEs. If you specify -Report, the script finds non-inherited ACEs containing trustees, but it doesn't remove them. If you specify -Remove, the script removes the non-inherited ACEs. It's very important to understand that the script will remove all non-inherited ACEs for the trustee, not just ACEs added by the Delegation of Control Wizard. This is because there isn't any way to determine how the non-inherited ACEs were added.
The -Report and -Remove parameters are optional, but the script assumes the -Report parameter by default. The script will throw an error if you specify both parameters at the same time.
You use the -Path parameter to specify one or more distinguished names (DNs) of AD OUs. The -Path parameter name is optional and accepts pipeline input. Although you can specify multiple DNs, you can't use wildcards.
The -Trustee parameter names the trustee to find in the ACEs. The script examines each OU's DACL for non-inherited ACEs containing the named trustee. You can specify multiple trustees using a comma-delimited list or an array, but you can't use wildcards. You can specify trustee names using any of the name formats listed in Table 1.
Format | Example |
---|---|
Windows NT 4.0 naming format (NT4) | FABRIKAM\KenDyer |
The object's DN | CN=Ken Dyer,CN=Users,DC=fabrikam,DC=com |
The object's canonical name | fabrikam.com/Users/Ken Dyer |
The object's user principal name (UPN) | This email address is being protected from spambots. You need JavaScript enabled to view it. |
You include the -Recurse parameter if you want to search for OUs underneath the specified OU. If you want to connect to a specific domain controller (DC), you can specify the server's name with the
-ServerName parameter. Both the -Recurse and -ServerName parameters are optional.
The script supports alternative credentials. The -Credential parameter uses a PSCredential object that contains the username and password the script should use to connect to the domain.
The script also supports the -Confirm parameter. The -Confirm parameter is only meaningful in combination with the -Remove parameter. The -Confirm parameter is enabled by default, unless you disable it by specifying -Confirm:$FALSE or by setting the $ConfirmPreference variable to None. You should only disable the -Confirm parameter when you're absolutely certain you're removing the correct ACEs.
The script produces output objects containing the properties listed in Table 2.
Property | Description |
---|---|
Path | The OU's DN |
Trustee | The trustee's name in DOMAIN\name format |
ACEs | The number of non-inherited ACEs in the OU's ACL |
Result* | The word "Removed" or an error message |
*The Result property exists only when using the -Remove parameter. |
The script only includes OUs with non-inherited ACEs containing a trustee. Inherited ACEs for a trustee aren't included in the output. Figure 7 shows two examples. The first command in Figure 7 produces no output because the DACL for the Accounting OU doesn't contain any non-inherited ACEs for the Password Reset group. (The Accounting OU has two ACEs for the Password Reset group, but these ACEs are inherited from the All Users OU, as shown in Figure 6.) The second command in Figure 7 produces output. There are two non-inherited ACEs for the Password Reset group in the All Users OU (as seen in Figure 5).
Real-World Example
Let's look at how you might use Remove-DSACE.ps1 in the real world. Suppose that an administrator in the fabrikam.local domain had used the Delegation of Control Wizard to delegate permissions to the Secretarial Staff group in the All Users OU and some of the OUs underneath it, but he doesn't remember which OUs. You need to remove these delegated permissions so that you can delegate the permissions to other groups.
First, you need to see a list the OUs that have non-inherited ACEs containing the Secretarial Staff group. To do so, you can use the command:
-Path "OU=All Users,DC=fabrikam,DC=local" `
-Trustee "FABRIKAM\Secretarial_Staff" `
-Recurse | Format-List
This command and its output are shown in Figure 8.
From this output, you can see that there are three OUs that have non-inherited ACEs containing the Secretarial Staff group. After you've verified that you can remove these ACEs, you can replace the -Report parameter with the -Remove parameter and repeat the command, as shown in Figure 9. As I mentioned before, if the Secretarial Staff group has been assigned any other permissions outside of the Delegation of Control Wizard, those will be removed as well.
Take Control of AD Delegation
The Delegation of Control Wizard is a very helpful tool, but there's no easy way to quickly view or reverse its effects. Although you can use Dsrevoke.exe and Dsacls.exe to accomplish these tasks, these tools have some limitations. If you use the Remove-DSACE.ps1 script instead, you'll have better control over delegated permissions in AD.