Active Directory – Permissions

I had the pleasure to visit The Experts Conference 2012. This time in Frankfurt. After a really early start (train at 5:30) and some train troubles we arrived a bit late at the InterContinental. Well I will not go in details about the various sessions, except that they were great and the catering was excellent, but I learned that AD permissions seems to be difficult to manage with the available commandlets from Microsoft or from “Quest”.
So I promised one of the speakers, to blog about my solution to this problem.
I am afraid, this will be a longer entry :-/
Until now, as I mentioned in my first blog entry, I did not look into managing AD Objects with Quest or MS commandlet. While writing this entry, I found out how they work. So first of all, despite what I was told, you can manage permissions with the MS and Quest commandlets. Microsoft’s commandlets do not have any command to manage permissions directly.
With Quest you can use Get-QADPermission, Add-QADPermission and Remove-QADPermission.

[PS] Scripts:> Get-QADPermission "DC=adds,DC=int" –Inherited
Permissions for: adds.int/

Ctrl Account Rights Source AppliesTo
—- ——- —— —— ———
Deny Everyone Delete Child objects Not inherited This object only
ADDSLink Group Policy Objects Read/Write gPLink Not inherited This object and…
ADDSLink Group Policy Objects Read/Write gPOptions Not inherited This object and…
ADDSAllow Group Policy Modeling Generate Resultant Set of Policy… Not inherited This object and…
ADDSAllow Group Policy Modeling Generate Resultant Set of Policy… Not inherited This object and…
[PS] Scripts:>
[PS] Scripts:>

Well, that’s not bad. And it translates the Rights GUIDs. As you may notice, I am looking at the root of a domain. The provided rights seem a bit short.
Let’s try to add another switch: -SchemaDefault

[PS] Scripts:> Get-QADPermission "DC=adds,DC=int" -inherited -SchemaDefault
Permissions for: adds.int/

Ctrl Account Rights Source AppliesTo
—- ——- —— —— ———
Deny Everyone Delete Child objects Not inherited This object only
Everyone Read all properties AD Default This object only
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Special AD Default This object only
NT AUTHORITYAuthenticated Users Special AD Default This object only
NT AUTHORITYSYSTEM Full control AD Default This object only
ADDSAdministrators Special AD Default This object and…
ADDSPre-Windows 2000 Compatible Access List Contents AD Default This object and…
ADDSPre-Windows 2000 Compatible Access Special AD Default This object only
ADDSDomain Admins Special AD Default This object only
ADDSEnterprise Admins Full control AD Default This object and…
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Read tokenGroups AD Default Child user objects
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Read tokenGroups AD Default Child group obj…
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Read tokenGroups AD Default Child computer …
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Replicating Directory Changes In… AD Default This object only
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Replicating Directory Changes AD Default This object only
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Replication Synchronization AD Default This object only
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Read Only Replication Secret Syn… AD Default This object only
NT AUTHORITYENTERPRISE DOMAIN CONTRO… Manage Replication Topology AD Default This object only
NT AUTHORITYSELF Special AD Default All child objects
NT AUTHORITYAuthenticated Users Update Password Not Required Bit AD Default This object only
NT AUTHORITYAuthenticated Users Enable Per User Reversibly Encry… AD Default This object only
NT AUTHORITYAuthenticated Users Unexpire Password AD Default This object only
ADDSAdministrators Replicating Directory Changes All AD Default This object only
ADDSAdministrators Read Only Replication Secret Syn… AD Default This object only
ADDSAdministrators Manage Replication Topology AD Default This object only
ADDSAdministrators Replicating Directory Changes In… AD Default This object only
ADDSAdministrators Replication Synchronization AD Default This object only
ADDSAdministrators Replicating Directory Changes AD Default This object only
ADDSPre-Windows 2000 Compatible Access Special AD Default Child inetOrgPe…
ADDSPre-Windows 2000 Compatible Access Special AD Default Child group obj…
ADDSPre-Windows 2000 Compatible Access Special AD Default Child user objects
ADDSIncoming Forest Trust Builders Create Inbound Forest Trust AD Default This object only
ADDSEnterprise Read-only Domain Cont… Replicating Directory Changes AD Default This object only
ADDSDomain Controllers Replicating Directory Changes All AD Default This object only
ADDSLink Group Policy Objects Read/Write gPLink Not inherited This object and…
ADDSLink Group Policy Objects Read/Write gPOptions Not inherited This object and…
ADDSAllow Group Policy Modeling Generate Resultant Set of Policy… Not inherited This object and…
ADDSAllow Group Policy Modeling Generate Resultant Set of Policy… Not inherited This object and…
[PS] Scripts:>
[PS] Scripts:>

