Setting permissions on a entire folder tree w/ exceptions.

I don't have time to try and figure this out and want to learn powershell, but haven't had the chance yet.

I need to change the permissions on an entire folder structure, but it has a special need.

Folder starts at D:\HRDept

I need to reset all permissions, inherit for HRDept-Users Modify and HRDept-Payroll-Usersl list folders.  This is to remove old user permissions that should no longer be there.

But there are folders inside of D:\HRDept that are called "Payroll", where HR-Dept-Payroll needs Modify access.  So, when it comes across those folders, it needs to turn off inherit, copy the rules, and add a single new rule.

Added  bonus is to be able to run it on a individual folder for the GUI when they create a new user account.
                                                                       
Thanks in advance!
LVL 3
MarkJenksAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

egryllsCommented:
I would use RichCopy.  Copy the Payroll folder with perms to perhaps the root of the drive.  Make sure the permissions copied over acurately.

Then, reset the permissions at the root level of the folder as you described and tell it to reset permissions on all of the child objects right through explorer.  Once the permissions reset is complete, use RichCopy to copy the folder with the permissions back into place and add your permissions to the destination folder.
0
MarkJenksAuthor Commented:
Maybe I didn't explain it well enough.

D:\HRDept\Employeename\
And then folders inside of them for Payroll, Documents, etc, etc.

So, there are 1000's of folders, one for each Employee, and inside of those are the Payroll folders.
0
Chris DentPowerShell DeveloperCommented:

Copy the ACL from where? The parent? Or a generic ACL you've set up?

Chris
0
Creating Active Directory Users from a Text File

If your organization has a need to mass-create AD user accounts, watch this video to see how its done without the need for scripting or other unnecessary complexities.

MarkJenksAuthor Commented:
Basicly I want to reset the permissions for the entire tree to HRDept-Users Modify and HRDept-Payroll-Usersl list folders.   Turning on inherit for the entire tree.

Then I need something to go through the structure (recursive) and if the name of the folder is "Payroll", I need to turn off inherit and add the HRDept-Payroll-Users for Modify on all files in those folders.
0
Chris DentPowerShell DeveloperCommented:

In all cases below I suggest you create a limited copy of the structure you want to modify and thoroughly test these snippets out.

Lets deal with turning on Inherit for the tree first:

# Get all items beneath D:\HRDept. Apply a filter with Where-Object (?) to
# return folders only
Get-ChildItem "D:\HRDept" -Recurse | ?{ $_.PsIsContainer } | %{

  # Get the access control list for this folder
  $ACL = Get-ACL $_.FullName

  # If the folder does not inherit
  If ($ACL.AreAccessRulesProtected -eq $True)
  {
    # Turn off AccessRuleProtection, or enable Inheritance.
    $ACL.SetAccessRuleProtection($False, $False)
    # Apply the modified ACL
    Set-ACL $_.FullName -AclObject $ACL
  }
}


SetAccessRuleProtection has two arguments:

The first, IsProtected, defines whether the ACL is protected. If the ACL is protected it cannot inherit, we need to turn off protection to allow it to inherit.

The second, preserveInheritance, is what happens to existing inherited rules when IsProtected is set to $True. We're turning inheritance on, it has no effect here.

Note, this snippet does not removed access control entries. Do you need to to remove the access control entries defined on the folder so only inherited access applies?

For the second part of this question, we should be able to do this:


# Get all items beneath D:\HRDept where the name matches the filter
# Use Where-Object (?) to filter down to folders only.
Get-ChildItem "D:\HRDept" -Filter "Payroll" -Recurse | ?{ $_.PsIsContainer } | %{

  # Get the existing ACL
  $ACL = Get-ACL $_.FullName
  # Enable AccessRuleProtection / Disable Inheritance
  $ACL.SetAccessRuleProtection($True, $True)

  # Create the new access rule - notes below.
  $AccessRule = New-Object `
    Security.AccessControl.FileSystemAccessRule(`
      "YourDomain\HRDept-Payroll-Users", `
      @("Modify", "Synchronize"), `
      @("ObjectInherit", "ContainerInherit"), `
      "None,
      "Allow")
 
  # Add it to the ACL
  $ACL.AddAccessRule($AccessRule)

  # Apply the modified ACL
  Set-ACL $_.FullName -AclObject $ACL
}


That just leaves notes on Security.AccessControl.FileSystemAccessRule. We're using this Constructor for the object:

http://msdn.microsoft.com/en-us/library/sfe70whw%28v=VS.90%29.aspx

The identity is the user or group you wish to grant access to.

The rights we're defining are Modify and Synchronize, I included both because that will make it appear as if you ticked the Modify box in the GUI. Synchronize is something that happens in the background, it's not here to grant extra access, best described here:

http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights%28v=VS.90%29.aspx

InheritanceFlags are set to ContainerInherit (Folders Inherit) and ObjectInherit (Files Inherit).

PropagationFlags are set to none, these are used when you start selecting "This Folder Only", etc in the drop down boxes in the GUI. We want it to apply to all children without restriction, so None.

Finally, AccessControlType is allow.

Any questions?

Chris
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Chris DentPowerShell DeveloperCommented:
I'm missing a closing quote in this section:

# Create the new access rule - notes below.
  $AccessRule = New-Object `
    Security.AccessControl.FileSystemAccessRule(`
      "YourDomain\HRDept-Payroll-Users", `
      @("Modify", "Synchronize"), `
      @("ObjectInherit", "ContainerInherit"), `
      "None",
      "Allow")

Sorry about that.

Chris
0
MarkJenksAuthor Commented:
Wow, pretty much exactly what I was looking for with a good description to what it is doing.   I didn't even know about the -Filter option.  Takes me one step further into understanding it and writing my own.

"Note, this snippet does not removed access control entries. Do you need to to remove the access control entries defined on the folder so only inherited access applies?"

The ACL's that have been applied to here are pretty hosed up after years of changes and them not using groups, but adding users all over the place.   I would like to RESET the entire tree and start over.

I know I can do the reset from the GUI, but it's nice to understand how to do it from PS also.

This code above will do wonders for me and anyone that needs to do what I am doing.  

I'll have to wait until the morning to give it a try, but it looks like you got it.
0
Chris DentPowerShell DeveloperCommented:

A little modification to flush out existing rules, this is done in the first piece, at the same time as inheritance is enabled down the tree.

At the moment this part is limited to Folders because of the Where-Object filtering applied at the beginning. If you want it to apply to files as well as folders simply remove Where-Object (?{ $_.PsIsContainer }).

Chris
# Get all items beneath D:\HRDept. Apply a filter with 
# Where-Object (?) to return folders only
Get-ChildItem "D:\HRDept" -Recurse | ?{ $_.PsIsContainer } | %{

  # Get the access control list for this folder
  $ACL = Get-ACL $_.FullName

  # If the folder does not inherit
  If ($ACL.AreAccessRulesProtected -eq $True)
  {
    # Turn off AccessRuleProtection, or enable Inheritance.
    $ACL.SetAccessRuleProtection($False, $False)
  }

  # Find Access Control Entries which are applied explicitly
  $ACL.Access | ?{ $_.IsInherited -eq $False } | %{
    # Remove the rule from $ACL
    $ACL.RemoveAccessRule($_)
  }

  # Apply the modified ACL
  Set-ACL $_.FullName -AclObject $ACL
}

Open in new window

0
Chris DentPowerShell DeveloperCommented:

Hmm I just had a thought.

MoW wrote a simple function a long time ago that'll let you export the permissions assigned to an entire directory structure to a CSV file (leverages the SDDL format for security descriptors).

Using the script would give you a way back if you need to undo a change like this for all or part of the directory structure.

http://mow001.blogspot.com/2006/05/powershell-import-and-export.html

We could re-write it to make it a little prettier if we needed to, but it should work quite nicely as it stands :)

Chris
0
MarkJenksAuthor Commented:
At C:\powershell\grant-payroll.ps1:23 char:10
+   Set-ACL <<<<  $_.FullName -AclObject $ACL
    + CategoryInfo          : InvalidOperation: (D:\Departments\...Barbara\Pay
   roll:String) [Set-Acl], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Power
   Shell.Commands.SetAclCommand

Set-Acl : The security identifier is not allowed to be the owner of this object
0
MarkJenksAuthor Commented:
Okay, after messing around with this, I have an idea what is going on.

Why does set-acl want to set the owner to myself?  I want to leave the owner as "HRDept-Users".

I changed the owner via the GUI to myself for the entire tree, and now it works.

-Mark
0
Chris DentPowerShell DeveloperCommented:

I've seen this before.

Set-ACL cannot do anything clever or particularly useful with the owner. If the current owner is considered invalid then it will fail to set the ACL entirely. Unfortunately forcefully changing the owner requires far more rights than PS has or can be given.

In these cases I tend to recommend calling TakeOwn to fix the owner, the continuing with the job the script is trying to do.

But you've changed the owner already so it's no longer an issue?

Chris
0
MarkJenksAuthor Commented:
Correct, I force changed the owner from the GUI.

I talked to a friend of mine and he was wondering if it was because I was using 1.0 and not 2.0.

I'll goof around today and see if 2.0 does anything different.

Thanks for your help.   Not only did you help me solve what I needed quick, but now I understand more about PS than I did a few days ago.

-Mark
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.