Setting file ACLs via PowerShell

Yesterday I ran WireShark at work with my admin account and saved the results to a file. Later I moved that file (as my admin account) to the desktop of my regular account so I could email it to someone. But as you know moving has the effect that the original permissions are retained so even though the file was now in my regular Desktop I as a regular user couldn’t access it.

Running Explorer as an administrator doesn’t help either. Because of UAC when I right click Explorer and do “Run as administrator” it still runs as me but in an elevated context. This is an Explorer specific quirk. So unless I were to logout and login as my admin account, there seemed to be no way of changing the file ACLs to give my regular account permissions.

But of course there are ways. PowerShell was my first choice (coz I knew it had a Set-ACL cmdlet) but I wasn’t sure how to assign permissions using PowerShell. A quick web search got me to this blog post that summarizes what needs to be done. Up shot of the matter is you do something along these lines:

What you do here is that first you store the current ACLs of the file into a variable. Then you create a new ACE object with the permissions you want. Add that to the previous variable and assign the new ACL to the file.

While the above is useful, it would be good if I could just copy the ACLs from a file with ACEs I like to the file I want to modify. Something like this:

This doesn’t work though.

If I run this in a PowerShell session under my regular account it fails (obviously):

But if I run this under my admin account, then too it fails (though for not an obvious reason):

This is because by default Set-ACL also tries to set the owner ACE, and since the owner is different from the user account under which Set-ACL is running it gives an error. In Windows you can’t assign someone else as an owner unless you have a privilege for doing that (the SeRestorePrivilege privilege, see this MSDN page). All you can do is grant someone a Take Ownership permission and then they have to take ownership. (See this forum post for more info. Another forum post gives a workaround. Also, this blog post from Lee Holmes is useful in the context of the second forum post).

So a simple copy-paste is out of the question …

I still might be able to fix this easily though. Remember the reason the file (in my case) has a different set of permissions is because its ACEs are protected from inheritance. If I had copied the file over instead of moving, then permissions won’t be protected and inheritance would have kicked in. But since I moved the file here its permissions are protected. I can confirm this via Get-ACL too:

So all I need to do here is remove protection. That can be done via the SetAccessRuleProtection method. This takes two parameters – the first determines whether protection is enabled ($true) or not ($false). The second is ignored if protection is disabled; but if protection is enabled then it determines whether the inherited rules are kept ($true) or discarded ($false) . Thus, in my case, all I need to do is the following:

After this the file has both the original ACEs as well as the ones inherited from my home folder (notice the last three rules in the list below):

Now I can just copy the ACLs from another file – with PowerShell running under my account – as I had tried earlier. This is optional, I did it so the permissions are consistent with others.

While on Set-ACL the following snippet too might be useful:

This takes the ACLs from an existing file and adds these to the file I want. Again, this only works if you already have permissions on the file – in case above, I could do this after I have turned off protection.

While on PowerShell and ACLs its worth pointing to this Tip post. That’s where I first learnt about PowerShell and ACLs though I admit I have forgotten most of what I learnt from lack of use. This blog post which I came across today is a good read too. I came across it while searching for how to enable inheritance.

Apart from PowerShell there are other commands which can set/ get ACLs. One of these is ICACLS, which is present in Windows Vista/ Server 2003 SP2 and upwards.

Interestingly ICACLS seems to be able to set the owner to another account even though PowerShell fails. Not sure why that succeeds …

ICACLS can also easily reset the ACLs with inherited ones (i.e. like the PowerShell above it disables protection but also replaces the non-inherited entries with inherited ones).

This is a good post on using ICACLS. Apart from resetting and changing owners, you can also use ICACL to add/ remove ACEs, find files belonging to a particular user, and even substitute an ACE username/ SID with another. You can even save all ACEs of files in a folder and then restore them.

Lastly, if you are an administrator and want to take ownership of a file or directory, the takeown command is useful. It is not as useful as ICACLS which lets you assign someone else as the owner, but is useful if you are an admin and want take ownership.