Share via


Active Directory OU Permissions Report: Free PowerShell Script Download

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:

clip_image002

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

clip_image003

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

clip_image005

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:

image

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:

image

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.

Conclusion

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.

Comments

  • Anonymous
    January 01, 2003
    Hi Krishna,

    Great question. Here are a couple options for the current user:

    whoami /priv
    GPRESULT or Get-GPResultantSetOfPolicy

    For default group privileges:
    https://technet.microsoft.com/en-us/library/dn487460.aspx

    For tracking down user and group privileges in the directory:
    http://social.technet.microsoft.com/wiki/contents/articles/6477.how-to-view-or-delete-active-directory-delegated-permissions.aspx

    Hope this helps,
    Ashley
    GoateePFE

  • Anonymous
    March 25, 2013
    You are Great guy Can use this PS script for other AD objects permission, such as user or group? Thank you so much

  • Anonymous
    March 25, 2013
    Please check script. OU_permissions.p-s-1.txt is empty! Thanks

  • Anonymous
    March 25, 2013
    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, Ashley

  • Anonymous
    March 25, 2013
    Hello Ashely, Thank you for your immediate answer and support. Best regards

  • Anonymous
    April 01, 2013
    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.

  • Anonymous
    April 01, 2013
    GoateePFE, How would you go about running this against another domain in the forest or a domain you have a trust with?

  • Anonymous
    April 02, 2013
    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, GoateePFE
  • Anonymous
    September 12, 2013
    Hi, Doyou know this tool created by one of your colleague? colleablogs.technet.com/.../permissions-in-ad-lost-control.aspx Regards Guillaume

  • Anonymous
    December 04, 2013
    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? Thanks

  • Anonymous
    December 11, 2013
    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 }

  • Anonymous
    January 09, 2014
    Thanks for this script. It is extremely useful!Smita C
  • Anonymous
    January 19, 2014
    The comment has been removed
  • Anonymous
    March 17, 2014
    Today's post gives you a script to crawl your file shares and document the AD users and groups referenced in NTFS permissions. I’m sure others have published similar scripts, but I want to approach it from the angle of Active Directory group
  • Anonymous
    April 09, 2014
    Gr8 Gui Tool Chris
  • Anonymous
    July 09, 2014
    Great script, thanks very much!
  • Anonymous
    August 25, 2014
    How can I get the owner on AD OU's?
  • Anonymous
    August 25, 2014
    thanks for sharing.
  • Anonymous
    August 25, 2014
    Hello John,

    This one-liner will list all of your OUs and their owners:

    Get-ADOrganizationalUnit -filter * -Properties nTSecurityDescriptor | Select-Object DistinguishedName, @{name='Owner';Expression={$_.nTSecurityDescriptor.Owner}}

    Hope this helps,
    Ashley
    @GoateePFE
    • Anonymous
      February 22, 2018
      What I wish is that I knew how to get the information to construct such a complicated command as: Get-ADOrganizationalUnit -filter * -Properties nTSecurityDescriptor | Select-Object DistinguishedName, @{name=’Owner’;Expression={$_.nTSecurityDescriptor.Owner}}. I get it all the way to "select-object distinguishedname. But the next part could be written in Greek. Where did you get that information and the knowledge to construct the query like that? What do I need to read?
  • Anonymous
    August 27, 2014
    Great Script, it will be helpful to know how to get permissions from Domain root also
  • Anonymous
    August 27, 2014
    Hmm simply use Get-ADPermission from Exchange admin tools ? Never understood why such a critical cmdlet belonged exclusively to the Exchange group, when AD admins have so much use of it, and must struggle with Get-ACL instead...
  • Anonymous
    August 28, 2014
    The comment has been removed
  • Anonymous
    August 31, 2014
    The script to check permissions at domain root is as below

    Get-ADPermission -Identity mydomain.com | select-object user, Identity, deny, @{n="AccessRights";e={($_ | select -expandproperty AccessRights) -join '|' }},@{n="ExtendedRights";e={($_ | select -expandproperty ExtendedRights) -join '|' }}, IsInherited, @{label = "Properties ";expression = {[string]$.Properties }}, @{label = "ChildobjectTypes";expression = {[string]$.ChildobjectTypes }}, InheritedObjecttype, Inheritancetype | export-csv C:get-adpermission.csv

    Thanks
  • Anonymous
    August 31, 2014
    thanks
  • Anonymous
    September 05, 2014
    @LMS,
    I have updated the script download to now include the root of the domain in the permissions report. I don't know why I didn't do that to begin with. Thanks for the feedback.
    Ashley McGlone
    @GoateePFE
  • Anonymous
    September 09, 2014
    It's Great, Thank You...
  • Anonymous
    September 09, 2014
    thank you
  • Anonymous
    October 29, 2014
    Welcome! Today’s post includes demo scripts and links from the Microsoft Virtual Academy event: Using PowerShell for Active Directory . We had a great time creating this for you, and I hope you will share it with anyone needing to ramp up their
  • Anonymous
    January 31, 2015
    how do I know the privileges of a particular user/Group?
  • Anonymous
    March 05, 2015
    Great script, extremely helpful! Thank you very much for sharing
  • Anonymous
    May 14, 2015
    This script does nothing it appears to run for me but I never see any output
  • Anonymous
    May 14, 2015
    Hi Emily,
    Can you find the file OU_Permissions.csv in your working directory?
    Ashley
  • Anonymous
    June 15, 2015
    Thank you Ashley! your videos on AD powershell are great. And yes you are powershellAD_master
  • Anonymous
    January 21, 2016
    What if I don't want to search the entire domain, but instead, want to search through the entire OU structure of a single OU in a domain? Also, what about do this in different domains (run script on domain B from domain A)?
  • Anonymous
    February 24, 2016
    Do the new LAPS attributes have their own unique GUID? I er, binged the schemaIDGUID value in my schema for one of the new properties with no result, so is it randomly created?
  • Anonymous
    February 24, 2016
    How can find if a user ABC has delegation for any OU or not.
  • Anonymous
    March 11, 2016
    The comment has been removed
  • Anonymous
    April 13, 2016
    Hi, can you help me with extracting report with the help of Powershell for entire domain? Like how many active AD groups their description and all..regardsAvi
  • Anonymous
    May 21, 2016
    Is there any PS command to find out who is moving users from one OU to another in windows 2008 R2 domain.
  • Anonymous
    August 03, 2016
    How do I run this? Do I run it as is with a parameter? Or do I take pieces of it?
  • Anonymous
    September 05, 2016
    Great script! Ty
  • Anonymous
    September 06, 2016
    Hello Ashley,thank you for your great article. I got here while looking for a way to get a list of all possible inheritance-options (see your "Applies to"-screenshot). As far as I know this uses the "ActiveDirectoryAccessRule.InheritanceType" .Net-class with the "appliesto"-property but unfortunately I can't find any way to get a list or an export of this above mentioned dropdown-list. Do you have, by any chance, an idea how to realise this via powershell ?Thanks in advance and kind regardsMatthias
    • Anonymous
      April 27, 2017
      I would like to bump this question
  • Anonymous
    September 24, 2016
    Great and many , many thanks but.. i give up... how do i target for child domains? Thanks for this, this is a huge help for a serious issue i have been trying to get a handle on for yrs
    • Anonymous
      October 28, 2016
      Hi Steve,To target child domains you have two options: 1. Run the code locally in the other domain. 2. Improve this code to take parameters for domain name and domain credential. Both are viable alternatives.GoateePFE
  • Anonymous
    November 15, 2016
    Hi, I am wondering if you could tell me how to modify the report to see any user with any delegated permission? But exclude any "read only" or "view only" type permissions? We have some delegation granted by groups, but we also have before my time as an administrator users that were granted permissions directly to their user account. Such as "change password" or other delegated permissions.
    • Anonymous
      November 30, 2016
      Hi Tara,Hmm. To see specific users you would need to expand group memberships and add that to the report. To exclude certain types of permissions you could filter the output using Where-Object against the ActiveDirectoryRights property. You could probably do something like "Where-Object {$_.ActiveDirectoryRights -notlike "read"}". Hope this helps.AshleyGoateePFE
  • Anonymous
    March 10, 2017
    Excellent! Saved me some legwork, but I have one suggestion... In addition to the DN, add the Canonical Name to the report for Sortability when imported into a spreadsheet. In organizations with like operating OU structures that "should" have like permissions, its easier to sort, compare and pivot by something that's easier to read than a DN.
  • Anonymous
    March 18, 2017
    The comment has been removed
  • Anonymous
    May 18, 2017
    Thanks for this useful script. I modified the script a bit to fit my needs. I am trying to filter out the principals which are default.Currently I am doing this "Where-Object {$_.IdentityReference -notmatch "BUILTIN|NT AUTHORITY|EVERYONE|CREATOR OWNER|DOMAIN ADMINS|Domain Controllers|EXCHANGE|Organization Management|Enterprise Admins|Public Folder|S-1-5-32-554|S-1-5-32-548|S-1-5-32-557|S-1-5-32-561|S-1-5-32-550"} |"I want to so have a variable with all SIDs and principals. and the script should look into that array and select objects which doesnt match from the array.
  • Anonymous
    December 15, 2017
    Updating the Manager attribute of a user with an Object Type 'Contacts' is successful via AD but fails using Powershell. It seems that PS can update the Manager field by Object Type 'Users'Can there be any special permission setting to fix this or another way?
  • Anonymous
    February 07, 2019
    Hello Ashely,How do you query only one OU? I have something like: ou=Groups,ou=O365-contoso.com,ou=Americas,ou=Exchange,dc=local,dc=comI have hundreds of OUs I'm not interested about, so I'd like to just query particular OUs. I'd appreciate your response very much.P.S. Thank you for putting this script together. It definitely is a great life saver.