That’s more likely. The Quest tools distinguish between inherited, not inherited and permissions which were added based on AD schema. These AD Default permissions are explicit (not inherited) permissions. Quest makes it therefore quite easy to find permissions set by an Administrator or set while created.
With Microsoft’s Active Directory module you have to dig a bit deeper as it doesn’t include a handy commandlet for dealing with security descriptors.

[PS] Scripts:> (Get-ADObject -Identity "DC=adds,DC=int" -Properties ntSecurityDescriptor).ntSecurityDescriptor

Path Owner Access
—- —– ——
BUILTINAdministrators Everyone Deny …
[PS] Scripts:>
[PS] Scripts:>

That’s a bit disappointing. Where is the rest? But well, we are (at the moment) interested in the access rules.

[PS] Scripts:> (Get-ADObject -Identity "DC=adds,DC=int" -Properties ntSecurityDescriptor).ntSecurityDescriptor.access | ft

ActiveDirectory InheritanceType ObjectType InheritedObject ObjectFlags AccessControlTy IdentityReferen IsInherited InheritanceFlag PropagationFlag
Rights Type pe ce s s
————— ————— ———- ————— ———– ————— ————— ———– ————— —————
DeleteChild None 00000000-000… 00000000-000… None Deny Everyone False None None
ReadProperty None 00000000-000… 00000000-000… None Allow Everyone False None None
GenericRead None 00000000-000… 00000000-000… None Allow NT AUTHORITY… False None None
GenericRead None 00000000-000… 00000000-000… None Allow NT AUTHORITY… False None None
GenericAll None 00000000-000… 00000000-000… None Allow NT AUTHORITY… False None None
…, WriteOwner All 00000000-000… 00000000-000… None Allow BUILTINAdmi… False …ainerInherit None
ListChildren All 00000000-000… 00000000-000… None Allow BUILTINPre-… False …ainerInherit None
… ReadControl None 00000000-000… 00000000-000… None Allow BUILTINPre-… False None None
…, WriteOwner None 00000000-000… 00000000-000… None Allow ADDSDomain … False None None
GenericAll All 00000000-000… 00000000-000… None Allow ADDSEnterpr… False …ainerInherit None
ReadProperty Descendents b7c69e6d-2cc… bf967aba-0de… …eTypePresent Allow NT AUTHORITY… False …ainerInherit InheritOnly
ReadProperty Descendents b7c69e6d-2cc… bf967a9c-0de… …eTypePresent Allow NT AUTHORITY… False …ainerInherit InheritOnly
ReadProperty Descendents b7c69e6d-2cc… bf967a86-0de… …eTypePresent Allow NT AUTHORITY… False …ainerInherit InheritOnly
ExtendedRight None 89e95b76-444… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 1131f6aa-9c0… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 1131f6ab-9c0… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 1131f6ae-9c0… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 1131f6ac-9c0… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
…xtendedRight Descendents 91e647de-d96… 00000000-000… …eTypePresent Allow NT AUTHORITY… False …ainerInherit InheritOnly
ExtendedRight None 280f369c-67c… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 05c74c5e-4de… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None ccc2dc7d-a6a… 00000000-000… …eTypePresent Allow NT AUTHORITY… False None None
ExtendedRight None 1131f6ad-9c0… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
ExtendedRight None 1131f6ae-9c0… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
ExtendedRight None 1131f6ac-9c0… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
ExtendedRight None 89e95b76-444… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
ExtendedRight None 1131f6ab-9c0… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
ExtendedRight None 1131f6aa-9c0… 00000000-000… …eTypePresent Allow BUILTINAdmi… False None None
GenericRead Descendents 00000000-000… 4828cc14-143… …eTypePresent Allow BUILTINPre-… False …ainerInherit InheritOnly
GenericRead Descendents 00000000-000… bf967a9c-0de… …eTypePresent Allow BUILTINPre-… False …ainerInherit InheritOnly
GenericRead Descendents 00000000-000… bf967aba-0de… …eTypePresent Allow BUILTINPre-… False …ainerInherit InheritOnly
ExtendedRight None e2a36dc9-ae1… 00000000-000… …eTypePresent Allow BUILTINInco… False None None
ExtendedRight None 1131f6aa-9c0… 00000000-000… …eTypePresent Allow ADDSEnterpr… False None None
ExtendedRight None 1131f6ad-9c0… 00000000-000… …eTypePresent Allow ADDSDomain … False None None
…riteProperty All f30e3bbe-9ff… 00000000-000… …eTypePresent Allow ADDSLink Gr… False …ainerInherit None
…riteProperty All f30e3bbf-9ff… 00000000-000… …eTypePresent Allow ADDSLink Gr… False …ainerInherit None
ExtendedRight All b7b1b3dd-ab0… 00000000-000… …eTypePresent Allow ADDSAllow G… False …ainerInherit None
ExtendedRight All b7b1b3de-ab0… 00000000-000… …eTypePresent Allow ADDSAllow G… False …ainerInherit None
[PS] Scripts:>
[PS] Scripts:>

