4

I am trying to get effective permissions of certain active directory users on various Active Directory objects. I can see these permissions from the UI - enter image description here

I am trying to get this using Powershell. I have already tried dsacls and Get-Acls but these don't give effective permissions. These both give "who has access/permissions" which is not the same as "who has what effective permissions". These also don't list out all the granular details that would provide context around the effective access.

Any pointers on how this can be achieved programmatically would be really appreciated.

Update -

Effective permissions here would mean which permissions are allowed to the object in reality based on inheritances or other rules set at a different level.

For example -

All the properties in the below example are not visible with Get-ACL. enter image description here

Another example of what Get-Acl shows while the UI tells differently is when I pulled permissions for domain admins on one of the OUs via Get-ACL , after resolving the values in ObjectType and InheritedObjectType (use get-effective access function mentioned by Santiago Squarzon) I get -

enter image description here

While the UI effective access shows-

enter image description here

My end goal is to get all the permission in the above screenshot using powershell.

4
  • Get-Acl should give you that information. Use the grouping operator (..) to expose that code property. (Get-ACL .\).Access. Can you clarify what you mean by "effective permissions"? Commented May 26, 2021 at 1:23
  • All Objects (Full Control) in the ACL you're showing means full control over the ActiveDirectoryRights, it is not the same as Effective Access on Advanced Security Settings. Compare the result of an IdentityReference the you know has full control with the one you're showing, you'll see the difference. In addition, you're not showing if there is other ACL denying Full Control over that IdentityReference. As I said in my answer, you need to know how to read the output of Get-ACL. Commented May 27, 2021 at 4:01
  • This was the only entry for domain controllers. It didn't have any deny rules. I didn't include the identity reference as I wanted to avoid censoring the image. Both the screen shots show the result of the same identity reference. Commented May 27, 2021 at 11:45
  • Just for reference, I edited my answer to show you how Full Control looks like compared with WriteDACL. Commented May 27, 2021 at 14:32

3 Answers 3

3

Note

The function used in this answer was rewritten as a binary cmdlet and published to the Gallery. There is no longer a dependency on the Active Directory Module.

If you want to try out the Module version, first install it:

Install-Module ADEffectiveAccess -Scope CurrentUser

Then the usage is similar to what's shown below however you can use the cmdlet itself for filtering, see the Usage section for details.


This is pretty close to what you're looking for. Source for more details. Access Control Lists with Get-ACL are not as easy to read as Effective Access on Advanced Security Settings and I don't think there is a way around that. I do think that, once used to it, Get-ACL gives a lot more details when you know what you're looking for \ filter the ACLs to get what you're looking for.

Code

