Goatee PFE

Blog of Microsoft Premier Field Engineer Ashley McGlone featuring PowerShell scripts for Active Directory.

Active Directory OU Permissions Report: Free PowerShell Script Download

Active Directory OU Permissions Report: Free PowerShell Script Download

  • Comments 33
  • Likes

Who owns your OUs?

Have you ever lost your keys? It is a scary feeling. Someone out there could have keys to your house and your car. Your personal safety could be at risk. The same is true in Active Directory.  Do you know who has the keys to all of your accounts?

The Problem

In Active Directory we need to know who has the keys to our organizational units (OUs), the place where our users and computers live. Over the years OUs have grown to meet needs. Different teams may have been delegated access for managing users, groups, and computers. Then you come along as the new administrator. You probably have no idea where permissions have been granted to your OUs. And the scary thing is… neither does anyone else.  I know, because I’ve been there.  I hear the same thing from our customers.

Out-of-the-box we do not have a specific tool to report all of the OU permissions. You have to click each OU and view the security tab one-by-one, and we all know that is entirely impractical.  Today’s post contains a script download to generate a report of this vital information.

OU Permissions

OU permissions are multi-faceted. In other words… it’s complicated. They have a number of properties:

  • Principal
  • Allow/Deny
  • Scope
  • Applies To
  • Permissions

You’ll see the following dialog when you add a permission. This is enough to explain the complexity of the group access notation:


Now look how many Applies to: options there are.  Notice that this box scrolls a long way.


What we need is a report that lists the contents of the Advanced permissions GUI like this for every OU:


The matrix of potential permission configurations is mind-blogging.

The Solution: PowerShell

I had wondered if a report like this could be as simple as:

Import-Module ActiveDirectory
cd AD:
dir –recurse –directory | Get-ACL

Of course what works in our imaginations is rarely as simple in real life.  No, that code would not do it.  However, the concept is the same:

  • Get a list of all OUs
  • Loop through the OUs to retrieve their permissions
  • Export all data to a CSV file

Our good friend Get-ACL reports on more than file system permissions.  We can use this same cmdlet to query OU permissions as well.  Notice that we preface the OU distinguished name with AD:\.  Any time you query permissions with Get-ACL you need to expand the Access property to see the list of permission entries (ACEs):

Get-Acl -Path "AD:\OU=Domain Controllers,DC=wingtiptoys,DC=local" |
  Select-Object -ExpandProperty Access

Here is an example of an ActiveDirectoryAccessRule object that is returned for an OU:


We get an entry like this for every permission assigned to the OU.  My first instinct was to simply dump a list of these to CSV and be done with it.  But then I noticed the ObjectType and InheritedObjectType properties.  Hmmmm.  These are ugly GUIDs… not what we need for the report.  We need to translate these to the names of the objects that receive the permissions.  These names are what we see in that long drop-down list in the screenshot above.

To make a long story short I stayed up until 3AM researching this and traced it all down in the Active Directory Technical Specifications (MS-ADTS) here:

You are welcome to read these pages for yourself to understand the relationships.  Essentially these GUID values are stored on attributes of selected objects in the schema and configuration partitions of the AD database.  You can query these to build a list of names that will make the report readable.  So that’s what I did and put them into a hash table for quick look-ups when we generate the report.

The Big Finish

When we script it all out we get a report that looks something like this:


Obviously there are too many columns to read in the screenshot, but it is quite thorough.  Now you can use filters and pivot tables in Excel to analyze the data and produce reports showing exactly which OUs have delegated permissions, what kind of permissions, and who has them.  Likewise you can pivot the report by group to see a list of all OUs that a group can control.  You may want to filter the output by the IsInherited property.  By filtering for FALSE you will find everywhere that permissions are explicitly delegated in the OU tree.


I would advise all Active Directory shops to run and review this report on a quarterly basis to make sure there are no surprise administrators lurking in your domain. The report can be quite large for any size organization.  Perhaps this would be a good report to feed to the Information Security team, if you have one.  Now you know who holds the keys.


Download the full script from the TechNet Script Gallery.

Can you help me?  Yes!

If you would like to have me or another Microsoft PFE visit your company and assist with the ideas presented in this blog post, then contact your Microsoft Premier Technical Account Manager (TAM) for booking information.

For more information about becoming a Microsoft Premier customer email PremSale@microsoft.com.  Tell them GoateePFE sent you.

