I'm hoping to come up with a script that can walk a directory tree on a Windows server and show me a tree that only includes directories whose permissions are different from it's parent (or sub) directory. I want to produce an easily understandable report that can help me quickly audit the permissions of a folder structure.
Here's what I've got so far:
DIR "Z:\FileShare" -directory -recurse | GET-ACL | where {$_.AreAccessRulesProtected -eq $true} | select path, accessToString | format-list |out-file c:\permissions.txt
This produces a usable set of data as is but it's a bit bulky.
What I don't know is how to have it filter out redundant text, namely lines like "BUILTIN\Administrators Allow FullControl" and instead only show me the delta. Human readable psudo-code might be "if this ACL line can be found in the immediate parent directory, don't show it here."
I tested this with a few folders setting up different ACLs with my own user and it seem to be working but I haven't tested enough to be sure. Basically, the script will loop through directories and add the ACLs to a dictionary where the Keys are each IdentityReference
and the Values are the properties from the ACLs which you're interested on (FileSystemRights
and AccessControlType
) in addition to the folder's absolute path. While enumerating the directories, each object will be compared against the stored values using the Compare-Acl
function which only returns $true
if the object is different.
using namespace System.Collections
using namespace System.Collections.Generic
$map = [Dictionary[string, ArrayList]]::new()
$outObj = {
[pscustomobject]@{
AbsolutePath = $dir.FullName
FileSystemRights = $acl.FileSystemRights
IdentityReference = $acl.IdentityReference
AccessControlType = $acl.AccessControlType
}
}
function Compare-Acl {
param(
[object[]] $Reference,
[object] $Difference
)
foreach ($ref in $Reference) {
$fsRights = $ref.FileSystemRights -eq $Difference.FileSystemRights
$actRef = $ref.AccessControlType -eq $Difference.AccessControlType
if ($fsRights -and $actRef) {
return $false
}
}
$true
}
foreach ($dir in Get-ChildItem Z:\FileShare -Directory -Recurse) {
foreach ($acl in (Get-Acl $dir.FullName | Where-Object AreAccessRulesProtected).Access) {
if ($thisKey = $map[$acl.IdentityReference]) {
$obj = & $outObj
if (Compare-Acl -Reference $thisKey -Difference $obj) {
$null = $thisKey.Add($obj)
}
continue
}
$obj = & $outObj
$map.Add($acl.IdentityReference, [object[]] $obj)
}
}
$map.Keys.ForEach({ $map[$_] }) | Export-Csv path\to\acls.csv -NoTypeInformation