powershellaclaccess-control

Read ACLs excluding the ownership information in Powershell 7


I need to update permissions with adding, editing, and/or removing access rules from ACLs through Powershell. Normally, you would just do something like

$MyACL = Get-Acl
$MyACL.SetAccessRule($SomeNewAccessRule)
Set-Acl -LiteralPath "My Path" -AclObject $MyACL

The problem I have run in to is that the environment my code has to run in lacks the SeTakeOwnershipPrivilege and Get-Acl includes the ownership information. When I subsequently run Set-Acl it fails because it is trying to overwrite the current ownership info, even if it has not changed. I solved this with the following workaround:

$MyAcl = (Get-Item).GetAccessControl("Access")
...

This works because .GetAccessControl("Access") reads the ACL but excludes both the .Path and the .Owner properties and I can then use Set-Acl without a hitch.

I just found that this no longer works in Powershell 7 and the same line instead throws:

InvalidOperation: Method invocation failed because [System.IO.DirectoryInfo] does not contain a method named 'GetAccessControl'.

It seems that Microsoft has removed this call from Powershell 7 and forward. I cannot seem to remove the .Owner property from a Get-Acl object either because it is read-only. How can I read ACLs excluding the .Owner property in Powershell 7?


Solution

  • What happens is that .GetAccessControl() was moved from an instance method in .NET Framework to an extension method in .NET, the type that contains it is FileSystemAclExtensions.

    Unfortunately, extension methods don't translate well into PowerShell, so, the equivalent of:

    $MyAcl = (Get-Item .).GetAccessControl('Access')
    

    Would be the following in PowerShell 7+:

    $MyAcl = [System.IO.FileSystemAclExtensions]::GetAccessControl(
        (Get-Item .),
        [System.Security.AccessControl.AccessControlSections]::Access)
    

    If you wanted you could also use Update-TypeData to have a similar functionality:

    $updateTypeDataSplat = @{
        TypeName   = 'System.IO.FileSystemInfo'
        MemberName = 'GetAccessControl'
        MemberType = 'ScriptMethod'
        Value      = {
            if ($args.Count -eq 0) {
                return [System.IO.FileSystemAclExtensions]::GetAccessControl($this)
            }
    
            [System.IO.FileSystemAclExtensions]::GetAccessControl(
                $this, [System.Security.AccessControl.AccessControlSections] $args[0])
        }
    }
    Update-TypeData @updateTypeDataSplat