Contact

Subscribe via Email

Subscribe via RSS

Categories

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

Use SetACL if you want to overcome the 260 character limit when setting ACLs

I had to set folder & file permissions (basically, take ownership and enable inheritance) for a bunch of Windows folders the other day. Thing is the folders had levels and levels of sub-folders so Windows Explorer kept failing when applying permissions. I tried to use takeown and icacls via the command prompt but these too kept failing.

One workaround I had in mind was use subst or make junctions but these didn’t work either. When I mapped part of the folder name to a drive letter using subst the command line tools kept complaining that it wasn’t a file system that supported ACLs. Junctions didn’t do that well either. Mainly coz once you map part of a folder to a path/ drive letter, there’s no way to select the multiple sub-folders in there and assign permissions – when you select multiple folders, the security tab is missing.

Anyhoo, long story short, I came across this Server Fault thread from where I learnt the following –

In the Windows API, there is an infamous constant known as MAX_PATH. MAX_PATH is 260 characters. The NTFS file system actually supports file paths of up to 32,767 characters. And you can still use 32,767 character long path names by accessing the Unicode (or “wide”) versions of the Windows API functions, and also by prefixing the path with \\?\.

MAX_PATH was set in stone a very long time ago in the Windows world. I think it has something to do with ANSI standards at the time… but it’s one of those things that’s very difficult for Microsoft to change now, as now we have thousands of programs and applications, including some written by Microsoft themselves, that use MAX_PATH and would fail in strange new ways if the constant were suddenly changed. (Buffer overflows, heap corruption, etc.)

See this MSDN page too.

So what I needed was a tool that made use of the Unicode versions of the Windows API functions. A quick Google search bought me to SetACL – an amazing command-line tool that is able to set ACLs without the path limitations and that also has a nice syntax (I don’t know why, but icacls and even PowerShell has such obscure syntax for setting file ACLs). Check out this example page to get started. In my case all I really needed to do was run a command like this to (1) enable permissions inheritance and (2) set the ownership, and the command would do it recursively for all the files and folders in that path. Amazing!

The only gotcha I encountered was that I got the following error message after a while with the above command:

SetACL error message: The call to SetNamedSecurityInfo () failed Operating system error message: Access is denied.

Thankfully a forum post from the SetACL forums sorted that out for me. Trick is to do the take ownership first, and then the permission inheritance – apparently doing both together causes the above error.

So I did this first:

Followed by this:

SetACL is free but but command-line oriented. If you want a GUI version there’s SetACL Studio. That’s a paid product with a 30-day trial. I haven’t tried it yet. There is a SetACL t-shirt I might buy coz I was quite pleased with this tool yesterday. :)

Batch file to add BUILTIN\Administrators group to a folder of roaming profiles

Based on the idea I elaborated in my previous post

Latest version can be found on GitHub

I will explain the Batch file in detail later.

To view a file or folder owner use dir /q

Yup, you can’t use icacls or any of those tools to view who owns a file/ folder. Got to use the dir command with a /q switch. 

Can run it against a particular file/ folder too to get the permissions of just that. 

Weird! I mean, why not make this a part of the usual ACLs tools??

Beware of takeown and recursively operating

takeown is an in-built Windows tool that lets you take ownership of files and folders. Unlike other tools (e.g. icacls) which only let you give someone the right to take ownership of a file or folder, takeown seems to actually let you become the owner. And not just yourself, you can run it under a different context and that user account can be made the owner.

But it has a quirk which isn’t obvious until it turns around and bites you!

Here’s what I am using takeown for. I have a bunch of roaming profile folders that my admin account can’t view because only the user has full access to it. If I were using the GUI I would have opened the security tab of these folders, changed ownership to myself or the Administrators group, set that to propogate to all the child folders, and then add myself to the ACLs of this folder setting it to replace the ACLs of this folder and its children.

I have a large number of such folders, however, and I want to create a batch file to do this easily.

The obvious solution is to use takeown.

But this only sets the ownership of the parent folder. Not a problem, there’s a switch /R which tells takeown to recurse, so let’s try that:

Note that harmless question: do you want to replace the directory permissions with ones granting us full control? Harmless, because that’s what you would do via the GUI too. Gaining ownership of a folder doesn’t give you any permissions. That’s a separate step, so it seems like the command is only being helpful and offering to do this for you (so it can peek inside the sub-folders and give you ownership there too). And there-in lies the quirk which turned around and bit me. If you answer YES to this question (or use a switch /D Y to answer YES by default) it replaces the existing permissions with a new set. Yes, replace, not append as the GUI would have done. The net result of this is that once you run the takeown command as above only the Administrators group has any permissions, even the user loses their rights!

That’s definitely not what we want!

The right approach here seems to be to use a mix of takeown and icacls.

First use takeown to get ownership to the parent folder:

Then use icacls to recursively grant Full Control to the parent folder and sub-folders. Note that this only appends to the ACLs, it doesn’t replace. (This takes a few minutes and there’s plenty of output).

I don’t know why AppData failed above. It did for all the profiles I tested with and I didn’t investigate further. Could be an icacls limitation I suppose.

