Set-Acl is the PowerShell cmdlet that writes a security descriptor back to a file or folder. On its own it does very little; the work happens on the ACL object you get from Get-Acl, where you add, remove, or replace access rules before handing the result to Set-Acl. Once you know that pattern, every permission change in this cheat sheet is a variation on the same three lines.

This page is the companion to our Get-Acl cheat sheet for viewing folder permissions. Everything here changes NTFS permissions on disk, so read the safety section first if you are working on a production file server.

Before You Change Anything

Permission changes take effect immediately, there is no undo, and a mistake on a parent folder inherits down to everything beneath it. Three habits keep Set-Acl safe:

  • Capture the current state first. Save the SDDL string or an icacls backup so you can restore it (see verification).
  • Test on one folder. Run the change against a scratch folder, inspect $acl.Access, and only then point it at the real path.
  • Run elevated. Set-Acl writes the owner along with the access rules, which needs an administrator session even when the owner is not changing.

Never drop inherited entries without copying them first. Calling SetAccessRuleProtection($true, $false) on a folder removes every inherited permission, including the Administrators and SYSTEM entries that let you fix it afterwards.

The Get, Modify, Set Pattern

Every change follows the same shape. Read the descriptor, change the in-memory object, write it back:

$path = "C:\Data\Finance"

# 1. read the current security descriptor
$acl = Get-Acl -Path $path

# 2. build a rule and add it to the descriptor (nothing has changed on disk yet)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Finance-RW", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)

# 3. write the descriptor back
Set-Acl -Path $path -AclObject $acl

Between steps two and three you can print $acl.Access to confirm the rule looks right. If it does not, discard the variable and start again; the folder is untouched.

Anatomy of a FileSystemAccessRule

The five constructor arguments map directly onto the fields you see in the Windows Security dialog:

ArgumentMeaningCommon values
IdentityThe user or group, as DOMAIN\Name, a built-in name, or an NTAccount objectCORP\Finance-RW, BUILTIN\Users, NT AUTHORITY\Authenticated Users
RightsA FileSystemRights value; combine with commasFullControl, Modify, ReadAndExecute, Read, Write
Inheritance flagsWhat the entry passes to childrenContainerInherit, ObjectInherit (subfolders and files), ContainerInherit (subfolders only), None (this folder only)
Propagation flagsHow far inheritance reachesNone (all descendants), InheritOnly (children but not this folder), NoPropagateInherit (one level only)
TypeAllow or DenyAllow, Deny

The Security dialog's "Applies to" dropdown is just a combination of the inheritance and propagation flags:

Applies toInheritance flagsPropagation flags
This folder, subfolders and filesContainerInherit, ObjectInheritNone
This folder onlyNoneNone
This folder and subfoldersContainerInheritNone
This folder and filesObjectInheritNone
Subfolders and files onlyContainerInherit, ObjectInheritInheritOnly
Files onlyObjectInheritInheritOnly

Grant a User or Group Access

The most common change: give a group Modify rights that flow to everything beneath the folder.

$path = "C:\Data\Finance"
$acl  = Get-Acl -Path $path
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Finance-RW", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)
Set-Acl -Path $path -AclObject $acl

Read-only access uses ReadAndExecute; a folder-only entry that should not inherit uses "None" for the inheritance flags:

# read-only, inherited by subfolders and files
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Finance-RO", "ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow")

# full control on this folder only
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\FS-Admins", "FullControl", "None", "None", "Allow")

Grant to groups, not people. An entry for an individual account becomes an orphaned SID the day that account is deleted. Put the user in a group and grant the group, as described in our NTFS permissions best practices.

Add a Deny Entry

A Deny rule uses the same constructor with "Deny" as the type. Deny entries are evaluated before Allow entries, so they win even when the same account is allowed through another group:

$acl  = Get-Acl -Path "C:\Data\Finance\Archive"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Contractors", "Write, Delete", "ContainerInherit, ObjectInherit", "None", "Deny")
$acl.AddAccessRule($rule)
Set-Acl -Path "C:\Data\Finance\Archive" -AclObject $acl

Use Deny sparingly. Most access problems that end in a Deny entry are better solved by removing the account from the group that allows it. Deny entries are the leading cause of "access denied" tickets that nobody can explain six months later.

Remove an Account from a Folder

PurgeAccessRules removes every explicit entry for an identity in one call. It takes an NTAccount object rather than a string:

$path = "C:\Data\Finance"
$acl  = Get-Acl -Path $path
$who  = [System.Security.AccessControl.NTAccount]"CORP\jsmith"
$acl.PurgeAccessRules($who)
Set-Acl -Path $path -AclObject $acl

To remove one specific rule rather than everything for the account, find it in the Access list and pass it to RemoveAccessRule:

