Configuring NTFS permissions is something that you can do using your Windows Explorer, Server Manager, or by using command-line tools like subinacl.exe or icacls.exe. In this blog post, I will show you how to set NTFS permissions in two different ways using PowerShell 🙂

Built-in cmdlets
PowerShell has two ACL cmdlets for retrieving and setting NTFS permissions, Get-Acl and Set-Acl.
Get-Acl
When using Get-Acl with the -Path parameter to specify the folder or file you want to check the permissions of, it will look like this:
C:\Users\HarmVeenstra> Get-Acl -Path C:\Windows\ | Format-List Path : Microsoft.PowerShell.Core\FileSystem::C:\Windows\ Owner : NT SERVICE\TrustedInstaller Group : NT SERVICE\TrustedInstaller Access : CREATOR OWNER Allow 268435456 NT AUTHORITY\SYSTEM Allow 268435456 NT AUTHORITY\SYSTEM Allow Modify, Synchronize BUILTIN\Administrators Allow 268435456 BUILTIN\Administrators Allow Modify, Synchronize BUILTIN\Users Allow -1610612736 BUILTIN\Users Allow ReadAndExecute, Synchronize NT SERVICE\TrustedInstaller Allow 268435456 NT SERVICE\TrustedInstaller Allow FullControl APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadAndExecute, Synchronize APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow -1610612736 APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow ReadAndExecute, Synchronize APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow -1610612736 Audit : Sddl : O:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464G:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464D:PAI(A;OICIIO;GA;;;CO)(A;OICIIO;GA;;;SY)(A;;0x1301bf ;;;SY)(A;OICIIO;GA;;;BA)(A;;0x1301bf;;;BA)(A;OICIIO;GXGR;;;BU)(A;;0x1200a9;;;BU)(A;CIIO;GA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)(A;;FA;;;S-1-5-80-9560088 85-3418522649-1831038044-1853292631-2271478464)(A;;0x1200a9;;;AC)(A;OICIIO;GXGR;;;AC)(A;;0x1200a9;;;S-1-15-2-2)(A;OICIIO;GXGR;;;S-1-15-2-2)
It will show the Owner, Group, and individual permissions of the file or folder. The numbers 268435456, -536805376, and -1610612736 indicate this:
Number | Access |
268435456 | FullControl |
-536805376 | Modify, Synchronize |
-1610612736 | ReadAndExecute, Synchronize |
The Sddl (Security Descriptor Definition Language) details can be found here.
You can also show the Access Permissions in more detail using (Get-Acl -Path c:\windows\).Access
C:\Users\HarmVeenstra> (Get-Acl -Path C:\Windows\).Access FileSystemRights : 268435456 AccessControlType : Allow IdentityReference : CREATOR OWNER IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : InheritOnly FileSystemRights : 268435456 AccessControlType : Allow IdentityReference : NT AUTHORITY\SYSTEM IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : InheritOnly FileSystemRights : Modify, Synchronize AccessControlType : Allow IdentityReference : NT AUTHORITY\SYSTEM IsInherited : False InheritanceFlags : None PropagationFlags : None FileSystemRights : 268435456 AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : InheritOnly FileSystemRights : Modify, Synchronize AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : None PropagationFlags : None
More (advanced) examples can be found here.
Set-Acl
The Set-Acl cmdlet can be used to set permissions on files or folders. The nice thing about it is that you can copy/paste permission. In the example below, I copy the permissions from the d:\Test1 folder and set them on the d:\Test2 folder. First, I retrieve the permissions using Get-Acl, store them in the $permissions object, and set them using Set-Acl on the newly created D:\Test2 folder.
C:\Users\HarmVeenstra> (Get-Acl -Path D:\Test1).Access FileSystemRights : ReadAndExecute, Synchronize AccessControlType : Allow IdentityReference : Everyone IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None FileSystemRights : FullControl AccessControlType : Allow IdentityReference : NT AUTHORITY\SYSTEM IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None FileSystemRights : FullControl AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None C:\Users\HarmVeenstra> (Get-Acl -Path D:\Test2).Access FileSystemRights : FullControl AccessControlType : Allow IdentityReference : Everyone IsInherited : True InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None C:\Users\HarmVeenstra> $permissions=Get-Acl d:\Test1 C:\Users\HarmVeenstra> Set-Acl -Path D:\Test2\ -AclObject $permissions C:\Users\HarmVeenstra> (Get-Acl -Path D:\Test2).Access FileSystemRights : ReadAndExecute, Synchronize AccessControlType : Allow IdentityReference : Everyone IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None FileSystemRights : FullControl AccessControlType : Allow IdentityReference : NT AUTHORITY\SYSTEM IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None FileSystemRights : FullControl AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : ContainerInherit, ObjectInherit PropagationFlags : None
More (advanced) examples can be found here.
NTFSSecurity PowerShell module
You can also use the NTFSSecurity module (Install it using Install-Module -Name NTFSSecurity). This module is made and maintained by Raimund Andrée (https://github.com/raandree). This module contains the following cmdlets that you can use to view and set NTFS permissions.
Note: The module has not been updated in years, it still works but no bugfixes/improvements
Add-NTFSAccess Add-NTFSAudit Clear-NTFSAccess Clear-NTFSAudit Copy-Item2 Disable-NTFSAccessInheritance Disable-NTFSAuditInheritance Disable-Privileges Enable-NTFSAccessInheritance Enable-NTFSAuditInheritance Enable-Privileges Get-ChildItem2 Get-DiskSpace Get-FileHash2 Get-Item2 Get-NTFSAccess Get-NTFSAudit Get-NTFSEffectiveAccess Get-NTFSHardLink Get-NTFSInheritance Get-NTFSOrphanedAccess Get-NTFSOrphanedAudit Get-NTFSOwner Get-NTFSSecurityDescriptor Get-NTFSSimpleAccess Get-Privileges Move-Item2 New-NTFSHardLink New-NTFSSymbolicLink Remove-Item2 Remove-NTFSAccess Remove-NTFSAudit Set-NTFSInheritance Set-NTFSOwner Set-NTFSSecurityDescriptor Test-Path2
To show the permissions of a file or folder, you can use it like the example below:
C:\Users\HarmVeenstra> Get-NTFSAccess -Path c:\windows | Format-Table -AutoSize Path: c:\windows (Inheritance disabled) Account Access Rights Applies to Type IsInherited InheritedFrom ------- ------------- ---------- ---- ----------- ------------- CREATOR OWNER GenericAll SubfoldersAndFilesOnly Allow False NT AUTHORITY\SYSTEM GenericAll SubfoldersAndFilesOnly Allow False NT AUTHORITY\SYSTEM Modify, Synchronize ThisFolderOnly Allow False BUILTIN\Administrators GenericAll SubfoldersAndFilesOnly Allow False BUILTIN\Administrators Modify, Synchronize ThisFolderOnly Allow False BUILTIN\Users GenericExecute, GenericRead SubfoldersAndFilesOnly Allow False BUILTIN\Users ReadAndExecute, Synchronize ThisFolderOnly Allow False NT SERVICE\TrustedInstaller GenericAll SubfoldersOnly Allow False NT SERVICE\TrustedInstaller FullControl ThisFolderOnly Allow False APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES ReadAndExecute, Synchronize ThisFolderOnly Allow False APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES GenericExecute, GenericRead SubfoldersAndFilesOnly Allow False APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES ReadAndExecute, Synchronize ThisFolderOnly Allow False APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES GenericExecute, GenericRead SubfoldersAndFilesOnly Allow False
To set the permissions on a file or folder, you can use it like the example below: (Same as my Set-Acl example, copy NTFS permissions in an object and set it on the desired file or folder.
Note: Set-ACL copies the Inheritance flag by default. With the NTFSSecurity cmdlet, you will need to remove the Inheritance Flag first if needed (As I also did in the example below)
C:\Users\HarmVeenstra> Get-NTFSAccess -Path D:\Test1 Path: D:\Test1 (Inheritance disabled) Account Access Rights Applies to Type IsInherited InheritedFrom ------- ------------- ---------- ---- ----------- ------------- Everyone ReadAndExecute, Synchronize ThisFolderSubfoldersAndF… Allow False NT AUTHORITY\SYSTEM FullControl ThisFolderSubfoldersAndF… Allow False BUILTIN\Administrators FullControl ThisFolderSubfoldersAndF… Allow False C:\Users\HarmVeenstra> Get-NTFSAccess -Path D:\Test2 Path: D:\Test2 (Inheritance enabled) Account Access Rights Applies to Type IsInherited InheritedFrom ------- ------------- ---------- ---- ----------- ------------- Everyone FullControl ThisFolderSubfoldersAndF… Allow True D: C:\Users\HarmVeenstra> Disable-NTFSAccessInheritance d:\Test2 C:\Users\HarmVeenstra> Get-NTFSAccess -Path d:\test1 | Add-NTFSAccess D:\Test2 C:\Users\HarmVeenstra> Get-NTFSAccess -Path d:\Test2 Path: d:\Test2 (Inheritance disabled) Account Access Rights Applies to Type IsInherited InheritedFrom ------- ------------- ---------- ---- ----------- ------------- Everyone FullControl ThisFolderSubfoldersAndF… Allow False NT AUTHORITY\SYSTEM FullControl ThisFolderSubfoldersAndF… Allow False BUILTIN\Administrators FullControl ThisFolderSubfoldersAndF… Allow False
There is a site with good documentation about all the cmdlets of the NTFSecurity module, with excellent examples and detailed instructions. Go and check that out. I think the NTFSSecurity module is the thing you should use when setting (automated) permissions. More flexible than Get-Acl/Set-Acl IMHO 🙂
Thanks for this. I did a terabytes of filesystem permissions work last year as part of an enterprise divesture migration and found icacls is orders of magnitude faster than get-acl and set-acl. The pattern we used was to export the source permissions to a file with icacl, munge the file, and then import it on the target. It was crazy fast.
Icacls is much more low level I guess and performs better because of that perhaps, subinacl too. Should do a benchmark of that to see the difference 🤔
Any idea, how i can uncheck the „delete“ and check the box „delete only lower folders and Files“ in the advanced permissions?
“Allow on Subfolders and files only with Read&Execute/List Folder Contents/Read/Only apply these permissions on objects and/or containers within this container” rights?
Very very underrated PS Module. I use this almost daily has a system admin, but I did not know about “Note: Set-ACL copies the Inheritance flag by default. With the NTFSSecurity cmdlet, you will need to remove the Inheritance Flag first if needed (As I also did in the example below)”.
That’s some good info, most of the time I’m using the module to GET info on FileShares.
There are some really good PS scripts that I use made by others as well.
Great script, I use this when I’m wanting to audit a fileshare and see if permissions need to be set differently or AD groups cleaned up on the ACL’s.
https://github.com/seyo-IV/PowerShell/blob/master/Get-Effective-Permissions-EXCEL.ps1
Good article for the ntfs module.
https://zamarax.com/2020/07/01/how-to-manage-ntfs-permissions-with-powershell/
This is a work in progress, but I get sick of making AD groups for FileShares, so wanting to make a script that would make it easier for me.
Any feedback would be appreciated!!
“`ps
Function Create-NewFolderWithGroups {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[String]$FolderPath,
[Parameter(Mandatory = $true)]
[String]$FolderName
)
# Import the Active Directory module
Import-Module ActiveDirectory
# Import the NTFSSecurity module
Import-Module NTFSSecurity
# Combine the folder path and name to create the full folder path
$newFolderFull = Join-Path $FolderPath $FolderName
# Display the new folder path
Write-Output “New Folder will be: $newFolderFull”
# Prompt for confirmation
$confirm = Read-Host “Confirm? Y/N”
if ($confirm -ne “y”) {
# End the function if confirmation is not “y”
return
}
# Create AD Groups
$groupNameRW = “fs_$FolderName_RW”
$groupNameR = “fs_$FolderName_RO”
# Create the Read-Write group
New-ADGroup -Name $groupNameRW -SamAccountName $groupNameRW -GroupScope Universal -GroupCategory Security -Path “OU=NTFS Groups,DC=TR12R,DC=local”
$confirmReadOnly = Read-Host “Is a Read-Only Group Needed? Y/N”
if ($confirmReadOnly -eq “y”) {
# Create the Read-Only group if needed
New-ADGroup -Name $groupNameR -SamAccountName $groupNameR -GroupScope Universal -GroupCategory Security -Path “OU=NTFS Groups,DC=TR12R,DC=local”
}
# Add a delay to allow time for group replication
Start-Sleep -Seconds 15
# Create the folder
Write-Output “Add Folder..”
New-Item $newFolderFull -ItemType Directory
# Set rights and access control settings using NTFSSecurity module
$readOnly = “ReadAndExecute”
$readWrite = “Modify”
$userRW = “DOMAIN\$groupNameRW”
$userR = “DOMAIN\$groupNameR”
# Grant Read-Write access to the Read-Write group
Add-NTFSAccess -Path $newFolderFull -Account $userRW -AccessRights $readWrite -AppliesTo ThisFolderSubfoldersAndFiles
# Grant Read-Only access to the Read-Only group
Add-NTFSAccess -Path $newFolderFull -Account $userR -AccessRights $readOnly -AppliesTo ThisFolderSubfoldersAndFiles
}
# Usage example
Create-NewFolderWithGroups -FolderPath “C:\Path\To\Folder” -FolderName “NewFolder”
“`
Nice, thanks for the information and links! I will check your script later this week on a test vm, but first impression is good 👍
Justin,
I updated your script a little 😉 Renamed it to New-FolderWithGroups so that the naming is an approved verb and addedsome error handling and status output:
Function New-FolderWithGroups {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[String]$FolderPath,
}
Usage example
#New-FolderWithGroups -FolderPath ‘C:\Path\To\Folder’ -FolderName ‘NewFolder’