tags:
Contents
Overview
Changing NTFS permissions with PowerShell saves a lot of time when you need to make changes to a large group of files or when it is required as part of a larger automation project. This article should help you understand everything you need to know to manipulate security permissions with PowerShell.
When changing ownership of files or folders you must run PowerShell as an Administrator. Everything here will work in Windows PowerShell 5, but not PowerShell 6 as of this writing – specifically, the SetAccessControl() method does not exist in PowerShell 6.
Viewing ACL
We are going to use the Get-Acl
cmdlet to view the current ACL. Running it in PowerShell will give the following output.
PS C:\Users\larntz\Documents> Get-Acl .\Directory\ | Format-List
Path : Microsoft.PowerShell.Core\FileSystem::C:\Users\Administrator\Documents\Directory\
Owner : WIN-UBFNHEQ8GII\Administrator
Group : WIN-UBFNHEQ8GII\None
Access : NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
WIN-UBFNHEQ8GII\Administrator Allow FullControl
Audit :
Sddl : O:LAG:S-1-5-21-3514988389-1168544693-1271638760-513D:AI(A;OICIID;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;LA)
Our primary focus in this article will be on the Owner and Access objects. We can see from this example that WIN-UBFNHEQ8GII\Administrator
is the owner and we have three Access rules granting FullControl.
Ownership Details
Ownership is pretty simple. Ownership is assigned to one user or group and there are no additional details.
PS C:\Users\larntz\Documents> (Get-Acl .\Directory\).Owner
WIN-UBFNHEQ8GII\Administrator
Access Right Details
We can see a more detailed description of the access rules by selecting them specifically using this command (Get-Acl .\Directory\).Access
. Now we can see which permissions were inherited and the InheritanceFlags and PropagationFlags. These latter two will be important when we start modifying rules.
PS C:\Users\larntz\Documents> (Get-Acl .\Directory\).Access
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : WIN-UBFNHEQ8GII\Administrator
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
Modifying ACL
Before we can set an object’s ACL we need to build one. The easiest way to do that is to save the current ACL in a variable and then modify it. To do that we’ll just assing the output of Get-Acl
to $acl
.
PS C:\Users\larntz\Documents> $acl = Get-Acl .\Directory\
Another option would be to create a completely new, and empty, ACL object like this:
PS C:\Users\larntz\Documents> $acl = New-Object System.Security.AccessControl.DirectorySecurity
Now that we have our ACl object we can make modifications. Once we’ve made the desired changes we have to apply it back to the directory or our changes will be lost.
Setting Ownership
Setting the owner in the ACL is almost as simple as viewing it. We will use the SetOwner()
method on the ACL. This method takes one argument of type System.Security.Principal.NTAccount
so first we need to create an object of that type and then we can set the owner.
However, there are two limitations when setting ownership via PowerShell.
- We need to be running powershell as Administrator.
- We can only set the owner to the user currently running PowerShell or
BUILTIN\Administrators
.
PS C:\Users\larntz\Documents> $owner = New-Object System.Security.Principal.NTAccount("BUILTIN\Administrators")
PS C:\Users\larntz\Documents> $acl.SetOwner($owner)
Remember, we haven’t changed anything on the filesystem yet. We’ve only modified our $acl
object.
Inheritance Flags
When creating access rules we will want to specify inheritance flags also. When doing so we have four options. You will most likely want to set both the ContainerInheritance
and the ObjectInheritance
flags. This indicates that we want our permission to be propagated to all child directories and files.
Inheritance Flag | Meaning |
---|---|
ContainerInherit | Propagate to child containers (directories). |
None | Do not propagate this permission to any child containers or objects. |
ObjectInherit | Propagate to child objects (files). |
Propagation Flags
In addtion to Inheritance Flags we can also set Propagation Flags. The default Windows behavior is None
. See the table below for more detail on the three Propagation Flag options. Setting this flag to InheritOnly
will cause the access rule to only apply to child objects of the container.
Propagation Flag | Meaning |
---|---|
InheritOnly | Specifies that the ACE is propagated only to child objects. This includes both container and leaf child objects. |
None | Specifies that no inheritance flags are set. |
NoPropagateInherit | Specifies that the ACE is not propagated to child objects. |
Flag Combinations and Effect
The table below details how a rule will be apply to the current object and child objects based on the flags set in the access rule.
Access Rule Applies To | Inheritance Flags | Propagation Flags |
---|---|---|
Subfolders and Files only | ContainerInherit,ObjectInherit | InheritOnly |
This Folder, Subfolders and Files | ContainerInherit,ObjectInherit | None |
This Folder, Subfolders and Files | ContainerInherit,ObjectInherit | NoPropagateInherit |
This folder and Subfolders | ContainerInherit | None |
Subfolders only | ContainerInherit | InheritOnly |
This Folder and Files | ObjectInherit | None |
This Folder and Files | ObjectInherit | NoPropagateInherit |
This Folder only | None | None |
Access Control Types
There are only two access control types. Allow
and Deny
. Allow means we are allowing the permission, e.g., we are allowing a user to write to this directly. Deny will specifically deny a right, and takes precedence over Allow permissions. So, if a user has a Modify/Allow entry and also a Read/Deny that user will have all Modify rights except read.
Be sure to verify a principal’s effective access when using Deny
types.
Basic Permissions
When we talk about basic permissions we are talking about the primary checkboxes available when looking at the security tab in a file system object’s Properties dialog.
Here is a table of basic permissions that can be set via PowerShell, and the rights each will grant.
Permission | Rights Granted |
---|---|
FullControl | Specifies the right to exert full control over a folder or file, and to modify access control and audit rules. This value represents the right to do anything with a file and is the combination of all rights in this enumeration. |
Modify | Specifies the right to read, write, list folder contents, delete folders and files, and run application files. This right includes the ReadAndExecute right, the Write right, and the Delete right. |
ReadAndExecute | Specifies the right to open and copy folders or files as read-only, and to run application files. This right includes the Read right and the ExecuteFile right. |
Read | Specifies the right to open and copy folders or files as read-only. This right includes the ReadData right, ReadExtendedAttributes right, ReadAttributesright, and ReadPermissions right. |
Write | Specifies the right to create folders and files, and to add or remove data from files. This right includes the WriteData right, AppendData right, WriteExtendedAttributes right, and WriteAttributes right. |
Note that List folder contents
is not in the table above. While this can be set via PowerShell it will show up under Special permissions as List folder / read data
.
Adding Basic Permissions
To add new rights to a folder we will need to first create a file system rule, and then we can add it to our current set of $acl
. There are two methods we can use to either add or set a rule.
SetAccessRule() vs AddAccessRule()
The first method is SetAccessRule()
. When using SetAccessRule()
our new rule will overwrite any existing rule of the same type (Allow or Deny) for that security principal (user or group) regardless of the existing permissions. If a user has Modify permission and a new rule is created using SetAccessRule()
specifying Read permission that user will now only have Read permission. This method essentially removes any existing access an replaces that access with the specified rule.
The second method is AddAccessRule()
. This method will add this access rule to the ACL. Here if a user has Modify permission and we use AddAccessRule()
to create a new rule with Read permission the user will still have Modify permissions. This can be dangerous from a security perspective if we think we intend to limit a user’s access, but mistakenly use the AddAccessRule()
method.
My suggestion is always use SetAccessRule()
and specify all intended permissions when making ACL changes.
Creating A New FileSystem Access Rule
Now that we understand inheritance flags, basic permissions, and the methods used to add a rule to our $acl
we are ready to create a new filesystem rule. This is a two step process. First we create our rule, and then we will apply it to our $acl
object.
Here’s what we need to create the rule.
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\larntz","Write","ContainerInherit,ObjectInherit","None","Allow")
The code block above creates a new object of type System.Security.AccessControl.FileSystemAccessRule
with the following parameters:
Parameter | Value |
---|---|
identity | DOMAIN\larntz |
fileSystemRights | Write |
inheritanceFlags | ContainerInherit,ObjectInherit |
propagationFlags | None |
type | Allow |
After creating the rule we can apply it to our $acl
object using the SetAccessRule()
method.
$acl.SetAccessRule($rule)
Again, we haven’t modified the filesystem yet. We’ve only modified our $acl
object. Next let’s look at how to apply our $acl
object to a filesystem object.
Removing A FileSystem Access Rule
To remove an existing access rule you should use the RemoveAccessRule()
method. This is very straightfoward once you understand how to create an access rule. To remove a rule it must already be part of the $acl
object. Generally you would loop through these to find the rule you wanted and assign it to a variable. Then you can call $acl.RemoveAccessRule($rule)
to remove the rule from the $acl
object.
Here is a simple example to illustrate. This example demonstrates create an ACL object, create a rule, listing the access rules in our ACL object, and then removing the access rule from the ACL object.
PS C:\Users\larntz\Documents> $acl = New-Object System.Security.AccessControl.DirectorySecurity
PS C:\Users\larntz\Documents> $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\larntz","Read,CreateFiles","ContainerInherit,ObjectInherit","None","Allow")
PS C:\Users\larntz\Documents> $acl.SetAccessRule($rule)
PS C:\Users\larntz\Documents> $acl.Access
FileSystemRights : CreateFiles, Read, Synchronize
AccessControlType : Allow
IdentityReference : DOMAIN\larntz
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
PS C:\Users\larntz\Documents> $acl.RemoveAccessRule($rule)
True
PS C:\Users\larntz\Documents> $acl.Access
PS C:\Users\larntz\Documents>
Saving the ACL Changes
To avoid a bug in Set-Acl
we will be using the SetAccessControl()
method to save our permissions. If we need to be compatible with PowerShell 6 we must use Set-Acl
, but you may experience odd behavior after using it and from personal experience I don’t recommend using Set-Acl
.
What we are going to do instead is use the SetAccessControl()
method of the DirectoryInfo
class to apply our ACL.
To do this we can use Get-Item and then call SetAccessControl()
on the returned object.
(Get-Item .\Directory\ChildDirectory\).SetAccessControl($acl)
Putting all the steps together we can get or create an ACL object, add a rule, and apply that rule to a file system object. The code block below shows all three steps together.
PS C:\Users\larntz\Documents> $acl = Get-Acl .\Directory\
PS C:\Users\larntz\Documents> $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\larntz","Write","ContainerInherit,ObjectInherit","None","Allow")
PS C:\Users\larntz\Documents> $acl.SetAccessRule($rule)
Special Permissions
A basic right such as Modify can be thought of as a group of special permissions. Special permissions are more detailed rights that can be assigned rather than using the pre-defined basic rights groups. For instance, if you want to allow a principal to create files, but not directories that can be accomplished using special rights. These type permissions are only viewable in the GUI via the Advanced button on the Security tab.
At first, it may take some experimentation to get the desired rights when dealing with advanced permissions. Be sure to test these settings thoroughly to be sure everything behaves as intended.
Now, using the example above let’s grant a user Read
and CreateFiles
permission only. This will allow a user to read the directory tree and files, but only allow them to paste new files into the folders. As you can see in the table below the CreateFiles
permission does not grant AppendData
which is needed to change data in an existing file. Also, once the user creates/moves a file into this directory they will be unable to delete it.
PS C:\Users\larntz\Documents> $acl = get-acl .\Directory\
PS C:\Users\larntz\Documents> $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\larntz","Read,CreateFiles","ContainerInherit,ObjectInherit","None","Allow")
PS C:\Users\larntz\Documents> $acl.SetAccessRule($rule)
PS C:\Users\larntz\Documents> (Get-Item .\Directory\).SetAccessControl($acl)
PS C:\Users\larntz\Documents> (Get-Acl .\Directory\).Access
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
FileSystemRights : CreateFiles, Read, Synchronize
AccessControlType : Allow
IdentityReference : DOMAIN\larntz
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
Table of Special Permissions
Permission | Rights Granted |
---|---|
AppendData | Specifies the right to append data to the end of a file. |
ChangePermissions | Specifies the right to change the security and audit rules associated with a file or folder. |
CreateDirectories | Specifies the right to create a folder. |
CreateFiles | Specifies the right to create a file. |
Delete | Specifies the right to delete a folder or file. |
DeleteSubdirectoriesAndFiles | Specifies the right to delete a folder and any files contained within that folder. |
ExecuteFile | Specifies the right to run an application file. |
ListDirectory | Specifies the right to read the contents of a directory. |
ReadAttributes | Specifies the right to open and copy file system attributes from a folder or file. For example, this value specifies the right to view the file creation or modified date. This does not include the right to read data, extended file system attributes, or access and audit rules. |
ReadData | Specifies the right to open and copy a file or folder. This does not include the right to read file system attributes, extended file system attributes, or access and audit rules. |
ReadExtendedAttributes | Specifies the right to open and copy extended file system attributes from a folder or file. For example, this value specifies the right to view author and content information. This does not include the right to read data, file system attributes, or access and audit rules. |
ReadPermissions | Specifies the right to open and copy access and audit rules from a folder or file. This does not include the right to read data, file system attributes, and extended file system attributes. |
Synchronize | Specifies whether the application can wait for a file handle to synchronize with the completion of an I/O operation. |
TakeOwnership | Specifies the right to change the owner of a folder or file. Note that owners of a resource have full access to that resource. |
Traverse | Specifies the right to list the contents of a folder and to run applications contained within that folder. |
WriteAttributes | Specifies the right to open and write file system attributes to a folder or file. This does not include the ability to write data, extended attributes, or access and audit rules. |
WriteData | Specifies the right to open and write to a file or folder. This does not include the right to open and write file system attributes, extended file system attributes, or access and audit rules. |
WriteExtendedAttributes | Specifies the right to open and write extended file system attributes to a folder or file. This does not include the ability to write data, attributes, or access and audit rules. |
Conclusion
That covers the building blocks of modifying NTFS permissions with powershell. I would love feed back so please feel free to send questions, corrections, or general comments about the article to larntz+ntfssecposh@gmail.com.
References
Microsoft Docs
Related Articles
- List AD group members when the group contains foreign security principals
- How to do an offline install of remote server administration tools (RSAT) on Windows Server and Windows 10
- Powercli Script to Unmount and Detach Datastores
- Automatically Load Custom PowerShell Functions
- Outlook 2016’s Funky Portrait Orientation