Sharing Links
  • You are Great guy

    Can use this PS script for other AD objects permission, such as user or group?

    Thank you so much

  • Please check script. OU_permissions.p-s-1.txt is empty!


  • Hello Patris_70,

    I'm not sure what happened to the script file.  I have fixed it now by linking to the copy posted at the TechNet Script Gallery.

    As for permissions on other object types they should work the same way.  You can modify the script accordingly.

    Thanks for the feedback,


  • Hello Ashely,

    Thank you for your immediate answer and support.

    Best regards

  • Ken Brumfield's CheckDSAcls.exe on Codeplex also does this, which had been the only way I knew to produce this type of "who has permissions on my OU" report (using /SearchForAcct switch). It is nice to see PowerShell can be leveraged to produce similar reports. Your investigation of the GUIDs in MS-ADTS is particularly helpful. Thanks for this script.

  • GoateePFE,

    How would you go about running this against another domain in the forest or a domain you have a trust with?

  • Hi Neil,

    Great question!  To scale this script across forests, domains, and trusts I can think of two methods:

    1.  You could parameterize the script in a function.  The parameters could reference the target server name and a credentials object that you capture.  Then you could modify all of the calls in the script to use these parameters.  This would be thorough, but a bit more time-consuming.

    2.  The easiest way would be to use Invoke-Command against the remote server and pass credentials like this:

    Invoke-Command -ComputerName CVDC1.cohovineyard.com -Credential (Get-Credential) -FilePath .\OU_permissions.ps1 |

    Export-CSV .\Remote-OUs.csv -NoTypeInformation

    In order for this last part to work I took out the final part of the script which exports the CSV.  This way it dumps $report into your local session for exporting locally.

    Hope this helps,


  • Hi,

    Doyou know this tool created by one of your colleague? colleablogs.technet.com/.../permissions-in-ad-lost-control.aspx



  • Guy, this is a great script. How can I export each OU to separate .CSV files? I would like each file to be named OU=Service Accounts,OU=Corp Objects,DC=corp,DC=domain,DC=com. Each file will be named with it's own distinctive OU. How can I go about accomplishing this?


  • Hello Dwight,

    This should put each OU in its own file:

    $schemaIDGUID = @{}

    $ErrorActionPreference = 'SilentlyContinue'

    Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter '(schemaIDGUID=*)' -Properties name, schemaIDGUID |

    ForEach-Object {$schemaIDGUID.add([System.GUID]$_.schemaIDGUID,$_.name)}

    Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).configurationNamingContext)" -LDAPFilter '(objectClass=controlAccessRight)' -Properties name, rightsGUID |

    ForEach-Object {$schemaIDGUID.add([System.GUID]$_.rightsGUID,$_.name)}

    $ErrorActionPreference = 'Continue'

    # Get a list of all OUs.  Add in the root containers for good measure (users, computers, etc.).

    $OUs  = Get-ADOrganizationalUnit -Filter * | Select-Object -ExpandProperty DistinguishedName

    $OUs += Get-ADObject -SearchBase (Get-ADDomain).DistinguishedName -SearchScope OneLevel -LDAPFilter '(objectClass=container)' | Select-Object -ExpandProperty DistinguishedName

    # Loop through each of the OUs and retrieve their permissions.

    # Add report columns to contain the OU path and string names of the ObjectTypes.

    ForEach ($OU in $OUs) {

       # This array will hold the report output.

       $report = @()

       $report += Get-Acl -Path "AD:\$OU" |

        Select-Object -ExpandProperty Access |

        Select-Object @{name='organizationalUnit';expression={$OU}}, `

                      @{name='objectTypeName';expression={if ($_.objectType.ToString() -eq '00000000-0000-0000-0000-000000000000') {'All'} Else {$schemaIDGUID.Item($_.objectType)}}}, `

                      @{name='inheritedObjectTypeName';expression={$schemaIDGUID.Item($_.inheritedObjectType)}}, `


       # Dump the raw report out to a CSV file for analysis in Excel.

       $report | Export-Csv ".\$OU.csv" -NoTypeInformation


  • Thanks for this script. It is extremely useful! Smita C

  • If anyone wants an easy to use GUI alternative to the Powershell options, I made a tool recently for reporting AD permissions. More info and a download link for the free edition (which is not time limited) here for anyone interested: http://www.cjwdev.co.uk/Software/ADPermissionsReporter/Info.html

  • Gr8 Gui Tool Chris

  • Great script, thanks very much!

  • How can I get the owner on AD OU's?

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment