PowerShell NTFS Permissions: Get and Set ACLs

PowerShell NTFS Permissions: Get and Set ACLs

PowerShell Tips Editor 3 min read
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.FileSystemAccessRule object 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 Stop to Set-Acl inside a try/catch block 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.

Send-Item -To