Unlike the Quest tools, it does no nice formatting. ObjectType and InheritedObjectType are shown as GUIDs. So let’s do some formatting.
I have a separate post “Convert SchemaGUID and / or RightsGUID function” on how to create a (“simple”) function to convert the GUIDs.

[PS] Scripts:> (Get-ADObject -Identity "DC=adds,DC=int" -Properties ntSecurityDescriptor).ntSecurityDescriptor.access | Select @{n="Crtl";e={$_.AccessControlType}}, @{n="Account";e={$_.IdentityReference}}, @{n="Rights";e={$_.ActiveDirectoryRights}}, InheritanceType, @{n="InhObjType";e={Convert-SchemaGUIDtoLDAPDisplayName $_.InheritedObjectType}}, IsInherited, @{n="ObjType";e={Convert-SchemaGUIDtoLDAPDisplayName $_.ObjectType}}, InheritanceFlags, PropagationFlags | ft

Crtl Account Rights InheritanceType InhObjType IsInherited ObjType InheritanceFlags PropagationFlags
—- ——- —— ————— ———- ———– ——- —————- —————-
Deny Everyone DeleteChild None All False All None None
Allow Everyone ReadProperty None All False All None None
Allow NT AUTHORITYE… GenericRead None All False All None None
Allow NT AUTHORITYA… GenericRead None All False All None None
Allow NT AUTHORITYS… GenericAll None All False All None None
Allow BUILTINAdmini… …cl, WriteOwner All All False All ContainerInherit None
Allow BUILTINPre-Wi… ListChildren All All False All ContainerInherit None
Allow BUILTINPre-Wi… …y, ReadControl None All False All None None
Allow ADDSDomain Ad… …cl, WriteOwner None All False All None None
Allow ADDSEnterpris… GenericAll All All False All ContainerInherit None
Allow NT AUTHORITYE… ReadProperty Descendents user False tokenGroups ContainerInherit InheritOnly
Allow NT AUTHORITYE… ReadProperty Descendents group False tokenGroups ContainerInherit InheritOnly
Allow NT AUTHORITYE… ReadProperty Descendents computer False tokenGroups ContainerInherit InheritOnly
Allow NT AUTHORITYE… ExtendedRight None All False Replicating Di… None None
Allow NT AUTHORITYE… ExtendedRight None All False Replicating Di… None None
Allow NT AUTHORITYE… ExtendedRight None All False Replication Sy… None None
Allow NT AUTHORITYE… ExtendedRight None All False Read Only Repl… None None
Allow NT AUTHORITYE… ExtendedRight None All False Manage Replica… None None
Allow NT AUTHORITYSELF … ExtendedRight Descendents All False Private Inform… ContainerInherit InheritOnly
Allow NT AUTHORITYA… ExtendedRight None All False Update Passwor… None None
Allow NT AUTHORITYA… ExtendedRight None All False Enable Per Use… None None
Allow NT AUTHORITYA… ExtendedRight None All False Unexpire Password None None
Allow BUILTINAdmini… ExtendedRight None All False Replicating Di… None None
Allow BUILTINAdmini… ExtendedRight None All False Read Only Repl… None None
Allow BUILTINAdmini… ExtendedRight None All False Manage Replica… None None
Allow BUILTINAdmini… ExtendedRight None All False Replicating Di… None None
Allow BUILTINAdmini… ExtendedRight None All False Replication Sy… None None
Allow BUILTINAdmini… ExtendedRight None All False Replicating Di… None None
Allow BUILTINPre-Wi… GenericRead Descendents inetOrgPerson False All ContainerInherit InheritOnly
Allow BUILTINPre-Wi… GenericRead Descendents group False All ContainerInherit InheritOnly
Allow BUILTINPre-Wi… GenericRead Descendents user False All ContainerInherit InheritOnly
Allow BUILTINIncomi… ExtendedRight None All False Create Inbound… None None
Allow ADDSEnterpris… ExtendedRight None All False Replicating Di… None None
Allow ADDSDomain Co… ExtendedRight None All False Replicating Di… None None
Allow ADDSLink Grou… … WriteProperty All All False gPLink ContainerInherit None
Allow ADDSLink Grou… … WriteProperty All All False gPOptions ContainerInherit None
Allow ADDSAllow Gro… ExtendedRight All All False Generate Resul… ContainerInherit None
Allow ADDSAllow Gro… ExtendedRight All All False Generate Resul… ContainerInherit None
[PS] Scripts:>
[PS] Scripts:>

