Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, January 6, 2016 8:24 PM
Hi. I'm writing a PowerShell script to list AD ACLs for our SQL Servers. (I'm a DBA and don't really understand AD.) I'm hung up on trying to translate a ACL ObjectType GUID into a descriptive text string. For example, f3a64788-5306-11d1-a9c5-0000f80367c1 (Self, ReadProperty, WriteProperty) is both an attribute (Service-Principal-Name) and an extended right (Validated-SPN).
I use 5 lookup hash tables - 3 from extended rights and 2 for classes/attributes. The "Extended-Rights" container in AD uses validAccesses=8 for validated write, validAccesses=48 for property sets, and validAccesses=256 for extended rights. For these, the rightsGUID is what I use for the GUID lookup. The "Schema" container has the class and attribute lookups. For these, I use the schemaGUID for the lookup. The GUIDs are unique most of the time; however, there are a few that exist in more than one table. Here is the code for the lookup hash tables.
$domainNetBiosName = (Get-ADDomain -Server $domainName).NetBIOSName
$domainRoot = Get-ADRootDSE -Server $domainName
# lookup hash tables
$dn_extented = "CN=Extended-Rights,$($domainRoot.configurationNamingContext)"
$lookup_8 = @{}
Get-ADObject -Server $DomainName -SearchBase $dn_extented -Filter 'objectClass -eq "controlAccessRight" -and validAccesses -eq 8' -Properties 'Name', 'displayName', 'rightsGUID' |
%{$lookup_8.Add([System.GUID]$_.rightsGUID, $_.displayName + ' (' + $_.Name + ')')}
$lookup_48 = @{}
Get-ADObject -Server $DomainName -SearchBase $dn_extented -Filter 'objectClass -eq "controlAccessRight" -and validAccesses -eq 48' -Properties 'Name', 'displayName', 'rightsGUID' |
%{$lookup_48.Add([System.GUID]$_.rightsGUID, $_.displayName + ' (' + $_.Name + ')')}
$lookup_256 = @{}
Get-ADObject -Server $DomainName -SearchBase $dn_extented -Filter 'objectClass -eq "controlAccessRight" -and validAccesses -eq 256' -Properties 'Name', 'displayName', 'rightsGUID' |
%{$lookup_256.Add([System.GUID]$_.rightsGUID, $_.displayName + ' (' + $_.Name + ')')}
$dn_schema = $domainRoot.schemaNamingContext
$lookup_class = @{}
Get-ADObject -Server $DomainName -SearchBase $dn_schema -Filter 'objectClass -eq "classSchema"' -Properties 'Name', 'schemaIDGUID' |
%{$lookup_class.Add([System.GUID]$_.schemaIDGUID, $_.Name)}
$lookup_attribute = @{}
Get-ADObject -Server $DomainName -SearchBase $dn_schema -Filter 'objectClass -eq "attributeSchema"' -Properties 'Name', 'schemaIDGUID' |
%{$lookup_attribute.Add([System.GUID]$_.schemaIDGUID, $_.Name)}
I have code that gets the SQL OU, builds a list of a few computers in the OU, and then gets the ACL for each. (I don't use GET-ACL because it has a bug when the distinguished name has a colon in it.)
$sql_OU = Get-ADOrganizationalUnit -Server $domainName -Filter 'name -like "SQL*"' |
Select-Object -ExpandProperty DistinguishedName
$computers = Get-ADObject -Server $domainName -SearchBase $sql_OU -SearchScope Subtree -Filter 'objectClass -eq "computer"' |
Select-Object -ExpandProperty DistinguishedName
$computers = $computers | Sort-Object | Select-Object -first 5 # Order the objects by dn
# Get the access for each object
ForEach ($computer in $computers) {
$access = Get-ADObject -Server $domainName -Identity $computer -Properties 'ntSecurityDescriptor' |
Select-Object -ExpandProperty ntSecurityDescriptor |
Select-Object -ExpandProperty Access
$accesses += ($access |
%{new-object -TypeName PSObject -Property (@{
'DomainName'=$domainName;
'DomainNetBiosName'=$domainNetBiosName;
'OrganizationalUnit'=$sql_OU;
'ObjectType'=$_.ObjectType;
'InheritedObjectType'=$_.InheritedObjectType;
'IdentityReference'=$_.IdentityReference;
'ActiveDirectoryRights'=$_.ActiveDirectoryRights;
'InheritanceType'=$_.InheritanceType;
'AccessControlType'=$_.AccessControlType;
'IsInherited'=$_.IsInherited;
'InheritanceFlags'=$_.InheritanceFlags;
'PropagationFlags'=$_.PropagationFlags;
'ObjectFlags'=$_.ObjectFlags;
'ObjectTypeName'=$(Get-AccessObjectTypeName -Access $_);
})})
}
The code in the Get-AccessObjectTypeName is experimental. I try to determine if a lookup table is appropriate based on the rights. At this point, I get all matching values. If there is more than one that applies, I don't really know how to pick the right one. Is there a priority order?
function Get-AccessObjectTypeName {
param(
[parameter(mandatory=$true)][System.DirectoryServices.ActiveDirectoryAccessRule]$Access
)
# ExtendedRight: validAccesses attribute to equal the ADS_RIGHT_DS_CONTROL_ACCESS (256)
# Note: [System.DirectoryServices.ActiveDirectoryRights] 256 returns "ExtendedRight"
# PropertySet: validAccesses attribute to equal ACTR_DS_READ_PROP (16) and ACTRL_DS_WRITE_PROP (32) or 48 total.
# Note: [System.DirectoryServices.ActiveDirectoryRights] 16 returns "ReadProperty"
# Note: [System.DirectoryServices.ActiveDirectoryRights] 32 returns "WriteProperty"
# ValidatedWrite: validAccesses attribute to equal ADS_RIGHT_DS_SELF (8).
# Note: [System.DirectoryServices.ActiveDirectoryRights] 8 returns "Self"
# The types of rights determines the locations to lookup the GUID.
$ActiveDirectoryRights = $Access.ActiveDirectoryRights
$ObjectFlags = $Access.ObjectFlags
$isClass = $ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::CreateChild) -or
$ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::DeleteChild)
$isAttribute = $ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::ReadProperty) -or
$ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::WriteProperty);
$isPropertySet = $isAttribute
$isExtended = $ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight);
$isValidated = $ActiveDirectoryRights.HasFlag([System.DirectoryServices.ActiveDirectoryRights]::Self);
$isObjectAceTypePresent = $ObjectFlags.HasFlag([System.Security.AccessControl.ObjectAceFlags]::ObjectAceTypePresent);
if (-not $isObjectAceTypePresent) { # e.g., empty GUID with all 0's
$name = 'ALL'
} else {
$guid = $Access.ObjectType
$count = 0
if ($isExtended) {$extended = $script:lookup_256.Item($guid); if ($extended) {$count++; $name=$extended}} else {$extended = $null}
if ($isPropertySet) {$propertySet = $script:lookup_48.Item($guid); if ($propertySet) {$count++; $name=$propertySet}} else {$propertySet = $null}
if ($isAttribute) {$attribute = $script:lookup_attribute.Item($guid); if ($attribute) {$count++; $name=$attribute}} else {$attribute = $null}
if ($isClass) {$class = $script:lookup_class.Item($guid); if ($class) {$count++; $name=$class}} else {$class = $null}
if ($isValidated) {$validated = $script:lookup_8.Item($guid); if ($validated) {$count++; $name=$validated}} else {$validated = $null}
if ($count -eq 0) {
write-host ($guid.GUID + " ($ActiveDirectoryRights): no matches")
} elseif ($count -gt 1) {
write-host ($guid.GUID + " ($ActiveDirectoryRights): multiple matches $class`;$attribute`;$propertySet`;$extended`;$validated")
}
} return $name
}
If there a priority order to the lookups, then I can use elseif to stop at the first match found.
Randy in Marin
All replies (10)
Friday, January 8, 2016 2:50 AM
Hi Randy,
Since this query is more related to PowerShell, I will move this thread into PowerShell forum so that you would get more efficient support.
Best Regards,
Amy
Please remember to mark the replies as answers if they help and un-mark them if they provide no help. If you have feedback for TechNet Subscriber Support, contact [email protected].
Friday, January 8, 2016 6:37 AM
You are asking a very vague and broad set of questions. Please ry to ask a single and specific question. This forum cannot help you with broad design issues. The forum is not a free consulting service but is geared to assistance with fundamental question of how to write a script or how to address a script error.
Please try to ask a clear and specific question.
\(ツ)_/
Friday, January 8, 2016 6:56 AM
I ran your code but still cannot focus on what you are asking. You need to simplify and provide a clear example. I/We could figure it out but who wants to spend time trying to decode what you are doing.
Maybe a better question is - Why do you want to do this?
\(ツ)_/
Friday, January 8, 2016 3:11 PM
fyi you have many typos. 'entented' so your variables won't return anything.
You don't need a hash table and you can put all of them in one and then do what you want with the validaccesses number.
$perms = Get-ADObject -Server $DomainName -SearchBase $dn_extended -Filter "objectClass -eq 'controlAccessRight'" -Properties Name,displayName,rightsGUID,validaccesses
That said, I'm with JRV. This isn't very practical at all. Set your permissions on the ou as you would like and forget it.
Dan
Friday, January 8, 2016 5:42 PM
I should have left the PowerShell script out. Here's a shorter version. GET-ACL returns GUIDs for some values. For example,
ActiveDirectoryRights : WriteProperty
InheritanceType : All
ObjectType : ea1b7b93-5e48-46d5-bc6c-4df4fda78a35
InheritedObjectType : bf967a86-0de6-11d0-a285-00aa003049e2
ObjectFlags : ObjectAceTypePresent, InheritedObjectAceTypePresent
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SELF
IsInherited : True
InheritanceFlags : ContainerInherit
PropagationFlags : None
I'm trying to translate the ObjectType and InheritedObjectType. In addition, I want to translate the ActiveDirectoryRights into individual permissions.
Manually, I use "Active Directory Computers and User", select the computer of interest, properties, security tab, advanced, look at SELF (more than one), click view, and check the Object/Properties tabs for permissions. I don't want to do this manually every month for a 100 servers, so I'm trying to script this. If there is a reference to help me understand how to create such a report, I would appreciate it. I don't know enough about AD to know how I should do this.
Randy in Marin
Friday, January 8, 2016 6:07 PM
Sorry about the typos. I only have read access to AD. As a DBA, I've been bitten by missing "mysterious" permissions enough times that I want to monitor them. We have several domains and a special OU in each for most SQL Servers. Most recently, we have had SSRS issues related to NTLM vs KERBEROS dues to a lack of SPN rights on some servers. I want to be proactive to insure the right permissions are in place and stay in place. I don't want to do this manually or assign the task to a busy staff.
I suppose I could skip understanding the GUIDs and look only for changes, not understanding what changed. If any change occurs, then a manual inspect would be called for to insure required rights are in place.
I will open a new very short question re monitoring permissions.
Randy in Marin
Friday, January 8, 2016 6:32 PM
Amy, I really was asking about AD, but using PSH as an example. I asked a new question, but did not realize the move. So, now my AD question is in the PSH forum. Would you take a look and see if it should be moved?
Thanks
Randy in Marin
Friday, January 8, 2016 7:04 PM
translate them to what?
Dan
Friday, January 8, 2016 7:45 PM
I would like to translate the GUIDs to "friendly" names. For example, I think the ObjectType GUID is either an extended right rightsGUID or a schema schemaIDGuid. However, the values of rightsGUID and schemaIDGUID are not always unique by design. So, if I happen to have a an ObjectType GUID that is not unique, which rightsGUID or schemaIDGUID do I use?
Here is a list all the duplicates in one of our domains - see script further below. There are not that many. If my ObjectType GUID happens to be the first one listed, I have three choices. I think the one I pick will depend upon the rights assigned. If the rights include "Self", then perhaps the one with validAccesses=8 is always the correct choice. Otherwise, if both "ReadAttribute" and "Writeattribute" are in the rights, then perhaps I should pick the property set validAccesses=48 if one exists; otherwise, it's a schemaIDGUID?
GUID Name objectClass validAccess
72e39547-7b18-11d1-adef-00c04fd8d5cd DNS-Host-Name attributeSchema
72e39547-7b18-11d1-adef-00c04fd8d5cd DNS-Host-Name-Attributes controlAccessRight 48
72e39547-7b18-11d1-adef-00c04fd8d5cd Validated-DNS-Host-Name controlAccessRight 8
80863791-dbe9-4eb8-837e-7f0ab55d9ac7 ms-DS-Additional-Dns-Host-Name attributeSchema
80863791-dbe9-4eb8-837e-7f0ab55d9ac7 Validated-MS-DS-Additional-DNS-Host-Name controlAccessRight 8
bf9679c0-0de6-11d0-a285-00aa003049e2 Member attributeSchema
bf9679c0-0de6-11d0-a285-00aa003049e2 Self-Membership controlAccessRight 8
d31a8757-2447-4545-8081-3bb610cacbf2 ms-DS-Behavior-Version attributeSchema
d31a8757-2447-4545-8081-3bb610cacbf2 Validated-MS-DS-Behavior-Version controlAccessRight 8
f3a64788-5306-11d1-a9c5-0000f80367c1 Service-Principal-Name attributeSchema
f3a64788-5306-11d1-a9c5-0000f80367c1 Validated-SPN controlAccessRight 8
Here is a script that you might be able to run to see the same or similar results.
$DomainName = 'ourdomainname'
$domain = Get-ADDomain -Server $DomainName
$root = Get-ADRootDSE -Server $DomainName
$dn_extented = "CN=Extended-Rights,$($root.configurationNamingContext)"
$dn_schema = $root.schemaNamingContext
$raw_extended = Get-ADObject -Server $DomainName -SearchBase $dn_extented -Filter 'objectClass -eq "controlAccessRight"' -Properties 'Name', 'validAccesses', 'rightsGUID', 'objectClass' |
%{new-object -TypeName PSObject -Property (@{
'GUID'=[System.Guid]$_.rightsGUID;
'Name'=$_.Name;
'objectClass'=$_.objectClass;
'validAccess'=$_.validAccesses;
})}
$raw_schema = Get-ADObject -Server $DomainName -SearchBase $dn_schema -Filter 'schemaIDGUID -like "*"' -Properties 'Name', 'schemaIDGUID', 'objectClass' |
%{new-object -TypeName PSObject -Property (@{
'GUID'=[System.Guid]$_.schemaIDGUID;
'Name'=$_.Name;
'objectClass'=$_.objectClass;
'validAccess'=$null;
})}
$raw_all = $raw_extended + $raw_schema
$raw_all_duplicate_GUIDs = $raw_all | group -Property GUID | ?{$_.Count -gt 1} | select -ExpandProperty Name
$raw_all_duplicates = $raw_all | ?{$raw_all_duplicate_GUIDs -icontains $_.GUID}
$raw_all_duplicates | sort -Property GUID, Name | ft GUID, Name, objectClass, validAccess -AutoSize
Randy in Marin
Monday, January 11, 2016 8:34 AM
Hi Randy,
The thread you mentiond ablove has been moved to the Active Directory Service Forum now.
Best Regards,
Elaine
Please remember to mark the replies as answers if they help and unmark them if they provide no help. If you have feedback for TechNet Subscriber Support, contact [email protected].