$acl  = Get-Acl -Path $path
$rule = $acl.Access | Where-Object {
    $_.IdentityReference.Value -eq "CORP\jsmith" -and
    $_.AccessControlType -eq "Deny" -and
    -not $_.IsInherited
}
$rule | ForEach-Object { [void]$acl.RemoveAccessRule($_) }
Set-Acl -Path $path -AclObject $acl

Inherited entries cannot be removed from the child folder. Either remove them from the parent where they are defined, or disable inheritance on the child and then remove the copied entry.

Replace an Account's Rights

SetAccessRule replaces all existing explicit entries for the identity with the rule you supply, which is cleaner than removing and re-adding:

# downgrade a group from Modify to read-only in one step
$acl  = Get-Acl -Path "C:\Data\Finance"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Finance-RW", "ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path "C:\Data\Finance" -AclObject $acl

Disable or Re-enable Inheritance

SetAccessRuleProtection controls whether a folder inherits from its parent. The second argument decides what happens to the entries that were being inherited: $true converts them to explicit entries on this folder, $false discards them.

# disable inheritance and keep the inherited entries as explicit copies (safe)
$acl = Get-Acl -Path "C:\Data\Payroll"
$acl.SetAccessRuleProtection($true, $true)
Set-Acl -Path "C:\Data\Payroll" -AclObject $acl

# re-enable inheritance (the second argument is ignored when enabling)
$acl = Get-Acl -Path "C:\Data\Payroll"
$acl.SetAccessRuleProtection($false, $false)
Set-Acl -Path "C:\Data\Payroll" -AclObject $acl

Re-enabling inheritance does not remove the explicit copies that were created when it was disabled, so a folder can end up with the same entry twice. Purge the duplicates afterwards, or use the reset approach under applying changes across a tree. Our broken inheritance guide covers how to find every folder where inheritance has been disabled and decide which breaks are legitimate.

Change the Folder Owner

The owner is set on the descriptor with SetOwner. Setting a group such as Administrators as owner is the usual fix for folders left behind by departed users:

$path  = "C:\Data\Finance\OldProjects"
$acl   = Get-Acl -Path $path
$owner = [System.Security.AccessControl.NTAccount]"BUILTIN\Administrators"
$acl.SetOwner($owner)
Set-Acl -Path $path -AclObject $acl

Set-Acl can only assign ownership to yourself or to a group you belong to, and it needs the restore privilege that comes with an elevated session. If you cannot even read the folder, take ownership first with takeown and then fix the permissions:

takeown /F "C:\Data\Finance\OldProjects" /A /R /D Y
icacls "C:\Data\Finance\OldProjects" /grant "BUILTIN\Administrators:(OI)(CI)F" /T

Apply a Change Across a Folder Tree

Because NTFS inheritance already propagates entries to children, you rarely need to loop. Add the rule with ContainerInherit, ObjectInherit at the top of the tree and every subfolder that inherits will pick it up. Looping is only necessary when some subfolders have inheritance disabled and you want the entry there too:

$root = "C:\Data\Finance"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\FS-Admins", "FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")

# apply at the root, then only to subfolders that do not inherit
$targets = @(Get-Item -LiteralPath $root) +
           (Get-ChildItem -Path $root -Directory -Recurse -ErrorAction SilentlyContinue |
                Where-Object { (Get-Acl -LiteralPath $_.FullName).AreAccessRulesProtected })

foreach ($folder in $targets) {
    $acl = Get-Acl -LiteralPath $folder.FullName
    $acl.AddAccessRule($rule)
    Set-Acl -LiteralPath $folder.FullName -AclObject $acl
}

To reset a tree so that every subfolder simply inherits from the root again, icacls is faster and safer than a PowerShell loop:

# re-enable inheritance everywhere below the root and remove explicit entries
icacls "C:\Data\Finance" /reset /T /C

Preview the blast radius first. Before resetting or looping over a tree, get a list of every folder with explicit entries or disabled inheritance so you know what the change will touch. The Get-Acl cheat sheet has the one-liner, and Permissions Reporter's filter presets do it across an entire server.

Copy Permissions from Another Folder

Piping Get-Acl into Set-Acl copies one folder's descriptor to another, which is a quick way to stamp a template ACL onto new project folders:

Get-Acl -Path "C:\Templates\ProjectFolder" | Set-Acl -Path "C:\Data\Projects\NewClient"

This copies the owner as well, which fails unless you are allowed to assign that owner. To copy only the access rules, transfer them through SDDL and strip the owner and group sections:

$source = Get-Acl -Path "C:\Templates\ProjectFolder"
$target = Get-Acl -Path "C:\Data\Projects\NewClient"

# keep only the DACL portion of the source descriptor
$dacl = $source.Sddl.Substring($source.Sddl.IndexOf("D:"))
$target.SetSecurityDescriptorSddlForm($dacl)
Set-Acl -Path "C:\Data\Projects\NewClient" -AclObject $target

