Get-Acl Cheatsheet

6 min readSep 1, 2022

TL;DR cheatsheet on querying using Get-Acl. Background on ACLs & why they matter here, although this lab exercise probably makes the point best.

Welcome to Part III of our cheatsheet series!

Part I: Mimikatz cheatsheet

Part II: Set-Acl cheatsheet

Part III: Get-Acl cheatsheet

Part IV: Enumerating AD cheatsheet

Part V: Windows reverse shells cheatsheet

Part VI: MS Graph PowerShell cheatsheet

Part VII: Hash cracking cheatsheet

Part VIII: The Credential Theft Shuffle

Part IX: SACLs & Querying Collected Logs

Part X: Setting up a simple AD lab in Azure


This is another seemingly simple command, right? It can be, but it really depends on exactly what you are looking for and how specific your query is. If all you want to do is see an ACL then by all means, just

(Get-Acl (Get-ADDomain).DistinguishedName).Access

However this is hardly useful by itself. Generally you will be looking either for who holds certain DangerousRights or what DangerousRights are held by a given user, like yourself.

We will dive into this by examining

  • What DangerousRights are
  • Automated querying if a given user holds them
  • Break this down Barney Style

DangerousRights table

DangerousRights (Jake Hildreth/Trimarc/Sean Metcalf’s term):

  • GenericAll (grants all privileges)
  • WriteDACL (grants one the right to give oneself privileges)
  • WriteOwner (grants the right to seize ownership, and then give oneself privileges)
  • GenericWrite (Functionally the same thing as WriteProperty with ObjectType all 0s)
  • WriteProperty on anything with ObjectType = 00000000–0000–0000–0000–000000000000
  • WriteProperty on OUs with ObjectType = f30e3bbe-9ff0–11d1-b603–0000f80367c aka gPLink
  • WriteProperty on Groups with ObjectType = bf9679c0–0de6–11d0-a285–00aa003049e2 aka member
  • WriteProperty on Groups with ObjectType = bc0ac240–79a9–11d0–9020–00c04fc2d4cf aka Group Membership Property set, includes member
  • Self on Groups with ObjectType = bf9679c0–0de6–11d0-a285–00aa003049e2 aka self-membership
  • Self on Groups with ObjectType = 00000000–0000–0000–0000–000000000000 includes the above
  • ExtendedRight on Users with ObjectType = 00299570–246d-11d0-a768–00aa006e0529 aka ResetPassword
  • ExtendedRight on Users with ObjectType = 00000000–0000–0000–0000–000000000000 includes the above

Rights specific to the domain root, $root = (Get-ADDomain).DistinguishedName

  • ExtendedRight with ObjectType = 1131f6aa-9c07–11d1-f79f-00c04fc2dcd2 (DS-Replication-Get-Changes)
  • ExtendedRight with ObjectType = 1131f6ad-9c07–11d1-f79f-00c04fc2dcd2 (DS-Replication-Get-Changes-All)
  • ExtendedRight with ObjectType = 00000000–0000–0000–0000–000000000000 includes the above

Rights specific to OUs

  • Delete (self-explanatory)
  • DeleteChild (delete the items in the OU)
  • CreateChild (create items, aka users, in the OU)
  • DeleteTree (self-explanatory)

Query for DangerousRights held by yourself

I call this one Mishky’s Red Team as it was inspired by PowerView’s Invoke-ACLScanner and Trimarc’s query of ADCS rights. You can tell how heavily Trimarc influenced it as we didn’t even change all their variable names.

Download Get-ADNestedGroups.ps1 from and import it first. Mishky’s PowerView relies on it to check all groups the given user is nested in. Invoke-ACLScanner doesn’t check for rights held by all the groups the user is nested in.

The original proof of concept code is below. The current refined version is located here.

