‘Twas a long time ago, longer now than it seems
In a place that perhaps you’ve seen in your dreams.
For the story that you are about to be told
Began with the technicians of old.
A very long time ago, as a junior tech I got a seemingly simple request. “Tell me what user X has access to”
Quickly I looked up the groups and and provided the list, and got the response you already know. “We know that but what do those groups have access to?”
Of course this is a completely different question, so I set forth to write some code that would go through a file server and would tell me what the permissions where and at what level they changed. I purchased books and tried to call the API directly but was not able to create what I wanted and since nobody else could do it either the project just dropped off the radar.
Very recently I got another request. “We need to look through a directory structure to see where the “Domain Admins” group does not have full access. Users have been creating folders and adjusting permissions that we will need to fix without resetting everything in the tree.”
This time I started writing in PowerShell, I didn’t think I would say this but I wish PowerShell existed in the NT days. I didn’t need to fix anything just report, and within a couple of hours I had it.
The following script will go through directories and output 1 line for each folder or file it finds where the requested group does not have the access level defined UNLESS the file or folder is inheriting permissions from a higher level. The intent is that you should only need to make 1 change per line of output to correct the permissions, and even if there are thousands of files with incorrect permissions that inherit permission from a parent.
You could have this fix things if you want using set-acl but I didn’t need to.
cls
# The intent of this script
# Loop recursively through files and folders starting at $target provided below)
# Look for the existance of an account or group in the ACL
# Check the access level for that user \ groupin the ACL
# Generate a report showing ONLY the places you would need to make a change
# to make sure the required account has the correct access on the entire tree.
# you could easily use set.acl to actually correct for issues (see note below) but I only needed a report.
# File System Audit and the WABAC machine - www.blackops.ca - blog - for more info.
$target="\\Servername\sharename"
$GroupToCheck="Domain\User"
$AccessExpected="FullControl"
Function CheckAll {
# This function starts at the folder provided above
param([string]$rootfolder)
CheckACL $rootfolder
#Check the current folder ACL's
$items = Get-ChildItem -Path $rootfolder
If ($items)
# The above IF traps for a condition of a folder with no files in it.
{
foreach ($item in $items)
{
if ($item.Attributes -ne "Directory")
{
# for each file (note the -NE) check the ACL for the file
checkacl $item.fullName
}
}
foreach ($item in $items)
{
if ($item.Attributes -eq "Directory")
{
# for each directory (note the -EQ this time) Recurse back into this function with the directory as the new root folder
CheckAll $item.fullName
}
}
}
}
Function CheckACL {
param([string]$target)
$Check=$false
$inheritON=$false
$acl=Get-Acl $target # this reads the ACL
if ($acl.AreAccessRulesProtected)
# if AreAccessRulesProtected is TRUE then that means that a folder is NOT inheriting it's permissions
# if a folder is inheriting then it will NOT appear in the output
{
foreach ($ACLDetail in $acl.Access)
{
#This loops through each user \ access level and checks to see if access levels are explicit or inherited.
if ($acldetail.IsInherited) {$inheritON=$true} #inheritance check if inhereted file \ folder will NOT appear in report
if ($acldetail.IdentityReference -eq $GroupToCheck) #This checks each user for the one we are looking for (provided at the top of the script
{
if ($acldetail.FileSystemRights -eq $AccessExpected) #This checks to see if the permissions are correct
{
$Check = $true
}
else
{
#If the permissions are not correct output the full path\name and the current access level
Write-Host -NoNewline $Target
Write-Host -NoNewline "`t" #tab
Write-Host $acldetail.FileSystemRights
# If you want to fix the issue you would need a set_acl here and once more below
}
}
}
if (!$Check -and !$inheritON) #if the expected user is not found AND there is no inheritance set then log the file\folder
{
Write-Host -NoNewline $target
write-host -NoNewline "`t" #tab
write-host -NoNewline $GroupToCheck
write-host " Missing"
# If you want to fix the issue you would need a set_acl here and once more above
}
}
}
"begin"
checkall $target
"end"
And yes I am old enough to remember the WABAC Machine although not quite old enough to see the episodes as they aired for the first time.
Well it didn’t take long to go from report only to please fix it, so I have another script. If you want the script to add the required access for the defined group use the script below. I actually found set-acl harder to use than I expected and remember you see different statements for each condition
ADD to ACL for folder
Modify ACL for folder
ADD to ACL for file
Modify ACL for file
cls
# The intent of this script
# Loop recursively through files and folders starting at $target provided below)
# Look for the existance of an account or group in the ACL
# Check the access level for that user \ groupin the ACL
# Generate a report showing ONLY the places you would need to make a change
# to make sure the required account has the correct access on the entire tree.
# for more info s@blackops.ca
# THIS VERSION WILL CORRECT ISSUES.
$target="C:\Temp"
$GroupToCheck="BUILTIN\Administrators"
$AccessExpected="FullControl"
#$DesiredPermission = $GroupToCheck,$AccessExpected,"ContainerInherit, ObjectInherit","NoPropagateInherit","Allow"
$person = [System.Security.Principal.NTAccount]"$GroupToCheck"
$access = [System.Security.AccessControl.FileSystemRights]"$AccessExpected"
$Folderinheritance = [System.Security.AccessControl.InheritanceFlags]“ContainerInherit, ObjectInherit”
$Fileinheritance = [System.Security.AccessControl.InheritanceFlags]“None”
$propagation = [System.Security.AccessControl.PropagationFlags]“NoPropagateInherit”
$type = [System.Security.AccessControl.AccessControlType]“Allow”
$FolderaccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($person,$access,$Folderinheritance,$propagation,$type)
$FileaccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($person,$access,$type)
$AccessModification = New-Object system.security.AccessControl.AccessControlModification
$AccessModification.value__ = 2
$Modification = $False
Function CheckAll {
# This function starts at the folder provided above
param([string]$rootfolder)
CheckACL $rootfolder
#Check the current folder ACL's
$items = Get-ChildItem -Path $rootfolder
If ($items)
# The above IF traps for a condition of a folder with no files in it.
{
foreach ($item in $items)
{
if ($item.Attributes -ne "Directory")
{
# for each file (note the -NE) check the ACL for the file
checkacl $item.fullName
}
}
foreach ($item in $items)
{
if ($item.Attributes -eq "Directory")
{
# for each directory (note the -EQ this time) Recurse back into this function with the directory as the new root folder
CheckAll $item.fullName
}
}
}
}
Function CheckACL {
param([string]$target)
$Check=$false
$inheritON=$false
$acl=Get-Acl $target # this reads the ACL
if ($acl.AreAccessRulesProtected)
# if AreAccessRulesProtected is TRUE then that means that a folder is NOT inheriting it's permissions
# if a folder is inheriting then it will NOT appear in the output
{
foreach ($ACLDetail in $acl.Access)
{
#This loops through each user \ access level and checks to see if access levels are explicit or inherited.
if ($acldetail.IsInherited) {$inheritON=$true} #inheritance check if inhereted file \ folder will NOT appear in report
if ($acldetail.IdentityReference -eq $GroupToCheck) #This checks each user for the one we are looking for (provided at the top of the script
{
if ($acldetail.FileSystemRights -eq $AccessExpected) #This checks to see if the permissions are correct
{
$Check = $true
}
else
{
#If the permissions are not correct output the full path\name and the current access level
Write-Host -NoNewline $Target
Write-Host -NoNewline "`t" #tab
Write-Host $acldetail.FileSystemRights
If (Test-Path $target -pathtype container)
{
# If you want to fix the issue you would need a set_acl here and once more below
$acl.ModifyAccessRule($AccessModification, $FolderaccessRule, [ref]$Modification) |Out-Null
Set-Acl $target -AclObject $acl
$Check = $true
}
Else
{
$acl.ModifyAccessRule($AccessModification, $FileaccessRule, [ref]$Modification) |Out-Null
Set-Acl $target -AclObject $acl
$Check = $true
}
}
}
}
if (!$Check -and !$inheritON) #if the expected user is not found AND there is no inheritance set then log the file\folder
{
Write-Host -NoNewline $target
write-host -NoNewline "`t" #tab
write-host -NoNewline $GroupToCheck
write-host " Missing"
if (Test-Path $target -pathtype container)
{
$acl.AddAccessRule($FolderaccessRule)
Set-Acl $target -AclObject $acl
# If you want to fix the issue you would need a set_acl here and once more above
}
Else
{
$acl.AddAccessRule($FileaccessRule)
Set-Acl $target -AclObject $acl
}
}
}
}
"begin"
checkall $target
"end"