Here’s something I had to do at work a few weeks back. I wanted to blog about it since then but never got around to it.

We had copied a bunch of folders from one location to another. Since this was a copy the folders lost their original ACLs. I wanted to do two things – 1) the folder names were in the format “LastName, FirstName” and I wanted to change that to “username” (I had a CSV file with mappings so I could use that to do the renaming). 2) I wanted to change the ACLs so the user had modify rights to the folders.

For the first task here’s what I did:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

$Mappings=@{}

foreach($rin(Import-Csv\path\to\Mappings.csv))

{

$Mappings[$r.Olduser]=$r.NewUser

}

foreach($folderin"G:\Folder1","G:\Folder2"){

Get-ChildItem$folder-Directory|%{

$oldPath=$_.FullName;

$oldUser=Split-Path-Leaf$oldPath;

$newUser=$Mappings[$oldUser];

if($newUser-ne$null){

$newPath="G:\NewFolder\$newUser"

# Write-Host "Will move from $oldPath to $newPath"

Move-Item$oldPath$newPath

}

}

}

Note that apart from renaming I also move the folder to a different path (coz I had multiple source locations and wanted to combine them all into one).

Turns out I was mistaken in my previous post. A few minutes after enabling inheritance, I noticed it was disabled again. So that means the groups must be protected by AD.

I knew of the AdminSDHolder object and how it provides a template set of permissions that are applied to protected accounts (i.e. members of groups that are protected). I also knew that there were some groups that are protected by default. What I didn’t know, however, what that the defaults can be changed.

Initially I did a Compare-Object -ReferenceObject (Get-ADPrincipalGroupMembership User1) -DifferenceObject (Get-ADPrincipalGroupMembership User2) -IncludeEqual to compare the memberships of two random accounts that seemed to be protected. These were accounts with totally different roles & group memberships so the idea was to see if they had any common groups (none!) and failing that to see if the groups they were in had any common ancestors (none again!)

Then I Googled a bit :o) and came across a solution.

Before moving on to that though, as a note to myself:

The AdminSDHolder object is at CN=AdminSDHolder,CN=System,DC=domain,DC=com. Find that via ADSI Edit (replace the domain part accordingly).

Right click the object and its Security tab lists the template permissions that will be applied to members of protected groups. You can make changes here.

SDProp is a process that runs every 60 minutes on the DC holding the PDC Emulator role. The period can be changed via the registry key HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters\AdminSDProtectFrequency. (If it doesn’t exist, add it. DWORD).

Bingo! Most of my admin groups were protected, so most admin accounts were protected. All I have to do now is either un-protect these groups (my preferred solution), or change the template to delegate permissions there.

Update: Simply un-protecting a group does not un-protect all its members (this is by design). The member objects too have their adminCount attribute set to 1, so apart from fun-protecting the groups we must un-protect the members too.

Something I hadn’t realized about adminCount. This attribute does not mean a group/ user will be protected. Instead, what it means is that if a group/ user is protected, and its ACLs have changed and are now reset to default, then the adminCount attribute will be set. So yes, adminCount will let you find groups/ users that are protected; but merely setting adminCount on a group/ user does not protect it. I learnt this the hard way while I was testing my changes. Set adminCount to 1 for a group and saw that nothing was happening.

Also, it is possible that a protected user/ group does not have adminCount set. This is because adminCount is only set if there is a difference in the ACLs between the user/ group and the AdminSDHolder object. If there’s no difference, a protected object will not have the adminCount attribute set. :)

Today I cracked a problem which had troubled us for a while but which I never really sat down and actually tried to troubleshoot. We had an OU with 3rd level admin accounts that no one else had rights to but wanted to delegate certain password related tasks to our Service Desk admins. Basically let them reset password, unlock the account, and enable/ disable.

Here’s some screenshots for the delegation wizard. Password reset is a common task and can be seen in the screenshot itself. Enable/ Disable can be delegated by giving rights to the userAccountControl attribute. Only force password change rights (i.e. no reset password) can be given via the pwdLastSet attribute. And unlock can be given via the lockoutTimeattribute.

Problem was that in my case in spite of doing all this the delegated accounts had no rights!

Snooping around a bit I realized that all the admin accounts within the OU had inheritance disabled and so weren’t getting the delegated permissions from the OU (not sure why; and no these weren’t protected group members).

Of course, enabling is easy. But I wanted to see if I could get a list of all the accounts in there with their inheritance status. Time for PowerShell. :)

The Get-ACL cmdlet can list access control lists. It can work with AD objects via the AD: drive. Needs a distinguished name, that’s all. So all you have to do is (Get-ADUser <accountname>).DistinguishedName) – prefix an AD: to this, and pass it to Get-ACL. Something like this:

1

Get-ACLAD:$((Get-ADUserrakhesh).DistinguishedName)

The default result is useless. If you pipe and expand the Access property you will get a list of ACLs.

Of interest to us is the AreAccessRulesProtected property. If this is True then inheritance is disabled; if False inheritance is enabled. So it’s straight forward to make a list of accounts and their inheritance status:

So that’s it. Next step would be to enable inheritance on the accounts. I won’t be doing this now (as it’s bed time!) but one can do it manually or script it via the SetAccessRuleProtection method. This method takes two parameters (enable/ disable inheritance; and if disable then should we add/ remove existing ACEs). Only the first parameter is of significance in my case, but I have to pass the second parameter too anyways – SetAccessRuleProtection($False,$True).

Update 2: Didn’t realize I had many users in the built-in protected groups (these are protected even though their adminCount is 0 – I hadn’t realized that). To unprotect these one must set the dsHeuristics flag. The built-in protected groups are 1) Account Operators, 2) Server Operators, 3) Print Operators, and 4) Backup Operators. See this post on instructions (actually, see the post below for even better instructions).

Update 3: Found this amazing page that goes into a hell of details on this topic. Be sure to read this before modifying dsHeuristics.

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:

1

get-acl\path\to\file\with\permissions\you\like|set-acl\path\to\file

This doesn’t work though.

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

1

Set-Acl:Attempted to perform an unauthorized operation.

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

1

Set-Acl:The security identifier is not allowed to be the owner of this object.

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:

1

(Get-Acl\path\to\file).AreAccessRulesProtected

So all I need to do here is remove protection. That can be done via the SetAccessRuleProtectionmethod. 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:

1

2

3

$acl=Get-Acl\path\to\file

$acl.SetAccessRuleProtection($false,$false)

$acl|Set-Acl\path\to\file

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):

1

2

3

4

5

6

7

8

9

10

(Get-Acl.\admin.txt).Access|ftIdentityReference,IsInherited-AutoSize

IdentityReference IsInherited

----------------------------

NT AUTHORITY\SYSTEM False

BUILTIN\Administrators False

DOMAIN\admin False

NT AUTHORITY\SYSTEM True

BUILTIN\Administrators True

DOMAIN\user True

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.

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 …

1

icacls\path\to\file/setowner"DOMAIN\User"

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).

1

icacls\path\to\file/reset

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 takeowncommand 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.

At work we discovered a few accounts yesterday that didn’t have a certain group in its ACL. So I was curious on how to use PowerShell and find other accounts which are similarly missing this group.

To get the ACL of an ActiveDirectory object you must import the ActiveDirectory module and then use the Get-ACL cmdlet. Importing the ActiveDirectory module creates the AD: PSDrive which is what Get-ACL will use to access the AD objects.