#Run/import Get-ADNestedGroups.ps1 first! (Available from:
Import-Module ActiveDirectory
Import-Module .\Get-ADNestedGroups.ps1
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName
$Accounts = (Get-ADUserNestedGroups (Get-ADUser "$env:username" -Properties *).DistinguishedName).Name$MyGroups = $Accounts.ForEach{[regex]::Escape($_)} -join '|'
$MyGroups2 = $MyGroups.Replace('\','')
$AlsoCheck = "$env:username|Everyone|Authenticated Users|Domain Users"$ADCS_Objects = (Get-ADObject -Filter * -SearchBase $ADRoot).DistinguishedName$DangerousRights = "GenericAll|WriteDACL|WriteOwner|GenericWrite|WriteProperty|Self"$DangerousGUIDs = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2|1131f6ad-9c07-11d1-f79f-00c04fc2dcd2|00000000-0000-0000-0000-000000000000|00299570-246d-11d0-a768-00aa006e0529"$FishyGUIDs = "ab721a56-1e2f-11d0-9819-00aa0040529b|ab721a54-1e2f-11d0-9819-00aa0040529b"ForEach ($object in $ADCS_Objects)
$BadACE = (Get-Acl $object -ErrorAction SilentlyContinue).Access | Where-Object {(($_.IdentityReference -match $MyGroups2) -or ($_.IdentityReference -match $AlsoCheck)) -and (($_.ActiveDirectoryRights -match $DangerousRights) -or ((($_.ActiveDirectoryRights -like "*ExtendedRight*") -and (($_.ObjectType -match $DangerousGUIDs) -or ($_.ObjectType -match $FishyGUIDs))))) -and ($_.AccessControlType -eq "Allow")}If ($BadACE)
Write-Host "Object: $object" -ForegroundColor Red

Back in the Set-Acl cheatsheet we listed examples that gave DCSync rights to a specific user and Self rights to a group. We then run Mishky’s PowerView as that user and it flags those three specific ACEs in the domain root’s ACL and lets us know what object this ACL applies to in red font.

Bear in mind that “DCSync rights” are two ExtendedRights with GUIDs, so there are two different ACEs. To recap, those two rights are DS-Get-Replication-Changes and DS-Get-Replication-Changes-All.

Naturally if you are in the GUI they have different names. Oh Microsoft, consistency is not their strong suit.

To my surprise, Mishky’s query didn’t really take any longer to run than PowerView’s Invoke-ACLScanner. It also doesn’t trip Defender :P

Breaking this down Barney Style

The basic syntax for querying an ACL is

$thing = (Get-ADUser $env:username –Prop *).DistinguishedName ; (Get-Acl “$thing”).Access

To look for specific things start tacking stuff to look for onto the end:

| Where-Object {$_.ObjectType -eq “00299570–246d-11d0-a768–00aa006e0529”}

To look for multiple conditions just start putting them inside parenthesis and use operators:

| Where-Object {($_.ActiveDirectoryRights –eq “ExtendedRight”) -and ((ObjectType -eq “00299570–246d-11d0-a768–00aa006e0529”) -or (ObjectType -eq “00000000–0000–0000–0000–000000000000”))}

This starts getting long, which is why we simply used a variable called $DangerousGUIDs.

Example query

Let’s say you want to see who has Self rights with either the specific “self-membership” GUID or all 0s on Domain Admins:

(Get-Acl (Get-ADGroup “Domain Admins”).DistinguishedName).Access | Where-Object {($_.ActiveDirectoryRights -like “*Self*”) -and (($_.ObjectType -eq “bf9679c0–0de6–11d0-a285–00aa003049e2”) -or ($_.ObjectType -eq “00000000–0000–0000–0000–000000000000”)) -and ($_.AccessControlType -eq “Allow”)}

Another example query

If you are looking for something really specific then you have to use the table of DangerousRights and then put the whole query together. This query is for who can pull NTLM hashes from NTDS.dit, aka DCSync:

$suspects = ((Get-ACL (Get-ADDomain).DistinguishedName).Access | Where {((($_.ActiveDirectoryRights -like “*ExtendedRight*”) -and (($_.ObjectType -eq “1131f6aa-9c07–11d1-f79f-00c04fc2dcd2”) -or ($_.ObjectType -eq “1131f6ad-9c07–11d1-f79f-00c04fc2dcd2”) -or ($_.ObjectType -eq “00000000–0000–0000–0000–000000000000”))) -or ($_.ActiveDirectoryRights -like “*GenericWrite*”) -or ($_.ActiveDirectoryRights -like “*GenericAll*”) -or ($_.ActiveDirectoryRights -like “*WriteDACL*”) -or ($_.ActiveDirectoryRights -like “*WriteOwner*”) -and ($_.AccessControlType -eq “Allow”))}).IdentityReference

These queries can get rather long, which is why it’s often simpler to match against a list:

(Get-Acl $object).Access | Where-Object {$_.ActiveDirectoryRights -match $DangerousRights}

Querying NTFS

Query the owner:

(Get-Acl -Path “I:”).Owner

Query the ACL:

(Get-Acl -Path “I:”).Access

You can then query for exactly what you are looking for using the same syntax as before:

(Get-Acl -Path “I:”).Access | Where-Object {($_.FileSystemRights -eq “FullControl”) -and ($_.AccessControlType -eq “Allow”)}

Microsoft being Microsoft, the rights that matter in a security context have NTFS specific names. A full list is here.

Some of the more important ones:

  • ChangePermissions (NTFS version of WriteDACL, allows one to change the ACL)
  • FullControl (NTFS version of GenericAll, includes all rights)
  • TakeOwnership (NTFS version of WriteOwner, allows one to change the owner and then do anything)
  • Delete (self-explanatory)
  • DeleteSubdirectoriesandFiles

NTFS specific

  • Modify (includes the rights Delete, Write, & ReadAndExecute)
  • ReadAndExecute (read, copy, run)
  • Write (pretty self-explanatory, allows one to change the data in a file)
  • WriteData (same as Write, but without the ability to write file attributes, file’s ACL, etc)

NTFS privileges matter too. Tools like PowerUp.ps1 can automate finding executables that run as a higher privileged user but let lower level users write to them, for example, and then take advantage of this to elevate privileges.


The syntax itself is not all that tricky, you just have to know what to look for. That’s where the table of DangerousRights comes in. The parenthesis and operators can get tricky as it’s easy to forget a single parenthesis somewhere.

Hence using variables and lists to match to is much easier. It also allows you to do things like whitelist groups that you meant to delegate to and then query what groups have DangerousRights and are not whitelisted.

Mishky’s Blue Team does exactly this. You feed it a CSV with OUs and who should have rights, then it flags anyone who is not whitelisted. The howto is here and the tool itself is here.


Ired team on DCSync specific rights:

Handy GUID table:

Selfadsi GUID list:

NTFS privileges:

List of NTFS privileges as seen in PowerShell:




I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.