Skip to content

Instantly share code, notes, and snippets.

@wipash
Last active June 15, 2022 03:44
Show Gist options
  • Save wipash/0ffcd4bd36a0b725ce14ed122b0d9df2 to your computer and use it in GitHub Desktop.
Save wipash/0ffcd4bd36a0b725ce14ed122b0d9df2 to your computer and use it in GitHub Desktop.
Fix inherited permissions on child folders of a specific folder
#requires -Version 7
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$FolderPath,
[Parameter(Mandatory = $false, Position = 1)]
[string]$Filter,
[Parameter(Mandatory = $false, Position = 2)]
[switch]$OnlyReportSkippedFolders,
[Parameter(Mandatory = $false, Position = 3)]
[switch]$ReportSkippedFolderACL
)
function New-Ace {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[Security.Principal.NTAccount]$Account,
[Parameter(Mandatory = $false, Position = 1)]
[Security.AccessControl.FileSystemRights]$Permissions = 'ReadAndExecute',
[Parameter(Mandatory = $false, Position = 2)]
[Security.AccessControl.InheritanceFlags]$InheritanceFlags = 'ContainerInherit,ObjectInherit',
[Parameter(Mandatory = $false, Position = 3)]
[Security.AccessControl.PropagationFlags]$PropagationFlags = 'None',
[Parameter(Mandatory = $false, Position = 4)]
[Security.AccessControl.AccessControlType]$Type = 'Allow'
)
New-Object Security.AccessControl.FileSystemAccessRule(
$Account, $Permissions, $InheritanceFlags, $PropagationFlags, $Type
)
}
try {
$ParentFolder = Get-Item -Path $FolderPath
$ParentFolderACL = [System.IO.FileSystemAclExtensions]::GetAccessControl($ParentFolder)
Write-Host -ForegroundColor Blue -Object "============================================="
Write-Host -ForegroundColor Blue -Object "Current permissions on: " -NoNewline
Write-Host -ForegroundColor Green -Object $ParentFolder.FullName
Write-Host -ForegroundColor Yellow -Object $ParentFolderACL.AccessToString
Write-Host -ForegroundColor Blue -Object "============================================="
if (-not [string]::IsNullOrEmpty($Filter)) {
Write-Host -ForegroundColor Blue -Object "Filtering subfolders with: " -NoNewline
Write-Host -ForegroundColor Green -Object $Filter
}
Write-Host -ForegroundColor Blue -Object "Retrieving all child folders..."
$ApplyToFolders = @(Get-ChildItem -Path $ParentFolder -Directory -Filter $Filter)
$TotalFolderCount = $ApplyToFolders.Count
Write-Host -ForegroundColor Blue -Object "Found " -NoNewline
Write-Host -ForegroundColor Magenta -Object $TotalFolderCount -NoNewline
Write-Host -ForegroundColor Blue -Object " folders"
Write-Host -ForegroundColor Blue -Object "============================================="
}
catch {
Write-Error "Can't connect to or read the ParentFolder $ParentFolder"
exit 1
}
# Create an empty ArrayList to store the names of folders that we skip later on, by casting an empty array to an ArrayList
$SkippedFolders = [System.Collections.ArrayList]@()
$i = 0
$TotalTime = Measure-Command -Expression {
Write-Host -ForegroundColor Blue -Object "Processing now..."
foreach ($Folder in $ApplyToFolders) {
$i++
$PercentComplete = (($i / $TotalFolderCount) * 100)
Write-Progress -Activity "Processing folders" -Status "$i of $TotalFolderCount :: $($Folder.Name)" -PercentComplete $PercentComplete
try {
# Use .NET method as it's way faster than Powershell's Get-ACL
$FolderACL = [System.IO.FileSystemAclExtensions]::GetAccessControl($Folder)
# Skip any folders that are not currently inheriting from the parent folder
if ($FolderACL.AreAccessRulesProtected) {
$SkippedFolderObject = [PSCustomObject]@{
Folder = $Folder
FolderACL = $FolderACL
}
$SkippedFolders.Add($SkippedFolderObject)
continue
}
if ($OnlyReportSkippedFolders -eq $false) {
# Apply and remove a temporary Access Control Entry, so that the system thinks the ACL has been modified
$TemporaryACE = New-Ace -Account "$env:USERDOMAIN\$env:USERNAME"
$FolderACL.AddAccessRule($TemporaryACE)
$FolderACL.RemoveAccessRule($TemporaryACE)
# Write the ACL back to the folder, which will recalculate all inherited permissions
[System.IO.FileSystemAclExtensions]::SetAccessControl($Folder, $FolderACL)
}
}
catch {
Write-Host -ForegroundColor Red -Object "Access error on " -NoNewline
Write-Host -ForegroundColor Yellow -Object $Folder.FullName
$SkippedFolderObject = [PSCustomObject]@{
Folder = $Folder
FolderACL = $null
}
$SkippedFolders.Add($SkippedFolderObject)
}
}
}
Write-Host -ForegroundColor Blue -Object "Processing completed"
Write-Host -ForegroundColor Blue -Object "============================================="
Write-Progress -Activity "Processing folders" -Completed
$TotalProcessedCount = $TotalFolderCount - $SkippedFolders.Count
Write-Host -ForegroundColor Blue -Object "Processed " -NoNewline
Write-Host -ForegroundColor Magenta -Object $TotalProcessedCount -NoNewline
Write-Host -ForegroundColor Blue -Object " folders (" -NoNewline
Write-Host -ForegroundColor Magenta -Object $SkippedFolders.Count -NoNewline
Write-Host -ForegroundColor Blue -Object " skipped)"
Write-Host -ForegroundColor Blue -Object "Total seconds: " -NoNewline
Write-Host -ForegroundColor Magenta -Object $TotalTime.TotalSeconds
Write-Host -ForegroundColor Blue -Object "Total time (dd:hh:mm:ss): " -NoNewline
Write-Host -ForegroundColor Magenta -Object "$($TotalTime.Days):$($TotalTime.Hours):$($TotalTime.Minutes):$($TotalTime.Seconds)"
if ($SkippedFolders.Count -gt 0) {
Write-Host -ForegroundColor Blue -Object "============================================="
Write-Host -ForegroundColor Blue -Object "Skipped folders:"
foreach ($SkippedFolder in $SkippedFolders) {
if ($ReportSkippedFolderACL) {
Write-Host -ForegroundColor Blue -Object "--------------"
Write-Host -ForegroundColor Yellow $SkippedFolder.Folder.FullName
$SkippedFolder.FolderACL.Access | Select-Object IdentityReference, FileSystemRights, IsInherited | Format-Table
Write-Host -ForegroundColor Blue -Object "--------------"
}
else {
Write-Host -ForegroundColor Yellow $SkippedFolder.Folder.FullName
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment