1. Overview
Some time ago, I was automating a few tasks with PowerShell and needed to set NTFS permissions on a folder. I was tempted to use the good old ICACLS.EXE command line, but I wanted to keep it all within PowerShell. While there are a number of different permissions you could want to set for a folder, my specific case called the following:
- Create a new folder
- Check the default permissions on the new folder
- Turn off inheritance on that folder, removing existing inherited permissions from the parent folder
- Grant “Full Control” permissions to Administrators, propagating via inheritance to files and subfolders
- Grant “Read” permissions to Users, propagating via inheritance to files and subfolders
- Review the permissions on the folder
2. The old ICACLS
In the old CMD.EXE world, you would use ICACLS.The commands would look like this:
- MD F:\Folder
- ICACLS F:\Folder
- ICACLS F:\Folder /INHERITANCE:R
- ICACLS F:\Folder /GRANT Administrators:(CI)(OI)F
- ICACLS F:\Folder /GRANT Users: (CI)(OI)R
- ICACLS F:\Folder
3. The PowerShell way
After some investigation, I found the PowerShell cmdlets to do the same things. You essentially rely on Get-Acl and Set-Acl to get, show and set permissions on a folder. Unfortunately, there are no cmdlets to help with the actual manipulation of the permissions. However, you can use a few .NET classes and methods to do the work. Here’s what I ended up with:
- New-Item F:\Folder –Type Directory
- Get-Acl F:\Folder | Format-List
- $acl = Get-Acl F:\Folder
- $acl.SetAccessRuleProtection($True, $False)
- $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
- $acl.AddAccessRule($rule)
- $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Users","Read", "ContainerInherit, ObjectInherit", "None", "Allow")
- $acl.AddAccessRule($rule)
- Set-Acl F:\Folder $acl
- Get-Acl F:\Folder | Format-List
4. Looking at the output
To show how this works, here’s the output you should get from those commands. Be sure to use the option to “Run as Administrator” if you’re creating a folder outside your user’s folders. Note that I made a few changes from the cmdlets shown previously. I also included couple of calls to the GetAccessRules method to get extra details about the permissions.
PS F:\> New-Item F:\Folder -Type Directory
Directory: F:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 11/6/2010 8:10 PM Folder
PS F:\> $acl = Get-Acl F:\Folder
PS F:\> $acl | Format-List
Path : Microsoft.PowerShell.Core\FileSystem::F:\Folder
Owner : BUILTIN\Administrators
Group : NORTHAMERICA\Domain Users
Access : BUILTIN\Administrators Allow FullControl
BUILTIN\Administrators Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
NT AUTHORITY\SYSTEM Allow 268435456
NT AUTHORITY\Authenticated Users Allow Modify, Synchronize
NT AUTHORITY\Authenticated Users Allow -536805376
BUILTIN\Users Allow ReadAndExecute, Synchronize
BUILTIN\Users Allow -1610612736
Audit :
Sddl : O:BAG:S-1-5-21-124525095-708259637-1543119021-513D:(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA)(A;ID;FA;;;SY)(A;OICIIOID
;GA;;;SY)(A;ID;0x1301bf;;;AU)(A;OICIIOID;SDGXGWGR;;;AU)(A;ID;0x1200a9;;;BU)(A;OICIIOID;GXGR;;;BU)
PS F:\> $acl.GetAccessRules($true, $true, [System.Security.Principal.NTAccount])
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : 268435456
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : InheritOnly
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : 268435456
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : InheritOnly
FileSystemRights : Modify, Synchronize
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : -536805376
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : InheritOnly
FileSystemRights : ReadAndExecute, Synchronize
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : -1610612736
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited : True
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : InheritOnly
PS F:\> $acl.SetAccessRuleProtection($True, $False)
PS F:\> $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
PS F:\> $acl.AddAccessRule($rule)
PS F:\> $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Users","Read", "ContainerInherit, ObjectInherit", "None", "Allow")
PS F:\> $acl.AddAccessRule($rule)
PS F:\> Set-Acl F:\Folder $acl
PS F:\> Get-Acl F:\Folder | Format-List
Path : Microsoft.PowerShell.Core\FileSystem::F:\Folder
Owner : BUILTIN\Administrators
Group : NORTHAMERICA\Domain Users
Access : BUILTIN\Administrators Allow FullControl
BUILTIN\Users Allow Read, Synchronize
Audit :
Sddl : O:BAG:S-1-5-21-124525095-708259637-1543119021-513D:PAI(A;OICI;FA;;;BA)(A;OICI;FR;;;BU)
PS F:\> (Get-Acl F:\Folder).GetAccessRules($true, $true, [System.Security.Principal.NTAccount])
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
FileSystemRights : Read, Synchronize
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
PS F:\>
5. Controlling parent folder inheritance
The script uses SetAccessRuleProtection, which is a method to control whether inheritance from the parent folder should be blocked ($True means no Inheritance) and if the previously inherited access rules should be preserved ($False means remove previously inherited permissions).
6. Building the access rules
To build a new access rule, the script also uses the New-Object cmdlet and specify the full name of the FileSystemAccessRule class. There are many constructors for this specific class of objects. I used one of the more complete ones, which takes 5 parameters:
- Identity (name of the user or group)
- Rights (including the common Read, Write, Modify and FullControl, among many others)
- Inheritance Flags (including None, ContainerInherit or ObjectInheritance)
- Propagation Flags (including None or InheritOnly, among others)
- Type (Allow or Deny)
I am using the .NET classes in this part, and that’s why you have to use the full name of the class (like System.Security.AccessControl.FileSystemAccessRule) and the full name of the data types (like [System.Security.Accesscontrol.InheritanceFlags]).
7. Using variables
The script also uses a few variables (names starting with a $ sign). In order to change the permissions, for instance, I started by copying the existing ACL to a variable called $acl using the Get-Acl cmdlet. Next, I modified $acl in memory and finally I applied the $acl back to the folder using Set-Acl cmdlet. You could avoid using the $rule variable, but your code would get a bit more complex. For instance, I could change the script shown previously to use only the $acl variable:
- $acl = Get-Acl F:\Folder
- $acl.SetAccessRuleProtection($True, $False)
- $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")))
- $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule("Users","Read", "ContainerInherit, ObjectInherit", "None", "Allow")))
- Set-Acl F:\Folder $acl
This does cut 2 lines from that section of the script. While I see of lot of fans of using a smaller number of command lines (even if they are longer command lines), I find the version that uses the additional $rule variable easier to understand.
8. Default permissions
You might have noticed that the initial attributes for the folder includes quite a few inherited permissions. Those are inherited from the parent folder F:\, and are the default permissions when you format an NTFS volume. Here are they in a nicely formatted table:
Identity |
Type |
Rights |
BUILTIN\Administrators |
Allow |
FullControl |
BUILTIN\Administrators |
Allow |
268435456 |
NT AUTHORITY\SYSTEM |
Allow |
FullControl |
NT AUTHORITY\SYSTEM |
Allow |
268435456 |
BUILTIN\Users |
Allow |
ReadAndExecute, Synchronize |
NT AUTHORITY\Authenticated Users |
Allow |
Modify, Synchronize |
NT AUTHORITY\Authenticated Users |
Allow |
-536805376 |
Some of the rights are fully spelled out (like “Full Control”, “Modify”, “Read”, “Write”, “Synchronize” and “ReadAndExecute”). More complex combinations are shown as numbers. The infrastructure only translates the numeric code into text for the most common ones.
9. Setting the Owner
Another fairly common operation is setting a new owner for a folder. This is useful when provisioning a folder for a specific user and wanting to give the user the ownership of the folder itself. It’s also handy if a administrator has been locked out of a folder. If I am the administrator, I can set the owner to myself and then grant myself permissions to access the folder. In CMD.EXE, you would use
- ICACLS F:\Folder /SETOWNER Administrators
The PowerShell equivalent would be:
- $acl = Get-Acl F:\Folder
- $acl.SetOwner([System.Security.Principal.NTAccount] "Administrators")
- Set-Acl F:\Folder $acl
10. It’s actually a Security Descriptor
The information returned by Get-Acl is actually better described as a “Security Descriptor”, not really an ACL (Access Control List). It contains a number of security-related information, including the Owner, the Group Owner, the Discretionary Access Control List (also known as DACL, which is where we added the two rules), the Audit Access Control List (also known as SACL). Technically, adding the two rules actually adds two ACEs (Access Control Entries) to the DACL (Discretionary Access Control List).
Also listed by Get-ACL is SDDL string. The SDDL a string that combines all the information returned by Get-Acl in a single string. It’s a bit hard to parse for humans, but it’s closer to the internal representation.
11. Looking at the other methods
There are a number of additional methods available to handle the Security Descriptor returned by Get-Acl. If you want to look into them, just pipe the output to Get-Member. See the example below:
PS F:\> Get-Acl F:\Folder | Get-Member
TypeName: System.Security.AccessControl.DirectorySecurity
Name MemberType Definition
---- ---------- ----------
Access CodeProperty System.Security.AccessControl.AuthorizationRuleCollection Access{get=...
Group CodeProperty System.String Group{get=GetGroup;}
Owner CodeProperty System.String Owner{get=GetOwner;}
Path CodeProperty System.String Path{get=GetPath;}
Sddl CodeProperty System.String Sddl{get=GetSddl;}
AccessRuleFactory Method System.Security.AccessControl.AccessRule AccessRuleFactory(System.Sec...
AddAccessRule Method System.Void AddAccessRule(System.Security.AccessControl.FileSystemAcc...
AddAuditRule Method System.Void AddAuditRule(System.Security.AccessControl.FileSystemAudi...
AuditRuleFactory Method System.Security.AccessControl.AuditRule AuditRuleFactory(System.Secur...
Equals Method bool Equals(System.Object obj)
GetAccessRules Method System.Security.AccessControl.AuthorizationRuleCollection GetAccessRu...
GetAuditRules Method System.Security.AccessControl.AuthorizationRuleCollection GetAuditRul...
GetGroup Method System.Security.Principal.IdentityReference GetGroup(type targetType)
GetHashCode Method int GetHashCode()
GetOwner Method System.Security.Principal.IdentityReference GetOwner(type targetType)
GetSecurityDescriptorBinaryForm Method byte[] GetSecurityDescriptorBinaryForm()
GetSecurityDescriptorSddlForm Method string GetSecurityDescriptorSddlForm(System.Security.AccessControl.Ac...
GetType Method type GetType()
ModifyAccessRule Method bool ModifyAccessRule(System.Security.AccessControl.AccessControlModi...
ModifyAuditRule Method bool ModifyAuditRule(System.Security.AccessControl.AccessControlModif...
PurgeAccessRules Method System.Void PurgeAccessRules(System.Security.Principal.IdentityRefere...
PurgeAuditRules Method System.Void PurgeAuditRules(System.Security.Principal.IdentityReferen...
RemoveAccessRule Method bool RemoveAccessRule(System.Security.AccessControl.FileSystemAccessR...
RemoveAccessRuleAll Method System.Void RemoveAccessRuleAll(System.Security.AccessControl.FileSys...
RemoveAccessRuleSpecific Method System.Void RemoveAccessRuleSpecific(System.Security.AccessControl.Fi...
RemoveAuditRule Method bool RemoveAuditRule(System.Security.AccessControl.FileSystemAuditRul...
RemoveAuditRuleAll Method System.Void RemoveAuditRuleAll(System.Security.AccessControl.FileSyst...
RemoveAuditRuleSpecific Method System.Void RemoveAuditRuleSpecific(System.Security.AccessControl.Fil...
ResetAccessRule Method System.Void ResetAccessRule(System.Security.AccessControl.FileSystemA...
SetAccessRule Method System.Void SetAccessRule(System.Security.AccessControl.FileSystemAcc...
SetAccessRuleProtection Method System.Void SetAccessRuleProtection(bool isProtected, bool preserveIn...
SetAuditRule Method System.Void SetAuditRule(System.Security.AccessControl.FileSystemAudi...
SetAuditRuleProtection Method System.Void SetAuditRuleProtection(bool isProtected, bool preserveInh...
SetGroup Method System.Void SetGroup(System.Security.Principal.IdentityReference iden...
SetOwner Method System.Void SetOwner(System.Security.Principal.IdentityReference iden...
SetSecurityDescriptorBinaryForm Method System.Void SetSecurityDescriptorBinaryForm(byte[] binaryForm), Syste...
SetSecurityDescriptorSddlForm Method System.Void SetSecurityDescriptorSddlForm(string sddlForm), System.Vo...
ToString Method string ToString()
PSChildName NoteProperty System.String PSChildName=test
PSDrive NoteProperty System.Management.Automation.PSDriveInfo PSDrive=C
PSParentPath NoteProperty System.String PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\
PSPath NoteProperty System.String PSPath=Microsoft.PowerShell.Core\FileSystem::C:\test
PSProvider NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft.PowerS...
AccessRightType Property System.Type AccessRightType {get;}
AccessRuleType Property System.Type AccessRuleType {get;}
AreAccessRulesCanonical Property System.Boolean AreAccessRulesCanonical {get;}
AreAccessRulesProtected Property System.Boolean AreAccessRulesProtected {get;}
AreAuditRulesCanonical Property System.Boolean AreAuditRulesCanonical {get;}
AreAuditRulesProtected Property System.Boolean AreAuditRulesProtected {get;}
AuditRuleType Property System.Type AuditRuleType {get;}
AccessToString ScriptProperty System.Object AccessToString {get=$toString = "";...
AuditToString ScriptProperty System.Object AuditToString {get=$toString = "";...
To find the specific parameters for a given method, just filter the output and pipe it to Format-List. For instance, here are the details about the GetAccessRules method used in the script:
PS F:\> Get-Acl F:\Folder | Get-Member -MemberType Method "GetAccessRules" | Format-List
TypeName : System.Security.AccessControl.DirectorySecurity
Name : GetAccessRules
MemberType : Method
Definition : System.Security.AccessControl.AuthorizationRuleCollection GetAccessRules(bool includeExplicit, bool includ
eInherited, type targetType)
Here’s a short version, this time looking at the definition for the SetAccessRuleProtection method:
PS F:\> Get-Acl F:\Folder | Get-Member "SetAccessRuleProtection" | FL
TypeName : System.Security.AccessControl.DirectorySecurity
Name : SetAccessRuleProtection
MemberType : Method
Definition : System.Void SetAccessRuleProtection(bool isProtected, bool preserveInheritance)
12. Conclusion
I hope this helped you understand how to manipulate Security Descriptors and Access Control Lists using PowerShell. ACLs are used in several other places, like Registry entries, Active Directory objects and File Shares. I’m sure that adding these abilities to your PowerShell tool belt will eventually come in handy.
As usual, the MSDN site is a great reference. You can find all the details about the methods I used here by searching for the method name on MSDN. You can also look at an overview of the methods related to Security Descriptors (with lots of links) at: http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.aspx.
Also be sure to check my other blog posts about PowerShell athttp://blogs.technet.com/b/josebda/archive/tags/powershell/.
FROM:http://blogs.technet.com/b/josebda/archive/2010/11/12/how-to-handle-ntfs-folder-permissions-security-descriptors-and-acls-in-powershell.aspx
NTFS权限设置