Setting ACL on a File or Directory in Powershell
I know I said I was going to do more C# stuff but this powershell stuff is so cool 🙂 . If you ever have to do a massive task like set security across multiple servers on a particular Folder or Files you certainly do not want to do this manually . You can do this in a lot languages . In regular batch scripting using calcs.exe or vbcript . Today I’m going to give a powershell example using 2 cmdlets get-acl and set-acl.
So for example you had to set security on a folder c:\temp (not sure why you would want to but its just an example ) .
what you first have to do is get the ACL list from the folder like so :
$acl = Get-Acl c:\temp
next you can setup your account name that you want to add , Set the permission level (i.e. FullControl) and lastly set the allow permission or deny permission set .Lets take a look .
$permission = "domainName\Username","FullControl","Allow"
So now we use $permission in our .net class FileSystemAccessRule like so :
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission
We instantiated to use the .net class and passed our variable to set our permisson but we have not set it yet .
$acl.SetAccessRule($accessRule)
$acl | Set-Acl c:\temp
Now we did . Now check your folder and it should show full control for the username you specified .
Cool huh ?
I know this may not replace a cacls.exe but it will do the job also this cmdlet (set-acl) will work on the registry provider too which calcs.exe doesn’t do .
Full program
$acl = Get-Acl c:\temp
$permission = "domain\user","FullControl","Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl c:\temp
Hope this helps .
Chris
Ben Zass-Bangham 8:58 am on February 27, 2008 Permalink
Superb, thanks for this. Just what I needed for my world domination script (provisioning new customers in a highly segregated terminal server hosting environment)
Faris 8:09 am on May 24, 2008 Permalink
Super
But IS there a way to make this apply on a Subfolder and files
Thanks
Chris 3:32 am on May 25, 2008 Permalink
Hi Faris ,
I believe you would have to use SetAccessRuleProtection something like this ($acl.SetAccessRuleProtection($true,$true)
I haven’t confirmed though . I will look into it .
Thanks
Chris
Axel Bøg Andersen 2:13 pm on March 6, 2009 Permalink
You need a different constructor. This sets the inheritanceflag:
$acl = get-acl -path “D:\Folder\test”
$new = “Local\User”,”FullControl”,”ContainerInherit,ObjectInherit”,”None”,”Allow”
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $new
$acl.SetAccessRule($accessRule)
$acl | Set-Acl “D:\Folder\test”
adrian 7:10 am on March 18, 2009 Permalink
and how can i add multiple users with different rights?
user1 with full controll and user2 with modify?
thanks for some inputs.
Craig 4:01 pm on July 8, 2009 Permalink
Couldn’t get this to work. Getting this error:
Set-Acl : The security identifier is not allowed to be the owner of this object.
Marquis Calmes 2:47 pm on July 8, 2011 Permalink
Craig, Try running it against a UNC path. For example, \\servername\d$\Folder\test
See this post on my blog for more.
http://fixingit.wordpress.com/2011/07/08/set-owner-with-powershell-%e2%80%9cthe-security-identifier-is-not-allowed-to-be-the-owner-of-this-object%e2%80%9d/
Mike 5:00 pm on August 9, 2011 Permalink
I spent all day trying to get permissions on a registry key that I didn’t already have. This particular key’s owner is “administrators”, however the administrators group has read only access to this particular key. Thus when you’d run the script, you’d get access denied even though being the owner should prevent this. So here’s how I worked around the issue:
Regini.exe (built into windows 7) can change permissions on the key, but it’s very limited as to which groups it can assign permissions to. So using powershell, I save the current ACL on the key, use regini.exe to give administrators full control, then use powershell to restore the permissions with the additions that I want.
#powershell only has drives defined for HKLM and HKCU. The other drives like Classes Root need to be defined like this.
new-psdrive -name HKCR -psprovider registry -root HKEY_CLASSES_ROOT
#A string holding the path of the registry key. For some reason it doesn’t like the curly braces if you combine this and the next command without a variable
$regkey = “HKCR:\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder”
#get the original key’s permissions
$acl = get-acl $regkey
#set the parameters of the acl that I want set
$person = [System.Security.Principal.NTAccount]”BUILTIN\ADMINISTRATORS”
$access = [System.Security.AccessControl.RegistryRights]”FullControl”
$inheritance = [System.Security.AccessControl.InheritanceFlags]”ContainerInherit”
$propagation = [System.Security.AccessControl.PropagationFlags]”None”
$type = [System.Security.AccessControl.AccessControlType]”Allow”
#create the accessrule object based on the previous parameters.
$accessRule = New-Object System.Security.AccessControl.RegistryAccessRule($person,$access,$inheritance,$propagation,$type)
#add the new access rule to the existing ACL so that the inherited permissions are still there.
$acl.AddAccessRule($accessRule)
#user regini to grant administrators full control to this key.
regini.exe c:\regini\test.ini
#put the edited acl back in place now that we have full control of this key.
Set-acl $regkey -aclobject $acl
********contents of c:\regini\test.ini The [1] including brackets tells it to give administrators full control.
HKEY_CLASSES_ROOT\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder [1]
Camille 2:55 am on October 12, 2011 Permalink
I wrote a post on the different possibilities for the permission level string, side by side with the well-know GUI.
I think it’s a nice addition to this post 🙂
Here it goes: http://camillelemouellic.blog.com/2011/07/22/powershell-security-descriptors-inheritance-and-propagation-flag-possibilities/
How to create a folder in SharePoint2010 root folder and set permission to it « YBBEST 5:31 am on March 14, 2012 Permalink
[…] https://chrisfederico.wordpress.com/2008/02/01/setting-acl-on-a-file-or-directory-in-powershell/ […]
Keenan 1:56 pm on June 18, 2013 Permalink
I am trying to gain access to a registry key. I can gain access manually by checking the “Repalce owner on subcontainers and objects” box in the advanced tab under owner tab in permissions. I would like to be able to “check” this box by utilizing script because I have to make a registry change on many computers. Most of them are currently running Vista. Any help would be appreciated.
Chris 8:28 pm on June 18, 2013 Permalink
Hi Keenan
I would use the .net method for changing permissions . When I’m changing keys or adding keys in the registry I use the plan old reg command (reg /?) combined with powershell .
See if this can help : (You can put the following script in a script.ps1 file then execute it with the invoke-command against a lot of machines.)
$acl = Get-Acl HKLM:\SOFTWARE\whatever
$rule = New-Object System.Security.AccessControl.RegistryAccessRule (“domain\Username”,”FullControl”,”ContainerInherit,ObjectInherit”,”None”,”Allow”
$acl.SetAccessRule($rule)
$acl |Set-Acl -Path HKLM:\SOFTWARE\whatever
Try this on a test machine
Keenan 3:32 pm on June 19, 2013 Permalink
Hi Chris,
Thanks for your help. I had a similar instance of that code already but was having some troubles, you straightened that out. I am still having access control problems. Any ideas?
[string] $RegistryPath = “Software\odbc\odbcinst.ini\SQL Server”
[string] $RegistryKeyName = “CPTimeout”
[string] $RegistryValue = “”
[string] $RegistryType = “dword”
$acl = Get-Acl ‘HKLM:\SOFTWARE\odbc\odbcinst.ini\SQL Server’
$permission = “Administrator”,”FullControl”,”Allow”
$rule = New-Object System.Security.AccessControl.RegistryAccessRule $permission
$acl.SetAccessRule($rule)
$acl |Set-Acl -Path ‘HKLM:\SOFTWARE\odbc\odbcinst.ini\SQL Server’
VALIDATE REG VALUE
Write-output “Connecting to $Computer for registry Check `r ”
$Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘LocalMachine’, $Computer)
$RegistryKey = $Registry.opensubkey($RegistryPath,$False) ## $False = ReadOnly
$RegistryKeyValue = $RegistryKey.getvalue($RegistryKeyName)
IF ($RegistryKeyValue -eq $RegistryValue) { $RegKeyValueSet = $True ; Write-Output “Registry key
on $Computer is already set ($RegistryKeyName has a value of $RegistryKeyValue) `r ” }
MODIFY VALUE
Write-output “Connecting to $Computer for registry modification `r ”
$Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘LocalMachine’, $Computer)
$RegistryKey = $Registry.opensubkey($RegistryPath,$true) ## $True = Write
$RegistryKeyValue = $RegistryKey.getvalue($RegistryKeyName)
$RegistryKey.SetValue($RegistryKeyName,$RegistryValue)
Write-output “Value has been changed to $RegistryValue.”
I keep getting this error:
Exception calling “OpenSubKey” with “2” argument(s): “Requested registry access is not allowed.”
At I:\RegKeyChange.ps1:23 char:36
+ $RegistryKey = $Registry.opensubkey <<<< ($RegistryPath,$true) ## $True = Write
Exception calling "SetValue" with "2" argument(s): "Cannot write to the registry key."
At I:\RegKeyChange.ps1:25 char:22
+ $RegistryKey.SetValue <<<< ($RegistryKeyName,$RegistryValue)
Thanks a bunch,
Keenan
Chris 8:33 pm on June 19, 2013 Permalink
I think because the remote registry service is not started . I think its set to manual by default ?
Also make sure in your permission variable that you have this
$permission = “Administrator”,”FullControl”,”ContainerInherit,ObjectInherit”,”None”,”Allow”
See if that helps …
Keenan 8:04 am on June 20, 2013 Permalink
That service is started and set to automatic on my computer as well as the one I am testing this script on. It still says registry access is not allowed. I may just have to manually make the change on each computer. Thanks for all your help, if you have any other ideas, I would be glad to hear.
Thanks!
Keenan 8:26 am on June 20, 2013 Permalink
Will that acl code allow me to change the owner of the key? It is set by default to ‘TrustedInstaller’ and I need to change the owner to Administrators; this is in addition to changing the permissions for admin to full control.
Thanks.
Chris 7:11 pm on June 20, 2013 Permalink
Hi Keenan … you might be getting access denied because of the ownership . I’m sorry I havn’t worked with permissions in the registry much but there is a cool utility called subinacl
Google it and download it and you can work it into your powershell script
Here is an example of the syntax :
subinacl /keyreg HKEY_CLASSES_ROOT /setowner=###
Hope this helps ..
Chris
Keenan 2:05 pm on June 21, 2013 Permalink
I will give it a try, thanks.
Benajmin 3:26 am on August 7, 2013 Permalink
Goddammit…
Many Thanks, the only Example which works in the whole internet…
Baarrr Thank you very much.
How to connect Home Folder using PowerShell - Just just easy answers 11:22 am on September 6, 2013 Permalink
[…] https://chrisfederico.wordpress.com/2008/02/01/setting-acl-on-a-file-or-directory-in-powershell/ […]
Matt 4:46 am on December 16, 2015 Permalink
Is it just me, or is this not cool at all? Not the article (thanks for the info), I mean powershell vs windows gui, cmd, bash, etc – this is extremely long winded. 5 lines, 3 variables, and 220 words to do what with xcacls.exe is a simple, single line. I’m a big fan of the scope and power of powershell (appropriately titled) but on many occasions it seems to make simple tasks unnecessarily complicated.