function Get-EffectiveAccess {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidatePattern('(?:(CN=([^,]*)),)?(?:((?:(?:CN|OU)=[^,]+,?)+),)?((?:DC=[^,]+,?)+)$')]
        [alias('DistinguishedName')]
        [string] $Identity,

        [parameter()]
        [alias('Domain')]
        [string] $Server
    )

    begin {
        $guid    = [guid]::Empty
        $GUIDMap = @{}

        if($PSBoundParameters.ContainsKey('Server')) {
            $domain = Get-ADRootDSE -Server $Server
        }
        else {
            $domain = Get-ADRootDSE
        }

        $params = @{
            SearchBase  = $domain.schemaNamingContext
            LDAPFilter  = '(schemaIDGUID=*)'
            Properties  = 'name', 'schemaIDGUID'
            ErrorAction = 'SilentlyContinue'
        }
        $adObjParams = @{
            Properties = 'nTSecurityDescriptor'
        }

        if($PSBoundParameters.ContainsKey('Server')) {
            $params['Server']  = $Server
            $adObjParams['Server'] = $Server
        }
        $schemaIDs = Get-ADObject @params

        $params['SearchBase'] = "CN=Extended-Rights,$($domain.configurationNamingContext)"
        $params['LDAPFilter'] = '(objectClass=controlAccessRight)'
        $params['Properties'] = 'name', 'rightsGUID'
        $extendedRigths = Get-ADObject @params

        foreach($i in $schemaIDs) {
            if(-not $GUIDMap.ContainsKey([guid] $i.schemaIDGUID)) {
                $GUIDMap.Add([guid] $i.schemaIDGUID, $i.name)
            }
        }
        foreach($i in $extendedRigths) {
            if(-not $GUIDMap.ContainsKey([guid] $i.rightsGUID)) {
                $GUIDMap.Add([guid] $i.rightsGUID, $i.name)
            }
        }
    }

    process {
        try {
            $adObjParams['Identity'] = $Identity
            $object = Get-ADObject @adObjParams

            foreach($acl in $object.nTSecurityDescriptor.Access) {
                if($guid.Equals($acl.ObjectType)) {
                    $objectType = 'All Objects (Full Control)'
                }
                elseif($GUIDMap.ContainsKey($acl.ObjectType)) {
                    $objectType = $GUIDMap[$acl.ObjectType]
                }
                else {
                    $objectType = $acl.ObjectType
                }

                if($guid.Equals($acl.InheritedObjectType)) {
                    $inheritedObjType = 'Applied to Any Inherited Object'
                }
                elseif($GUIDMap.ContainsKey($acl.InheritedObjectType)) {
                    $inheritedObjType = $GUIDMap[$acl.InheritedObjectType]
                }
                else {
                    $inheritedObjType = $acl.InheritedObjectType
                }

                [PSCustomObject]@{
                    Name                  = $object.Name
                    IdentityReference     = $acl.IdentityReference
                    AccessControlType     = $acl.AccessControlType
                    ActiveDirectoryRights = $acl.ActiveDirectoryRights
                    ObjectType            = $objectType
                    InheritedObjectType   = $inheritedObjType
                    InheritanceType       = $acl.InheritanceType
                    IsInherited           = $acl.IsInherited
                }
            }
        }
        catch {
            $PSCmdlet.WriteError($_)
        }
    }
}

Examples

  • Get the Effective Access of the Organizational Unit named ExampleOU:
Get-ADOrganizationalUnit -Filter "Name -eq 'ExampleOU'" |
    Get-EffectiveAccess | Out-GridView
  • Get the Effective Access of the Organizational Unit named ExampleOU on a Trusted Domain:
Get-ADOrganizationalUnit -Filter "Name -eq 'ExampleOU'" -Server trustedDomain |
    Get-EffectiveAccess -Server trustedDomain | Out-GridView
  • Same as above but using the OU's DistinguishedName attribute:
Get-EffectiveAccess -Identity 'OU=ExampleOU,DC=domainName,DC=com' | Out-GridView
  • Store the Effective Access of the group named exampleGroup in a variable:
$effectiveAccess = Get-ADGroup exampleGroup | Get-EffectiveAccess
  • Get the Effective Access of the first 10 OUs found in the Domain:
Get-ADOrganizationalUnit -Filter * | Select -First 10 |
    Get-EffectiveAccess | Out-GridView

Sample

For reference, this is how Full Control looks like with Get-ACL

fullcontrol

Compared with BUILTIN\Administrators which has write permissions on this OU but not Full Control

writepermissions

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for providing with the information and the code this is useful. Based on my initial testing this gives more information than the by resolving the values in the ObjectType and InheritedObjectType. It still is not able to get the permissions that you can see in the Effective Access. Also with get-acls that this function uses permissions like Write ObjectSid, Read ObjectSid etc. are not visible. (will update the question) Also properties like Write Property does not tell me exactly which properties is a user given access while which property is denied.
I agree that this does not reflect the effective access tab, however it helped me quickly find a misconfigured OU by comparing the configuration of two OUs with this function, so it can be a valuable tool still! +1
You might want to have a look at the Note on top of my answer, the new binary version is highly improved from what I had here, also no requirement for AD module ;)
1

You can try PowerShellAccessControl module I think the details for this module are covered in this youtube video with the function Get-EffectiveAccess. This should help you get the information. The module has been deleted from the Microsoft's PS Gallery. I am not sure how you might be able to install the module from Github, I couldn't try it as I am working with a Mac.

Comments

0

In this example, the group in question has WriteOwner and WriteDACL rights. This means they can seize ownership of the AD object in question, and once they do the DACL does not matter anymore.

Additionally the group in question is the Administrators group, which means they can seize ownership of any AD object regardless of the DACL on it, much as local admin can seize ownership of any NTFS object. Once they seize ownership they can do whatever they want to.

Hence their "effective permissions" are GenericAll.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.