I used the similar names as the Quest snapin to make it easier to compare the output.
As each single entry requires a lookup in AD, the display is a bit slow. You might want to enhance “Convert-SchemaGUIDtoLDAPDisplayName” to cache the lookups in a hash table.
Finally the DotNet way of doing it. Getting the DACL is not really much different than doing it with Get-ADObject from the MS PowerShell commandlets except getting the object itself.

[PS] Scripts:> ([DirectoryServices.DirectoryEntry]"LDAP://DC=adds,DC=int").psbase.ObjectSecurity.Access

You have to use .psbase to access the underlying .net Object and not the PowerShell representation of it.
The rest is the same as before.
If you want to store the permissions in a text file for backing it up you can use the SDDL representation of it.
Quest

Get-QADObjectSecurity -Identity "dc=adds,dc=int" –SDDL

MS Commandlet

(Get-ADObject -Identity "DC=adds,DC=int" -Properties ntSecurityDescriptor).ntSecurityDescriptor.SDDL

DotNet

([DirectoryServices.DirectoryEntry]"LDAP://DC=adds,DC=int").PSBase.ObjectSecurity.SDDL

If you need more control what to backup (i.e. you don’t want to backup the ownership, just the permissions)

[PS] Scripts:> ([DirectoryServices.DirectoryEntry]"LDAP://DC=adds,DC=int"
).psbase.objectsecurity.GetSecurityDescriptorSddlForm([System.Security.AccessControl.AccessControlSections]::Access)
[PS] Scripts:>
[PS] Scripts:>

BTW. there is an excellent blog about details of parsing SDDL strings. http://blogs.dirteam.com/blogs/jorge/archive/2008/03/26/parsing-sddl-strings.aspx

But how about changing permissions?
This is a new chapter in my blog :-)

Stay Tuned

Patrick Sczepanski ist seit 11 Jahren im Bann der IT Industrie. Er hat schon für Kunden verschiedenster Grössen gearbeitet (von unter 200 bis über 200.000 Mitarbeitern). Bei der redtoo ist er, als Senior Consultant, Experte für den Bereich Infrastructure Services.