When dealing with legacy Windows file shares, administrators often encounter three major issues:
- Corrupted ACLs: Disordered or malformed Access Control Entries
- Permission denials: Explicit denies for SYSTEM or Administrators
- Path length limitations: Exceeding MAX_PATH (260 characters)
Here's a PowerShell script that handles all three scenarios:
# Fix-Permissions.ps1
param (
[Parameter(Mandatory=$true)]
[string]$Path
)
function Repair-LongPath {
param ($itemPath)
if ($itemPath.Length -gt 240) {
return "\\?\$($itemPath.Replace('/','\'))"
}
return $itemPath
}
function Reset-Permissions {
param ($item)
$acl = Get-Acl $item
$acl.SetAccessRuleProtection($false, $true)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"BUILTIN\Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.AddAccessRule($rule)
Set-Acl -Path $item -AclObject $acl
}
$fixedPath = Repair-LongPath $Path
try {
$acl = Get-Acl $fixedPath -ErrorAction Stop
if ($acl.Access | Where { $_.AccessControlType -eq "Deny" -and $_.IdentityReference -like "*Administrators*" }) {
takeown /F $fixedPath /A
icacls $fixedPath /grant "Administrators:(F)" /T /C
}
Reset-Permissions $fixedPath
}
catch {
if ($_.Exception -like "*cannot find the path*") {
Write-Warning "Path resolution failed - try UNC or long path prefix"
}
elseif ($_.Exception -like "*access is denied*") {
Write-Warning "Running under SYSTEM context may be required"
# Alternative using PsExec:
# psexec -s -i powershell -File "Fix-Permissions.ps1" -Path $fixedPath
}
}
For particularly problematic items, consider these approaches:
- SDDL Manipulation:
$sddl = "D:(A;;FA;;;BA)(A;;FA;;;SY)" $acl = Get-Acl -Path $fixedPath $acl.SetSecurityDescriptorSddlForm($sddl) Set-Acl -Path $fixedPath -AclObject $acl
- Backup/Restore Method:
robocopy "%temp%\empty" "problem_folder" /mir /xd "problem_folder"
When native tools aren't sufficient:
- SetACL: For granular permission management
setacl -on "X:\problem_folder" -ot file -actn restore -rec cont_obj -bckp "backup.sddl"
- NtfsInfo (Sysinternals): For low-level analysis
ntfsinfo -d X:\problem_folder > acl_analysis.txt
To avoid future issues:
# Group Policy recommendation:
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem"
-Name "LongPathsEnabled" -Value 1
When dealing with legacy file shares in enterprise environments, we frequently encounter three persistent issues:
- ACL Corruption: Disordered Access Control Entries or invalid security descriptors
- Permission Denials: Explicit DENY entries for SYSTEM or Administrators
- Path Length Limitations: Files exceeding MAX_PATH (260 characters) constraints
Here's a comprehensive PowerShell script that addresses all three scenarios:
function Repair-FilePermissions {
param (
[Parameter(Mandatory=$true)]
[string]$Path,
[switch]$Recursive
)
# Handle long paths
if ($Path.Length -gt 240) {
$Path = "\\?\$($Path.TrimStart('\\'))"
}
try {
$acl = Get-Acl -Path $Path -ErrorAction Stop
# Check for corrupted ACL
if ($acl.AccessToString -match "Invalid|Unknown") {
Write-Verbose "Found corrupted ACL at $Path"
$newAcl = New-Object System.Security.AccessControl.DirectorySecurity
$newAcl.SetAccessRuleProtection($false, $true)
Set-Acl -Path $Path -AclObject $newAcl -ErrorAction Stop
}
# Verify Administrator access
$adminRule = $acl.Access |
Where-Object { $_.IdentityReference -eq "BUILTIN\Administrators" -and $_.AccessControlType -eq "Deny" }
if ($adminRule) {
Write-Verbose "Found Administrator deny rule at $Path"
Takeown.exe /F $Path /A
Icacls.exe $Path /grant:r "BUILTIN\Administrators:(OI)(CI)F" /T /C
}
# Recurse if directory
if ((Get-Item $Path) -is [System.IO.DirectoryInfo] -and $Recursive) {
Get-ChildItem -Path $Path | ForEach-Object {
Repair-FilePermissions -Path $_.FullName -Recursive
}
}
}
catch {
Write-Warning "Failed to process $Path : $($_.Exception.Message)"
}
}
For particularly stubborn cases, we combine our PowerShell approach with Sysinternals utilities:
psexec.exe -i -s cmd.exe /c "takeown /f \"C:\problem_folder\" /r /d y && icacls \"C:\problem_folder\" /reset /t /c /q"
Before making changes, it's crucial to analyze the existing permissions. This script helps identify problematic entries:
function Get-PermissionIssues {
param ($Path)
$results = @()
$acl = Get-Acl $Path
foreach ($ace in $acl.Access) {
if ($ace.AccessControlType -eq "Deny" -and
($ace.IdentityReference -like "*Administrators*" -or
$ace.IdentityReference -like "*SYSTEM*")) {
$results += [pscustomobject]@{
Path = $Path
Issue = "Critical Deny Rule"
Identity = $ace.IdentityReference
}
}
if ($ace.IdentityReference -like "*S-1-5-21-*") {
$results += [pscustomobject]@{
Path = $Path
Issue = "Orphaned SID"
Identity = $ace.IdentityReference
}
}
}
return $results
}
For complex environments, consider these specialized tools:
- SetACL Studio: Graphical interface for bulk permission management
- NtfsPermissionsReport: Generates detailed permission analysis reports
- TreeSize Professional: Identifies permission issues alongside storage analysis
To avoid future problems:
- Implement regular permission audits with PowerShell scripts
- Establish standardized permission templates
- Enable Windows' built-in Access Denied Assistance feature
- Monitor for path length issues during file operations
Here's how we might process a problematic share:
# 1. First analyze the share structure
$issues = Get-ChildItem -Path "\\fileserver\share" -Recurse |
ForEach-Object { Get-PermissionIssues -Path $_.FullName } |
Where-Object { $_.Issue }
# 2. Process each issue
foreach ($item in $issues) {
Repair-FilePermissions -Path $item.Path -Recursive
}
# 3. Reset inheritance where needed
Get-ChildItem -Path "\\fileserver\share" -Recurse | ForEach-Object {
icacls $_.FullName /reset /t /c /q
}