ScriptBlocks/DryAD_SB_ADAccessRule_Set.ps1
# DryActiveDirectory is an AD config module for use with DryDeploy, or by itself. # # Copyright (C) 2021 Bjørn Henrik Formo (bjornhenrikformo@gmail.com) # LICENSE: https://raw.githubusercontent.com/bjoernf73/DryActiveDirectory/main/LICENSE # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. [ScriptBlock]$DryAD_SB_ADAccessRule_Set = { Param ( [String] $Path, [String] $TargetName, [String] $TargetType, [System.DirectoryServices.ActiveDirectoryRights[]] $ActiveDirectoryRights, [System.Security.AccessControl.AccessControlType] $AccessControlType, [String] $ObjectType, [String] $InheritedObjectType, [String] $ActiveDirectorySecurityInheritance, [String] $ExecutionType, [String] $Server ) Try { $ReturnError = $Null $ReturnValue = $False $DebugReturnStrings = @("Entered Scriptblock") $DebugReturnStrings += @("'Path' = '$Path'") $DebugReturnStrings += @("'TargetName' = '$TargetName'") $DebugReturnStrings += @("'TargetType' = '$TargetType'") $DebugReturnStrings += @("'ActiveDirectoryRights' = '$ActiveDirectoryRights'") $DebugReturnStrings += @("'AccessControlType' = '$AccessControlType'") $DebugReturnStrings += @("'ObjectType' = '$ObjectType'") $DebugReturnStrings += @("'InheritedObjectType' = '$InheritedObjectType'") $DebugReturnStrings += @("'ActiveDirectorySecurityInheritance' = '$ActiveDirectorySecurityInheritance'") $DebugReturnStrings += @("'ExecutionType' = '$ExecutionType'") $DebugReturnStrings += @("'Server' = '$Server'") # Remove any blank optional parameter value to ensure correct constructor of System.DirectoryServices.ActiveDirectoryAccessRule If ($ObjectType -eq '') { $DebugReturnStrings += "Removing 'ObjectType' (it is blank)" Remove-Variable -name ObjectType } If ($InheritedObjectType -eq '') { $DebugReturnStrings += "Removing 'InheritedObjectType' (it is blank)" Remove-Variable -name InheritedObjectType } If ($ActiveDirectorySecurityInheritance -eq '') { $DebugReturnStrings += "Removing 'ActiveDirectorySecurityInheritance' (it is blank)" Remove-Variable -Name ActiveDirectorySecurityInheritance } # Make sure ActiveDirectory module is loaded, so the AD drive is mounted If ((Get-Module | Select-Object -Property Name).Name -notcontains 'ActiveDirectory') { Try { Import-Module -Name 'ActiveDirectory' -ErrorAction Stop $DebugReturnStrings += @("The AD PSModule was not loaded, but I loaded it successfully") Start-Sleep -Seconds 4 } Catch { $PSCmdlet.ThrowTerminatingError($_) } } Else { $DebugReturnStrings += @("The AD PSModule was already loaded in session") } # However, that is not necessarily the case. That ActiveDirectory module is a bit sloppy Try { Get-PSDrive -Name 'AD' -ErrorAction Stop | Out-Null $DebugReturnStrings += @("The AD Drive exists already") } Catch [System.Management.Automation.DriveNotFoundException] { $DebugReturnStrings += @("The AD Drive does not exist - trying to create it") Try { $NewPSDriveParams = @{ Name = 'AD' PSProvider = 'ActiveDirectory' Root = '//RootDSE/' ErrorAction = 'Stop' } New-PSDrive @NewPSDriveParams | Out-Null } Catch { $DebugReturnStrings += @("Failed to create the AD Drive: $($_.ToString())") $PSCmdlet.ThrowTerminatingError($_) } } Catch { $DebugReturnStrings += @("The AD Drive did not exist, and an error occurred trying to get it?") $PSCmdlet.ThrowTerminatingError($_) } # Make sure the AD-drive is connected to $Server. This ensures that Set-ACL operates on a Domain Controller # that have the OUs, groups, users or any other AD object that the configuration set creates and configures, # without the need for a full AD replication to have happened $ADDrive = Get-PSDrive -Name 'AD' -ErrorAction Stop $ADDrive.Server = "$Server" $RootDSE = Get-ADRootDSE -ErrorAction Stop $DomainDN = $RootDSE.defaultNamingContext # Create a hashtable to store the GUID value of each schema class and attribute $ObjectTypeGUIDs = @{} Get-ADObject -SearchBase ($RootDSE.SchemaNamingContext) -LDAPFilter "(schemaidguid=*)" -Properties lDAPDisplayName,schemaIDGUID -ErrorAction Stop | ForEach-Object { $ObjectTypeGUIDs[$_.lDAPDisplayName]=[System.GUID]$_.schemaIDGUID } $ObjectTypeGUIDs['All'] = [GUID]::Empty $DebugReturnStrings += "Success getting ObjectTypeGUIDs" # Create a hashtable to store the GUID value of each extended right in the forest $ExtendedRightsMap = @{} Get-ADObject -SearchBase ($RootDSE.ConfigurationNamingContext) -LDAPFilter "(&(objectclass=controlAccessRight)(rightsguid=*))" -Properties displayName,rightsGuid -ErrorAction Stop | ForEach-Object { $ExtendedRightsMap[$_.displayName]=[System.GUID]$_.rightsGuid } $DebugReturnStrings += "Success getting ExtendedRightsMap" # Add Domain dN to $Path if it is missing If ($Path -notmatch "$DomainDN$") { $Path = $Path + ",$DomainDN" } $PathObject = Get-ADObject -Identity $Path -ErrorAction Stop $DebugReturnStrings += "PathObject: $($PathObject.distinguishedName)" # Get the object to deletegate rights to Switch ($TargetType) { 'group' { $ADGroup = Get-ADGroup -Identity $TargetName -ErrorAction Stop -Properties SID [System.Security.Principal.IdentityReference]$Target = $ADGroup.SID } 'user' { $ADUser = Get-ADUser -Identity $User -ErrorAction Stop -Properties SID [System.Security.Principal.IdentityReference]$Target = $ADUser.SID } } $DebugReturnStrings += "SID of the Target: $Target" $ObjectTypeGUID = $Null If ($ObjectType) { $DebugReturnStrings += "Finding GUID of ObjectType: '$ObjectType'" $ObjectTypeGUID = [GUID]($ObjectTypeGUIDs.$($ObjectType)) $DebugReturnStrings += "ObjectTypeGUID: $($ObjectTypeGUID.ToString())" } $InheritedObjectTypeGUID = $Null If ($InheritedObjectType) { $DebugReturnStrings += "Finding GUID of InheritedObjectType: '$InheritedObjectType'" $InheritedObjectTypeGUID = [GUID]($ObjectTypeGUIDs.$($InheritedObjectType)) $DebugReturnStrings += "InheritedObjectTypeGUID: $($InheritedObjectTypeGUID.ToString())" } ForEach ($ActiveDirectoryRight in $ActiveDirectoryRights) { $DebugReturnStrings += "Setting ACL for right: '$ActiveDirectoryRight'" # Current ACL $ACL = Get-ACL -Path "AD:\$($PathObject.DistinguishedName)" -ErrorAction Stop $DebugReturnStrings += "Success getting current ACL" $AccessRule = $null # If $ActiveDirectoryRight is an Extended Right, then $ActiveDirectoryRight becomes "ExtendedRight", # the GUID of the original right becomes the $ObjectTypeGuid, and GUID of $ObjectType becomes $InheritedObjectTypeGuid If ($ExtendedRightsMap.ContainsKey($ActiveDirectoryRight)) { $DebugReturnStrings += "'$ActiveDirectoryRight' is an Extended Right" $InheritedObjectTypeGuid = $ObjectTypeGUID $ObjectTypeGuid = $ExtendedRightsMap.$($ActiveDirectoryRight) $ActiveDirectoryRight = "ExtendedRight" } Else { $DebugReturnStrings += "'$ActiveDirectoryRight' is a Standard Right" } # Convert to proper types If ($Null -ne $ActiveDirectorySecurityInheritance) { [System.DirectoryServices.ActiveDirectorySecurityInheritance]$ActiveDirectorySecurityInheritance = $ActiveDirectorySecurityInheritance } # Now we're able to find the constructor If ( ($Null -eq $ActiveDirectorySecurityInheritance) -and ($Null -eq $ObjectTypeGUID) -and ($Null -eq $InheritedObjectTypeGUID) ) { $DebugReturnStrings += "Constructor: 1 (Target, ActiveDirectoryRight, AccessControlType)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType) -ErrorAction Stop } ElseIf ( ($Null -ne $ActiveDirectorySecurityInheritance) -and ($Null -eq $ObjectTypeGUID) -and ($Null -eq $InheritedObjectTypeGUID) ) { $DebugReturnStrings += "Constructor: 2 (Target, ActiveDirectoryRight, AccessControlType, ActiveDirectorySecurityInheritance)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType, $ActiveDirectorySecurityInheritance) -ErrorAction Stop } ElseIf ( ($Null -ne $ActiveDirectorySecurityInheritance) -and ($Null -eq $ObjectTypeGUID) -and ($Null -ne $InheritedObjectTypeGUID) ) { $DebugReturnStrings += "Constructor: 3 (Target, ActiveDirectoryRight, AccessControlType, ActiveDirectorySecurityInheritance, InheritedObjectTypeGUID)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType, $ActiveDirectorySecurityInheritance, $InheritedObjectTypeGUID) -ErrorAction Stop } ElseIf ( ($Null -eq $ActiveDirectorySecurityInheritance) -and ($Null -ne $ObjectTypeGUID) -and ($Null -eq $InheritedObjectTypeGUID) ) { $DebugReturnStrings += "Constructor: 4 (Target, ActiveDirectoryRight, AccessControlType, ObjectTypeGuid)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType, $ObjectTypeGuid) -ErrorAction Stop } ElseIf ( ($Null -ne $ActiveDirectorySecurityInheritance) -and ($Null -ne $ObjectTypeGUID) -and ($Null -eq $InheritedObjectTypeGUID) ) { $DebugReturnStrings += "Constructor: 5 (Target, ActiveDirectoryRight, AccessControlType, ObjectTypeGuid, ActiveDirectorySecurityInheritance)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType, $ObjectTypeGuid, $ActiveDirectorySecurityInheritance) -ErrorAction Stop } ElseIf ( ($Null -ne $ActiveDirectorySecurityInheritance) -and ($Null -ne $ObjectTypeGUID) -and ($Null -ne $InheritedObjectTypeGUID)) { #Type = 6 $DebugReturnStrings += "Constructor: 6 (Target, ActiveDirectoryRight, AccessControlType, ObjectTypeGuid, ActiveDirectorySecurityInheritance, InheritedObjectTypeGUID)" $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Target, $ActiveDirectoryRight, $AccessControlType, $ObjectTypeGuid, $ActiveDirectorySecurityInheritance, $InheritedObjectTypeGUID) -ErrorAction Stop } Else { Throw "Unable to determine constructor" } Try { # Add the AccessRule to the existing ACL $DebugReturnStrings += "Trying to add ACE to current ACL" $ACL.AddAccessRule($AccessRule) $DebugReturnStrings += "Successfully added ACE to current ACL" # Submitting the changes $DebugReturnStrings += "Trying to submit (Set-ACL) the modified ACL" Set-ACL -ACLObject $ACL -Path ("AD:\$($PathObject.DistinguishedName)") -ErrorAction Stop $DebugReturnStrings += "Successfully submitted the ACL!" } Catch { $PSCmdlet.ThrowTerminatingError($_) } } # If we reached this, assume success $ReturnValue = $True Return @($DebugReturnStrings,$ReturnValue,$ReturnError) } Catch { $DebugReturnStrings += "Set-DryADAccessRule failed" $ReturnError = $_ Return @($DebugReturnStrings,$ReturnValue,$ReturnError) } Finally { # should probably remove a bunch of stuff here } } |