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