Evaluating current ACEs on NTFS ACLs with PowerShell

We have a document management system that has million of files on a NTFS file system accessed through a network share. A single service account needs full permission to all of these files and the application brokers access using this service account.

During a migration of data, something happened and the permissions are now inconsistent.

I've been trying to write a script in PowerShell to identify which files don't have the appropriate ACE, but get-acl is somewhat...painful.

I've tried various combinations similar to:

get-childitem -recurse | get-acl | select -expandproperty access | 
where { $_.$_.IdentityReference -notcontains $principal

where $Principal is the user that needs permission in domain\user format.

There's got to be a way to do this, right? What is it? I'd like to keep it native to PowerShell and not use icacls or cacls if possible.


Solution 1:

You could do it like this (breaking it in to more statements helps readability):

# Go to the directory and find the files
Push-Location "C:\MDMarrasFiles"
$Files = Get-ChildItem -Recurse

# Create an IdentityReference and a FullControl FileSystemAccessRule for said identity
$Principal = New-Object System.Security.Principal.NTAccount("DOMAIN\user")
$FullControlACERule = New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList ($Principal,"FullControl","Allow")

# Go through the files
foreach($File in $Files)
{
    # Get the current ACL on the file
    $ACL = Get-ACL $File

    # Extract the ACEs, both explicit on the file and inherited 
    $ACEs = $ACL.GetAccessRules($true,$true,[System.Security.Principal.NTAccount])

    # Filter the ACEs to extract those giving FullControl to your target user
    $ACEsMatching = $ACEs |Where {`
        $_.FileSystemRights -eq "FullControl" -and `
        $_.IdentityReference -eq $objUser -and `
        $_.AccessControlType -eq "Allow"` 
    }

    # Test if there where no such ACE to be found
    if($ACEsMatching.Count -eq 0)
    {
        # Add the FullControl Rule to the current ACL
        $ACL.AddAccessRule($FullControlACERule)

        # Write the new ACL back to the file
        Set-ACL $File -AclObject $ACL 
    }
}
Pop-Location

Please test this on a smaller subset of files before running in production ;-)

If you want to make sure that a new explicit ACE is added even though the account might have the right inherited already, filter out inherited Access Rules like this:

$ACEs = $ACL.GetAccessRules($true, $false ,[System.Security.Principal.NTAccount])

Notice how the second boolean argument is now $false indicating that inherited rules should not be returned