At this point the roaming profile is owned by Administrators, and the ACLs have an entry for the Administrators group in addition to the existing ACEs.

Now I run takeown again, recursively, but this time I target only the sub-folders (i.e. not the parent folder, only the ones below it).

takeown doesn’t have limitions like icacls. It’s ruthless! It will change ownership of all the sub-folders – including AppData – and replace the ACEs granting Administrators full access.

Now I run icacls on all the sub-folders, enabling inheritance on them. (This too takes a few minutes, but there’s no output except towards the end). The result of this step is that the botched ACEs set by takeown are fixed by icacls as it enables inheritance.

And that’s it. That’s how to properly use takeown and icacls to take ownership and reset permissions on a folder and its children.

Start Menu and other directory junctions access denied

Here’s a screenshot of my c:\Users\UserName folder. Notice the “Start Menu” folder:

users-folder

It is a directory junction to another folder, left behind for compatibility purposes. If I double click the folder though I get an access denied:

access-denied

 

The actual target to which this points is accessible, but the junction itself isn’t. Every time I encounter this I think I must make a note of “why” this is so, but I forget. Today I intend to note it down once and for all. 

Remember from an earlier post: there are hard links and there are soft links. The former points to the data itself, and so only work for files. The latter points to the folder/ file containing the data. Soft links are an evolution of directory junctions (there are directory junctions and volume junctions). While directory junctions make use of something called reparse points and were introduced in Windows 2000, soft links were introduced in Vista and are baked into the kernel itself. Microsoft uses directory junctions – as we saw above – to redirect some of its special folders.

The important thing with both directory junctions and soft links is that they can have their own ACLs. So while a user might have full permissions to the target folder, the directory junction or soft link itself may not grant the user permissions and so the contents cannot be accessed via the directory junction or soft link. That’s what happening here too. 

First, from the command prompt note that this is a junction and that I can enter the directory junction but cannot see any files:

The files exist, however, as I can directly browse the target:

Compare the ACLs of the target and directory junction and we see the problem:

(I could have used the Explorer GUI here but I prefer icacls. In the GUI we have to dig down a bit more to see the relevant ACEs).

Notice a DENY entry for Everyone on the directory junction for listing the contents (RD). That’s why I can’t list the junction contents (in Explorer double clicking results in trying to list the contents, while in Command Prompt entering a junction and listing are two separate tasks – that’s why entering the junction worked, but listing the contents failed). 

What the above tells us is that only listing the junction contents is prohibited. If we know the names of some folders in there – as older software for whom this directory junction is present would know – we can go to those locations using the directory junction. Thus the following works:

There you go!

Using Get-ACL to view and modify Access Control Lists (part 1)

The Get-ACL cmdlet can be used to view and modify Access Control Lists in PowerShell. It works with any object you have a PSProvider for – be it files, folders, registry keys, Active Directory objects, and so on.

Viewing and setting the Owner

To find the owner of an object there are couple of ways. The easy way is to use the Owner property:

But there’s a GetOwner() method too. This takes as input the type of output you want. The input must be of class System.Security.Principal.IdentityReference. There are two such class: System.Security.Principal.NTAccount gives you the user account while System.Security.Principal.SecurityIdentifier gives you the SID. These two classes are worth remembering when you want to convert between a user account and SID or vice versa.

You can set the owner too using the SetOwner() method.

Simply doing a SetOwner() won’t do the trick though because what Get-Acl returns is an ACL object and so all we are really doing is setting the ownership info in that object but not applying it back to the file or folder whose ACL it is.

The correct way would be thus:

Setting the owner – gotchas

For reasons I don’t know, the following doesn’t work:

It could be because of this:

When you set the owner directly, the object is empty. It could be because the SetOwner method doesn’t return anything so $acl is assigned nothing. But when you set $acl to the ACL and then set its owner, it works.

Another gotcha is that Set-Acl cannot be set to give ownership to another user. It can only be used to take ownership. Have a look at this:

I couldn’t find much but this Hey, Scripting Guy! post briefly mentions the following:

… although you can take ownership of a file using Windows PowerShell, we don’t believe that you can give ownership of a file to someone else. To transfer ownership to another user you’ll need to use the Windows Resource Kit utility Subinacl.exe.

Yet another gotcha is that built-in groups like “Users” and “Administrators” need to be referred to differently:

I discovered this looking at this page of well known SIDs, finding the SID of the built-in “Users” group, and translating it via PowerShell:

SID: S-1-5-32-545
Name: Users
Description: A built-in group. After the initial installation of the operating system, the only member is the Authenticated Users group. When a computer joins a domain, the Domain Users group is added to the Users group on the computer.

In fact, the error Exception calling "SetOwner" with "1" argument(s): "Some or all identity references could not be translated." is a good way of checking if a user account exists.

More later!

Get all users in an OU where specified account does not have any rights

The following code gets a list of all users in an OU (specified by the variable $OU) on which the account (specified by $account) does not have any rights. There’s probably better ways to do this (and also check for specific rights) but I wanted something quick and dirty and this is what I came up with today: