ACLHelpers.psm1
Set-StrictMode -Version Latest Enum RuleCompareResult { Same Child Parent Different } Function Compare-Rule { # Sould handle all types https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.accessrule(v=vs.110).aspx #region Params [CmdletBinding(DefaultParameterSetName)] Param ( [Parameter(Mandatory=$true,Position =0)] [System.Security.AccessControl.AccessRule]$Rule1, [Parameter(Mandatory=$true,Position =1)] [System.Security.AccessControl.AccessRule]$Rule2 ) #endregion if($Rule1.GetType() -eq $Rule2.GetType() -and $Rule1.IdentityReference.Value -eq $Rule2.IdentityReference.Value -and $Rule1.AccessControlType -eq $Rule2.AccessControlType -and $Rule1.InheritanceFlags -eq $Rule2.InheritanceFlags -and $Rule1.PropagationFlags -eq $Rule2.PropagationFlags -and $Rule1.IsInherited -eq $Rule2.IsInherited) { if($Rule1.GetType() -eq [System.Security.AccessControl.FileSystemAccessRule]) { if($Rule1.FileSystemRights -eq $Rule2.FileSystemRights) { return [RuleCompareResult]::Same } else { return [RuleCompareResult]::Different } } elseif($Rule1.GetType() -eq [System.Security.AccessControl.RegistryAccessRule]) { if($Rule1.RegistryRights -eq $Rule2.RegistryRights) { return [RuleCompareResult]::Same } else { return [RuleCompareResult]::Different } } return [RuleCompareResult]::Different } else { return [RuleCompareResult]::Different } } Function Parse-Enum { [CmdletBinding()] Param ( [Parameter(Mandatory=$true,Position =0)] [string[]]$TextInput, [Parameter(Mandatory=$true,Position =1)] $DesiredEnum ) $results = ,@{} $results.clear() foreach($string in $TextInput) { $Result = $string -as $DesiredEnum if($Result -eq $null) { $options = $DesiredEnum.GetEnumNames() -join ", " throw "[$string] is not a recognized [$DesiredEnum] value. Allowed options are as follows:`r{$options}" } else { $results += $Result } } $results = $results -ne $null if($results.Count -eq 1) { return $results[0] } return $results } <# .SYNOPSIS Adds ACL Entries to Objects. .DESCRIPTION Used to simplify ACL setting work. Allows for more natural syntax .PARAMETER Path Changes the security descriptor of the specified item. Enter the path to an item, such as a path to a file or registry key. .PARAMETER Principal The user/group principal to be used. .PARAMETER Rights The permission(s) the should be used. .PARAMETER Rules Pre-set rule(s) that inherits from [System.Security.AccessControl.AccessRule]. .PARAMETER PropagationFlags Specifies how Access Control Entries (ACEs) are propagated to child objects. These flags are significant only if inheritance flags are present. .PARAMETER InheritanceFlags Inheritance flags specify the semantics of inheritance for access control entries (ACEs). .PARAMETER Inherit Should the permission be viewed as inherited by child objects. .PARAMETER Allow Represents an Allow permission. .PARAMETER Deny Represents an Deny permission overrides -Allow. .EXAMPLE Add-Acl -Path "c:\temp" -Principal "UserName" -Rights "Read" Update Folder ACL by username .EXAMPLE Add-Acl "HKCU:\Test" $StrSID "ReadKey" Update Registry ACL by username .NOTES #> Function Add-Acl { #region Params [CmdletBinding(DefaultParameterSetName='ByRights')] Param ( [Parameter(Mandatory=$true,Position=0,ValueFromPipeline)] [Parameter(ParameterSetName = 'ByRules')] [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(Mandatory=$true, Position=1,ParameterSetName = 'ByRules')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.AccessRule[]]$Rules, [Parameter(Mandatory=$true, Position=1,ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] $Principal, [Parameter(Mandatory=$true, Position=2,ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [array]$Rights, #[Parameter(HelpUri='https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags(v=vs.110).aspx')] [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.PropagationFlags] $PropagationFlags = "None", #[Parameter(HelpUri="https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.inheritanceflags(v=vs.110).aspx")] [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags = "ContainerInherit, ObjectInherit", [Parameter(ParameterSetName = 'ByRights')] [bool] $Inherit = $true, [Parameter(ParameterSetName = 'ByRights')] [switch] $Allow = $true, [Parameter(ParameterSetName = 'ByRights')] [switch] $Deny ) #endregion Begin { $ErrorActionPreference = "Stop" if($Allow) { $ActionVerb ="Allow" } if($Deny) { $Allow = $false $ActionVerb ="Deny" } if($Principal -is [System.String] -and $Principal -notmatch "\\") { $Principal = "$env:computername\$Principal" } } Process { $ErrorActionPreference = "Stop" foreach($item in $Path) { if(-not (Test-Path $item)) { Throw "Path [$item] not found" continue; } $Found = $false $HasWork = $false $Acl = Get-Acl $item $Ar=$null $List=$Rules if($Rights) { if($Rights.count -eq 1 -and $Rights[0].GetType() -eq [string]) { $List= $Rights[0].Split(",") } else { $List = $Rights } } foreach ($i in $List) { if($i.GetType() -eq $Acl.AccessRuleType) { $Ar= $i } else { $right = Parse-Enum $i $Acl.AccessRightType if($Inherit) { $Ar = New-Object ($Acl.AccessRuleType)($Principal, $right, $InheritanceFlags, $PropagationFlags, $ActionVerb) } else { $Ar = New-Object ($Acl.AccessRuleType)($Principal, $right, $ActionVerb) } } if($Ar) { $HasWork = $true $Acl.AddAccessRule($Ar) } } if($HasWork) { Set-Acl $item $Acl } } } } Set-Alias aacl Add-Acl <# .SYNOPSIS Removes ACL Entries to Objects. .DESCRIPTION Used to simplify ACL removing work. Allows for more natural syntax .PARAMETER Path Changes the security descriptor of the specified item. Enter the path to an item, such as a path to a file or registry key. .PARAMETER Principal The user/group principal to be used. .PARAMETER Rights The permission(s) the should be used. .PARAMETER PropagationFlags Specifies how Access Control Entries (ACEs) are propagated to child objects. These flags are significant only if inheritance flags are present. .PARAMETER InheritanceFlags Inheritance flags specify the semantics of inheritance for access control entries (ACEs). .PARAMETER Inherit Should the permission be viewed as inherited by child objects. .PARAMETER Allow Represents an Allow permission. .PARAMETER Deny Represents an Deny permission. .EXAMPLE Add-Acl -Path "c:\temp" -Principal "UserName" -Rights "Read" Update Folder ACL by username .EXAMPLE Add-Acl "HKCU:\Test" $StrSID "ReadKey" Update Registry ACL by username .NOTES #> Function Remove-Acl { #region Params [CmdletBinding(DefaultParameterSetName='ByRights')] Param ( [Parameter(Mandatory=$true,Position=0,ValueFromPipeline)] [Parameter(ParameterSetName = 'ByRules')] [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(Mandatory=$true, Position=1,ParameterSetName = 'ByRules')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.AccessRule[]]$Rules, [Parameter(Mandatory=$true, Position=1,ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] $Principal, [Parameter(Mandatory=$true, Position=2,ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [array]$Rights, [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.PropagationFlags] $PropagationFlags = "None", #[Parameter(HelpUri="https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.inheritanceflags(v=vs.110).aspx")] [Parameter(ParameterSetName = 'ByRights')] [ValidateNotNullOrEmpty()] [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags = "ContainerInherit, ObjectInherit", [Parameter(ParameterSetName = 'ByRights')] [bool] $Inherit = $true, [Parameter(ParameterSetName = 'ByRights')] [switch] $Allow = $true, [Parameter(ParameterSetName = 'ByRights')] [switch] $Deny ) #endregion Begin { $ErrorActionPreference = "Stop" if($Allow) { $ActionVerb ="Allow" } if($Deny) { $Allow = $false $ActionVerb ="Deny" } $ErrorActionPreference = "Continue" if($Principal -is [System.Security.Principal.SecurityIdentifier]) { try { $Principal = $Principal.Translate([System.Security.Principal.NTAccount]).Value # | select Name } catch [Security.Principal.IdentityNotMappedException] { Write-Warning "Can't Translate $Principal" } } elseif($Principal -is [System.String] -and $Principal -notmatch "\\") { $Principal = "$env:computername\$Principal" } } Process { foreach($item in $Path) { if(-not (Test-Path $item)) { Throw "Path [$item] not found" continue; } $HasWork = $false $Acl = Get-Acl $item $List=$Rules if($PSCmdlet.ParameterSetName -eq 'ByRights') { if($Rights.count -eq 1 -and $Rights[0].GetType() -eq [string]) { $List= $Rights[0].Split(",") } else { $List = $Rights } foreach ($rule in $Acl.Access | Where-Object {$_.IdentityReference.Value -eq $Principal -and $_.AccessControlType -eq $ActionVerb -and $_.InheritanceFlags -eq $InheritanceFlags -and $_.PropagationFlags -eq $PropagationFlags}) { $CurrentRightType=$Acl.AccessRightType $CurrentRights=$rule.($CurrentRightType.Name) $NewRights = $CurrentRights foreach($i in $List) { $right = parse-enum $i $CurrentRightType if($CurrentRights -band $i) { $NewRights = $NewRights - $I $HasWork = $true } } if($HasWork) { $acl.RemoveAccessRule($rule) | Out-Null if($NewRights -gt 0 -and $NewRights -ne "Synchronize") { $NewRule = New-Object ($Acl.AccessRuleType)($rule.IdentityReference, $NewRights, $rule.InheritanceFlags, $rule.PropagationFlags, $rule.AccessControlType) $Acl.AddAccessRule($NewRule) | Out-Null } } } } elseif($PSCmdlet.ParameterSetName -eq 'ByRules') { foreach($ProvidedRule in $List) { foreach ($rule in $Acl.Access | Where-Object { (Compare-Rule $_ $ProvidedRule) -eq [RuleCompareResult]::Same}) { $acl.RemoveAccessRule($rule) | Out-Null $HasWork = $true } } } if($HasWork) {Set-Acl $item $Acl } else { if($PSCmdlet.ParameterSetName -eq 'ByRights') { Write-Warning "[$Principal] dosent have [$ActionVerb] [$Rights] access on [$item]" } elseif($PSCmdlet.ParameterSetName -eq 'ByRules') { Write-Warning "Provided rule not found on [$item]" } } } } } Set-Alias racl Remove-Acl <# .SYNOPSIS Checks ACL Entries to Objects. .DESCRIPTION Used to simplify checking ACL settings. Allows for more natural syntax .PARAMETER Path Changes the security descriptor of the specified item. Enter the path to an item, such as a path to a file or registry key. .PARAMETER Principal The user/group principal to be used. .PARAMETER Rights The permission(s) the should be used. .PARAMETER PropagationFlags Specifies how Access Control Entries (ACEs) are propagated to child objects. These flags are significant only if inheritance flags are present. .PARAMETER InheritanceFlags Inheritance flags specify the semantics of inheritance for access control entries (ACEs). .PARAMETER Inherit Should the permission be viewed as inherited by child objects. .PARAMETER Allow Represents an Allow permission. .PARAMETER Deny Represents an Deny permission. .EXAMPLE Test-Acl -Path "c:\temp" -Principal "UserName" -Rights "Read" Update Folder ACL by username .EXAMPLE Test-Acl "HKCU:\Test" $StrSID "ReadKey" Update Registry ACL by username .NOTES #> Function Test-Acl { #region Params [CmdletBinding()] Param ( [Parameter(Mandatory=$true,Position=0,ValueFromPipeline)] [ValidateNotNullOrEmpty()] $Path, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] $Principal, [Parameter(Mandatory=$true, Position=2)] [ValidateNotNullOrEmpty()] $Rights, [ValidateNotNullOrEmpty()] [System.Security.AccessControl.PropagationFlags] $PropagationFlags = "None", [ValidateNotNullOrEmpty()] [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags = "ContainerInherit, ObjectInherit", [bool] $Inherit = $true, [switch] $Allow = $true, [switch] $Deny ) #endregion Begin { $ErrorActionPreference = "Stop" if($Allow) { $ActionVerb ="Allow" } if($Deny) { $Allow = $false $ActionVerb ="Deny" } if($Principal -is [System.String] -and $Principal -notmatch "\\") { $Principal = "$env:computername\$Principal" } $Results = ,@{} } Process { $ErrorActionPreference = "STOP" foreach($item in $Path) { $HasWork = $false $Acl =$item | Get-Acl $Any = $false foreach ($rule in $Acl.Access | Where-Object {$_.IdentityReference.Value -eq $Principal }) { $ExistingPermission =$rule.($Acl.AccessRightType.Name) Parse-Enum $Rights $Acl.AccessRightType | Out-Null $CheckingPermission = $Rights -as $Acl.AccessRightType if($ExistingPermission -band $CheckingPermission) { $Any = $true $Results += New-Object �TypeName PSObject �Prop (@{'Path'=$item; 'Result'=$true;}) break } } if($Any -eq $false) { $Results += New-Object �TypeName PSObject �Prop (@{'Path'=$item; 'Result'=$false;}) } } } End { return $Results | Format-Table } } Set-Alias tacl Test-Acl <# .SYNOPSIS Checks ACL Entries to Objects. .DESCRIPTION Used to simplify checking ACL settings. Allows for more natural syntax .PARAMETER Path Changes the security descriptor of the specified item. Enter the path to an item, such as a path to a file or registry key. .PARAMETER Principal The user/group principal to be used as master set. .PARAMETER DestinationPrincipal The user/group principal to be coped to. .EXAMPLE Copy-Acl -Path "c:\temp" -Principal "User1" -DestinationPrincipal "User2" Copy Folder ACL by username .NOTES #> Function Copy-Acl { #region Params [CmdletBinding()] Param ( [Parameter(Mandatory=$true,Position=0,ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] $Principal, [Parameter(Mandatory=$true, Position=2)] [ValidateNotNullOrEmpty()] $DestinationPrincipal ) #endregion Begin { if($Principal -is [System.Security.Principal.SecurityIdentifier]) { $Principal = $Principal.Translate([System.Security.Principal.NTAccount]).Value # | select Name } elseif($Principal -is [System.String] -and $Principal -notmatch "\\") { $Principal = "$env:computername\$Principal" } } Process { $ErrorActionPreference = "Continue" foreach($Item in $Path) { $HasWork= $False $Acl = Get-Acl $item foreach ($rule in $Acl.Access | Where-Object {$_.IdentityReference.Value -eq $Principal}) { $Ar=$null $HasWork = $true $Ar = New-Object($Acl.AccessRuleType)($DestinationPrincipal, $rule.($Acl.AccessRightType.Name), $rule.InheritanceFlags, $rule.PropagationFlags, $rule.AccessControlType) if($Ar) { $Acl.AddAccessRule($Ar) | Out-Null } } if($HasWork) { Set-Acl $Item $Acl } } } } Set-Alias cacl Copy-Acl Export-ModuleMember -Function Add-Acl, Remove-Acl, Test-Acl,Update-Acl,Copy-Acl -Alias aacl, racl, tacl, uacl, cacl |