Common Set-Acl Errors

ErrorCauseFix
The security identifier is not allowed to be the owner of this object The descriptor names an owner you cannot assign (typically the previous owner), and Set-Acl tries to write it back Run elevated, or build a new DirectorySecurity object that contains only your access rules
Attempted to perform an unauthorized operation The session lacks Write DAC on the folder, or is not elevated Run PowerShell as administrator; take ownership if the ACL locks out Administrators
Some or all identity references could not be translated The account name is misspelled, the domain is unreachable, or the account was deleted Check the name with [System.Security.Principal.NTAccount]"CORP\name" and translate it to a SID before building the rule
Cannot find path ... because it does not exist Wildcard characters in the path, or a path longer than 260 characters Use -LiteralPath; prefix long paths with \\?\
Change appears to succeed but children are unaffected The rule was created with None inheritance flags, or the children have inheritance disabled Rebuild the rule with ContainerInherit, ObjectInherit; find protected subfolders and fix them individually

To sidestep the owner problem entirely, create an empty descriptor, add only the rules you want to change, and let Set-Acl merge it:

$acl  = New-Object System.Security.AccessControl.DirectorySecurity
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "CORP\Finance-RW", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)
$acl.SetAccessRuleProtection($false, $true)   # keep inheriting from the parent
Set-Acl -Path "C:\Data\Finance" -AclObject $acl

Careful: a fresh DirectorySecurity object has an empty DACL. Set-Acl writes the whole DACL, so without SetAccessRuleProtection($false, $true) the folder would end up with your one rule and nothing else.

icacls Equivalents

icacls performs the same changes with one line each and no object model to learn. It is the better choice inside batch files, and its /save and /restore pair makes an easy backup.

Taskicacls
Grant Modify to a group, inheritedicacls "C:\Data" /grant "CORP\Finance-RW:(OI)(CI)M"
Replace an account's rightsicacls "C:\Data" /grant:r "CORP\Finance-RW:(OI)(CI)RX"
Add a Deny entryicacls "C:\Data" /deny "CORP\Contractors:(OI)(CI)W"
Remove an accounticacls "C:\Data" /remove "CORP\jsmith"
Disable inheritance, keep copiesicacls "C:\Data" /inheritance:d
Disable inheritance, drop entriesicacls "C:\Data" /inheritance:r
Re-enable inheritanceicacls "C:\Data" /inheritance:e
Change ownericacls "C:\Data" /setowner "BUILTIN\Administrators" /T
Reset a tree to inherited defaultsicacls "C:\Data" /reset /T /C
Back up and restore ACLsicacls "C:\Data" /save acls.txt /T then icacls "C:\" /restore acls.txt

Rights are abbreviated as F full control, M modify, RX read and execute, R read, and W write. (OI) and (CI) are object and container inheritance, matching the ObjectInherit and ContainerInherit flags above. Add /T to apply the change to every existing subfolder and file rather than relying on inheritance.

Verify the Change and Keep an Audit Trail

Always confirm the result. For one folder, re-run Get-Acl or icacls:

(Get-Acl -Path "C:\Data\Finance").Access |
    Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSize

For rollback, capture the descriptor before the change and restore it if needed:

# before
$saved = (Get-Acl -Path "C:\Data\Finance").Sddl

# rollback
$acl = Get-Acl -Path "C:\Data\Finance"
$acl.SetSecurityDescriptorSddlForm($saved)
Set-Acl -Path "C:\Data\Finance" -AclObject $acl

On a file server, the change you made is rarely the only one that matters. Inheritance carries it to thousands of subfolders, some of which had their own explicit entries or disabled inheritance, and the net effect on any given user depends on nested group membership that Get-Acl cannot see. That is where a before-and-after report earns its keep:

  • Run a Permissions Reporter scan of the server before the change and export it to XML.
  • Make the change with Set-Acl or icacls.
  • Scan again and use report comparison to see exactly which folders and principals gained or lost access, with group membership expanded.
  • Keep both exports as the audit record, or schedule the scan so every future change is captured automatically.

Permissions Reporter does not modify permissions itself; it shows you what to change and proves what changed. The Basic edition is free.

Related Resources

PowerShell Set-Acl FAQ

How do I set folder permissions with PowerShell?

+

How do I give a user Full Control of a folder in PowerShell?

+

How do I remove a user's permissions from a folder?

+

How do I disable inheritance on a folder with PowerShell?

+

Does Set-Acl apply the change to subfolders and files?

+

Why does Set-Acl fail with a security identifier or unauthorized operation error?

+

How can I verify the change or undo it?

+

Prove what changed with a before-and-after permissions report in minutes!

Download Free

Safe. Trusted. Guaranteed.

  • 100% malware free
  • 100% spyware free
  • 100% adware free
  • 100% quality software