PowerShell Get-Acl displays an unknown FileSystemRights for certain folders, files, and drives when GENERIC_ALL or other generic rights exist in an ACE

The Get-Acl PowerShell cmdlet is great for getting the NTFS permissions of folders, files, and drives however you may notice some strange behaviour with the FileSystemRights showing an numeric value rather than an enum.


This can occur when GENERIC permissions such as GENERIC_READ, GENERIC_ALL, GENERIC_WRITE, or GENERIC_EXECUTE are in use.

These permission can be seen in the definition of the access mask format
https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask-format




We came across this problem when writing an update for our Network Documentation Tool XIA Configuration Server please go ahead and take a look at our software.




So what's the purpose of these? 

Security descriptors are designed to be generic an applied to things like files, folders, drives, registry entries, Active Directory containers etc. etc.

They therefore have generic overarching permissions and then object specific permissions.

The problem is the generic permissions conflict (or at least combine with and confuse) the specific permissions. When you use the permissions UI in Windows it sets the specific permissions nicely.

Sometimes (for example on the root of a drive) Windows sets the GENERIC permissions and the UI has some weird inconsistencies as seen later.

PowerShell has no values for the GENERIC permissions in the enum definition and therefore shows a numeric value.

To replicate this you can use the icacls command line tool - this will grant the BATCH user GENERIC_ALL permissions to the folder D:\TestFolder.

icacls "D:TestFolder" /grant "Batch:(OI)(GA)"


The main permissions dialog displays this as "special".



Interestingly however, the advanced dialog automatically standardizes these rights to Full Control (because effectively it is full control) and the dialog as no way to set any of the "GENERIC_*" permissions.



PowerShell has the problem, mentioned before, of not knowing what the rights actually are and displays the value as an integer. This is actually the enum value with the GENERIC flags set.




To resolve this issue you can unset the GENERIC flags and set the corresponding specific NTFS rights flags.


# Corrects the NTFS file system rights standardizing GENERIC_* permissions.
Function Get-FileSystemRights
{

    [CmdletBinding()]
    param(
        [Parameter()]
        [int] $RightsValue
    )

    $GENERIC_ALL = [int]268435456;
    $GENERIC_READ = [int]-2147483648;
    $GENERIC_WRITE = [int]1073741824;
    $GENERIC_EXECUTE =[int]536870912;

    if (($RightsValue -band $GENERIC_ALL) -eq $GENERIC_ALL) { return [System.Security.AccessControl.FileSystemRights]::FullControl; }

    if (($RightsValue -band $GENERIC_READ) -eq $GENERIC_READ)
    {

        $RightsValue = $RightsValue -= $GENERIC_READ;

        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Read;

        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Synchronize;

    }

    if (($RightsValue -band $GENERIC_WRITE) -eq $GENERIC_WRITE)
    {
        $RightsValue = $RightsValue -= $GENERIC_WRITE;
        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Write;
        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Synchronize;
    }

    if (($RightsValue -band $GENERIC_EXECUTE) -eq $GENERIC_EXECUTE)
    {
        $RightsValue = $RightsValue -= $GENERIC_EXECUTE;
        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Traverse;
        $RightsValue = $RightsValue += [int][System.Security.AccessControl.FileSystemRights]::Synchronize;
    }

    return [System.Security.AccessControl.FileSystemRights] $RightsValue;



To function be used as per the following

$acl = (Get-Acl "D:\TestFolder").Access;
foreach ($ace in $acl)
{
    Write-Host $ace.IdentityReference $ace.FileSystemRights (Get-FileSystemRights -RightsValue $ace.FileSystemRights);

}

  

The permissions will be resolved correctly.





If you have any feedback on the article or know why Microsoft use these GENERIC_* permissions on the root of drives please leave a comment below.

Comments

Popular posts from this blog

Windows Server 2016, 2019, 2022, Windows 10 and Windows 11: Date and time "Some settings are managed by your organization".

TFTPD32 or TFTPD64 reports Bind error 10013 An attempt was made to access a socket in a way forbidden by its access permissions.

Windows Server 2019 desktop icons such as My Computer, Windows cannot access the specified device, path, or file.