PowerShell NTFS Permissions: Get and Set ACLs

A security audit finds that the Finance share grants Modify access to Everyone — a problem that exists across 50 subdirectories. Fixing it manually in the GUI would take hours; a PowerShell script using Get-Acl and Set-Acl fixes all 50 in under a minute. Mastering PowerShell NTFS permissions management lets you read, audit, add, remove, and copy access control entries programmatically, making security remediation and compliance reporting repeatable and auditable. This post covers every ACL operation you need.
Read Permissions with Get-Acl
Get-Acl returns the security descriptor for a file or folder, including the owner, audit settings, and the discretionary access control list (DACL) containing all permission entries:
$acl = Get-Acl -Path "C:\Shares\Finance"
Write-Host "Owner: $($acl.Owner)"
Write-Host "SDDL: $($acl.Sddl)"
Owner: CORP\Domain Admins
SDDL: O:DAG:DAD:AI(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICI;CCSWWPLOCRCDEDTWA;;;CO)
Display ACL Entries
The Access property of the ACL object contains all access rule entries. Expand it for a readable permission report:
$acl = Get-Acl -Path "C:\Shares\Finance"
$acl.Access | Select-Object IdentityReference, FileSystemRights, AccessControlType,
IsInherited, InheritanceFlags, PropagationFlags |
Format-Table -AutoSize
IdentityReference FileSystemRights AccessControlType IsInherited
----------------- ---------------- ----------------- -----------
BUILTIN\Administrators FullControl Allow True
NT AUTHORITY\SYSTEM FullControl Allow True
CORP\Finance-Staff ReadAndExecute Allow False
CORP\Finance-Managers Modify Allow False
Add a Permission Rule
Construct a FileSystemAccessRule object, add it to the ACL, and apply the updated ACL with Set-Acl:
$path = "C:\Shares\Finance"
$acl = Get-Acl -Path $path
$identity = "CORP\Auditors"
$rights = [System.Security.AccessControl.FileSystemRights]"Read,ListDirectory"
$type = [System.Security.AccessControl.AccessControlType]::Allow
$inherit = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit"
$propagate = [System.Security.AccessControl.PropagationFlags]::None
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$identity, $rights, $inherit, $propagate, $type
)
$acl.AddAccessRule($rule)
Set-Acl -Path $path -AclObject $acl
Write-Host "Added Read permission for $identity on $path"
Remove a Specific Permission
To remove a permission, get the current ACL, find the matching rule, remove it, and write the ACL back:
$path = "C:\Shares\Finance"
$acl = Get-Acl -Path $path
$identity = "CORP\TempContractors"
$ruleToRemove = $acl.Access |
Where-Object { $_.IdentityReference.Value -eq $identity }
if ($ruleToRemove) {
$acl.RemoveAccessRuleAll($ruleToRemove)
Set-Acl -Path $path -AclObject $acl
Write-Host "Removed all permissions for $identity"
} else {
Write-Host "No permissions found for $identity"
}
Copy ACL from Another Path
Copying the ACL from a template folder to a new folder is useful for consistent share provisioning. Get the source ACL and apply it to the destination:
$templatePath = "C:\Shares\_Template"
$newFolderPath = "C:\Shares\NewProject2026"
New-Item -Path $newFolderPath -ItemType Directory -Force | Out-Null
$sourceAcl = Get-Acl -Path $templatePath
Set-Acl -Path $newFolderPath -AclObject $sourceAcl
Write-Host "Permissions copied from $templatePath to $newFolderPath"
Audit Permissions Recursively
Generate a full permission report for all subdirectories using Get-ChildItem -Recurse and Get-Acl. Export to CSV for a spreadsheet-friendly audit trail:
$rootPath = "C:\Shares\Finance"
$report = Get-ChildItem -Path $rootPath -Recurse -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$folder = $_.FullName
try {
$acl = Get-Acl -Path $folder -ErrorAction Stop
$acl.Access | Where-Object IsInherited -eq $false | ForEach-Object {
[PSCustomObject]@{
Path = $folder
Identity = $_.IdentityReference
Rights = $_.FileSystemRights
AccessType = $_.AccessControlType
}
}
}
catch { Write-Warning "Cannot read ACL for $folder" }
}
$report | Export-Csv "C:\Reports\FinanceACLAudit.csv" -NoTypeInformation
Write-Host "Audit complete: $($report.Count) explicit permission entries exported"
Common Errors and Fixes
-
AccessRule must be constructed before adding to ACL. You cannot directly assign a permission string to the ACL. Always create a
System.Security.AccessControl.FileSystemAccessRuleobject with the exact rights, inheritance, and propagation flags you need, then call$acl.AddAccessRule($rule). -
Set-Acl requires admin rights on protected folders. System folders and paths with protected DACLs require elevated privileges. Run the script as an administrator, and add
-ErrorAction StoptoSet-Aclinside atry/catchblock to surface access denied errors cleanly.
Related Cmdlets / See Also
Wrapping Up
PowerShell NTFS permission management with Get-Acl and Set-Acl makes security changes fast, auditable, and repeatable. Build a recursive audit report before any security remediation, construct FileSystemAccessRule objects precisely, and always test with -WhatIf equivalents (inspect the ACL object before writing it back) when working with production shares.


