Setting Folder ACL

This topic contains 24 replies, has 4 voices, and was last updated by Profile photo of Charlie Spencer Charlie Spencer 6 months, 4 weeks ago.

  • Author
    Posts
  • #32933
    Profile photo of Brad Dworkin
    Brad Dworkin
    Participant

    Hi All,

    I'm trying to set ACL permissions on a folder. The goal is to set a ACE on the folder with a user in AD to have modify rights. Cant seem to ge thtis done. Below you find a snipping from the script.

    setup directories
    New-Item -Path \\ec-data\ecdata\documents -Name $initials -ItemType directory
    set acl
    $homepath="\\ec-data\ecdata\documents\$initials"
    $acl=get-acl $homepath
    $permission="ecp\$username","modify","allow"
    $accessrule=new-object System.Security.AccessControl.FileSystemAccessRule $permission
    $acl.SetAccessRule($accessrule)
    $acl | set-acl $homepath
    new-item -path \\ec-redir\pst$ -name $username -ItemType directory

  • #32934
    Profile photo of Don Jones
    Don Jones
    Keymaster

    I think this is the third ACL post today ;). The usual recommendation is, "Get-ACL and Set-ACL are a pain in the butt. Consider using icacls.exe instead."

    I know that seems like "cheating," but it isn't. There's a good reason PowerShell runs external command-line utilities – sometimes, they're the best tool for the job.

    If you are for some reason dead-set on using Set-ACL, you'll need to do more than post your script, though. What's it do? Any errors? Does absolutely nothing happen? Does Get-ACL return something different from the GUI?

    But... I'd use the command-line utility.

    • #44946
      Profile photo of Charlie Spencer
      Charlie Spencer
      Participant

      I don't already know icacls.exe. Am I better off trying to learn how to massage ACLs with PS, or taking the detour in my PS exploration and learning icacls.exe instead? Which will be faster? Will learning icacls give me a better understanding of what is being done in this command?

      $accessrule=new-object System.Security.AccessControl.FileSystemAccessRule $permission

      Thanks!

  • #32958
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    My experience shows you have to use the right set of parameters for FileSystemAccessRule. Another thing to be aware of is if you are creating the account in the same script you may have to delay it, or get the GUID of the account at creation (PassThru) and apply with that.

    The particular constructor I've had to follow is this one :
    FileSystemAccessRule Constructor (IdentityReference,FileSystemRights,InheritanceFlags,PropagationFlags,AccessControlType)

    Details : https://msdn.microsoft.com/en-us/library/ms147785%28v=vs.110%29.aspx

    Here are some snippets of the script I created at work that is used to make new shared folders.

    $Internal_ACL = Get-Acl -Path $Internal
    
    #region Disable Inheritance, remove previous ACLs
    $Internal_ACL.SetAccessRuleProtection($true, $false) | Out-Null
    $Internal_ACL.Access | ForEach-Object { $Internal_ACL.RemoveAccessRule($_) | Out-Null }
    #endregion Disable Inheritance, remove previous ACLs
    
    #region Create ACLs
    # Domain Admins
    $Rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("Domain Admins", "FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
    $Internal_ACL.AddAccessRule($Rule) | Out-Null
    # Group rights
    $Rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($Department.Group, "DeleteSubdirectoriesAndFiles, Modify", "ContainerInherit, ObjectInherit", "InheritOnly", "Allow")
    $Internal_ACL.AddAccessRule($Rule) | Out-Null
    $Rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($Department.Group, "DeleteSubdirectoriesAndFiles, Write, ReadAndExecute", "None", "None", "Allow")
    $Internal_ACL.AddAccessRule($Rule) | Out-Null
    
    # Internal Group rights
    $Rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($Department.GroupInR, "ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow")
    $Internal_ACL.AddAccessRule($Rule) | Out-Null
    #endregion Create ACLs
    
    #region Set ACLs
    Set-Acl -Path $Internal -AclObject $Internal_ACL -ErrorVariable ACLError -ErrorAction 'SilentlyContinue' | Out-Null
    if ($ACLError)
    {
    	Write-Output -InputObject "An error was caught attempting to apply security rights, `n`tyou may have to take ownership of the `'$ParentPath\$Internal`' folder"
    	Write-Verbose -Message "$ACLError"
    	$ACLError = $false
    } # if ACLError
    #endregion Set ACLs
  • #44949
    Profile photo of Don Jones
    Don Jones
    Keymaster

    I'd learn Icacls. But no, it won't help with that command. That command is basically low level .NET programming. Icacls doesn't use that. And yes, it's faster. It's probably easier. And it isn't a detour; you can run it in PowerShell. The Set-Acl stuff would also, by that definition, be a detour, because it's going to be low-level .NET programming, not cmdlets.

  • #44951
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    That script line just creates the rule, and matters a lot on what is in that $permission variable.

    The link my previous post is probably your best information for what those settings are and how to configure them for what you need.

    As for details about that particular line, it's creating a variable called $accessrule, which is a System.Security.AccessControl.FileSystemAccessRule .NET object type, the properties you feed it are what define the created object. You typically collect these in a different object with the .AddAccessRule method of an ACL Object.

    Learning either is useful, I've been trying to stick with powershell for as much as I can but I recently just hit a task where I had to break out icalcs for something powershell just could not properly push through, and gave almost no error about. So learn both, and then learn to start with the powershell part and just have icacls as a backup in the same script, that would be a great lesson.

    If you have more specific questions about that object type or the properties it sets, I can attempt to answer them to the best of my knowledge.

  • #44953
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Gentlemen, thanks for the quick responses!

    I'll take a look at icacls. Y'all scared me off with talk of 'low-level .NET objects'. I understood the creation of the $permission variable in the earlier statement. I understood the '$accessrule=' was creating another variable and was using the $permission variable, but the whole 'new-object System.Security.AccessControl.FileSystemAccessRule' threw me for a loop.

    Don, FYI, 'PS in a Month of Lunches' arrived today. The preface and '1.2 Is this book for you?' are very encouraging. You and Jeff are correct in the preface; the other books I've looked at assumed previous scripting experience.

  • #44964
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Okay, let me know if this icacls question is considered outside the scope of this forum and I'll take it elsewhere. On the other hand, since y'all did bring it up...

    I'm not getting the results I expect from either of these commands. As I understand, either of these should remove 'Domain Users' from the ACL of the specified folder.

    PS C:\> icacls \\domain.com\users\last6fm /remove 'domain.com\Domain Users'
    processed file: \\domain.com\users\last6fm
    Successfully processed 1 files; Failed processing 0 files

    and

    PS C:\> icacls \\domain.com\users\last6fm /remove:g 'domain.com\Domain Users'
    processed file: \\domain.com\users\last6fm
    Successfully processed 1 files; Failed processing 0 files

    When I look in the GUI, Domain Users is still in the ACL with 'Read & Execute', 'List Folder Contents', and Read, the permissions it had before I ran either command. The output seems to indicate my commands are valid, so apparently the syntax isn't correct for what I want to accomplish.

    Thanks for any suggestions, including that I take this elsewhere.

  • #44977
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Are those permissions inheriting from somewhere else? Icacls only modifies the direct ACL; it doesn't (and can't) remove any permissions inheriting from above, unless you use it to disable inheritance.

  • #44989
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Yes, they are inherited!

    Setting the ACL is a step in the series of actions I take when I create a new user account. I'm used to doing it all from the GUI, and disabling the inheritance has become another automatic 'point and click' action to me. I don't consciously think about it any more (or most of the other steps).

    I'll dig up handling inheritance at the command line. Thanks.

  • #45016
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    I licked the inheritance problem (icacls parameter /inheritance:d, if anyone is interested in the future).

    Also for anyone else's future benefit, I ran into an issue using a variable with icacls. The first command works successfully, but it's just to test my syntax. The second replaces the coded username with a variable holding the same username string. I tried enclosing the entire domain.com\$Name in single quotes, double quotes, percent signs, double and single, etc. Enclosing only the variable but NOT the domain turned out to be the solution.

    PS C:\Windows\system32> icacls \\domain.com\users\$Name /grant domain.com\last6fm:m 
    processed file: \\domain.com\users\last6fm
    Successfully processed 1 files; Failed processing 0 files
    
    PS C:\Windows\system32> icacls \\domain.com\users\$Name /grant "domain.com\$Name":m 
    icacls : Invalid parameter "/grant"
    At line:1 char:1
    + icacls \\domain.com\users\$Name /grant "domain.com\$Name":m
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (Invalid parameter "/grant":String) [], RemoteException
        + FullyQualifiedErrorId : NativeCommandError
    
    PS C:\Windows\system32> icacls \\domain.com\users\$Name /grant domain.com\"$Name":m 
    processed file: \\mu3srvfsbbg1.mu3.global.sys\users\last6fm
    Successfully processed 1 files; Failed processing 0 files

    I've got to figure out more effective search terms to use when Googling. I'm getting too many results that relate to other scripting tools.

    • This reply was modified 6 months, 4 weeks ago by Profile photo of Charlie Spencer Charlie Spencer. Reason: Clarity
  • #45019
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Well, I thought it did what I want but it doesn't. It handles the variable okay, but I'm still not getting the permissions I want.

    I thought :M would apply the same permissions as checking Modify in the GUI, but it doesn't. The account is added to the ACL but the permissions are applied as 'Special'.

    I also can't get the command to accept the (OI) and (CI) inheritance parameters for subordinate files and folders.

    PS C:\Windows\system32> icacls \\domain.com\users\$Name /t /grant last6fm:(OI)(CI)M
    OI : The term 'OI' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the 
    name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:69
    + icacls \\mu3srvfsbbg1.mu3.global.sys\users\$Name /t /grant last6fm:(OI)(CI)M
    +                                                                     ~~
        + CategoryInfo          : ObjectNotFound: (OI:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException

    EDIT – the above command does work correctly from a command prompt. It looks like my inability to use the inheritance parameter is why the rights are showing up as Special.

    • This reply was modified 6 months, 4 weeks ago by Profile photo of Charlie Spencer Charlie Spencer. Reason: Additional Information
  • #45024
    Profile photo of Don Jones
    Don Jones
    Keymaster

    The error indicates that PowerShell is trying to parse the command, rather than sending it as-is to Cmd.exe. That's not unusual. See http://edgylogic.com/blog/powershell-and-external-commands-done-right/ for background (especially the v3 section), but you probably want to run...

    &"icacls.exe" --% ...everything...else...
    

    The –% will tell PowerShell to knock it off with the remainder of the command, and just pass it along as-is.

  • #45032
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Yeah, that works as long as everything is hard-coded. I want to replace the specified username 'last6fm' with a variable $Name. As I suspected and my tests showed, the variable value doesn't getting passed along to icacls.

    This is what frustrates me more than anything else. I suspect I have the logic down, it's the syntax that drives me nuts, especially trying to make external, non-cmdlet pieces fit together.

  • #45034
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Check out that article. You'll have to start getting fancy with double quotes, and seeing if you can get the right combination to get it parsed and passed.

  • #45036
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    I started with the article, but I can't find any use of both –% and a variable.

    Also, if you need to reference PowerShell variables, you can't use this trick either. Read on.

    but darned if I've found it yet. I'll keep digging. Thanks.

  • #45040
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    Could you give an example of what you want the file rights to be, along with it's inheritance and propagation rights?

    OI is probably causing "special" permissions because it's for sub folders and files only, instead of this folder and decedents.
    CI is asking to inherit any propagated rights from above, so this could be tweaking what the final right set it as well.

    I typically end up giving the folder itself some kind of special rights, to stop users from being able to move or modify it directly, while still having control of all the items within it properly.

  • #45050
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Sure. I want to give the user the same rights he would get if I used the GUI and clicked the Allow:Modify box. That results in the following boxes getting checked: Modify, Read & Execute, List folder contents, Read, and Write.

    This command does exactly what I want, once Don pointed out the & and –% requirements.

    PS I:\> &icacls --% e:\users\last6fm /grant domain.com\last6fm:(oi)(ci)m

    But I want to replace last6fm with a variable $Name. The exact rights aren't the issue; I don't have any problems from a command prompt. It's getting PS to hand off all the parameters to icacls. I'd find something to copy and paste and just move on, but it looks like there's something important I need to learn from this about using resources external to PS. There's got to be some logic here somewhere, but most of what I've found makes it look like trial and error.

    Thanks.

  • #45060
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    ok, what about this.

    &icacls e:\users\$($Name) /grant domain.com\$($Name):"(oi)(ci)m"
  • #45064
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    That works. Can you tell me how? What's with

    $($Name)

    and

    :"(oi)(ci)m"

    ?

  • #45066
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    I just kept working on the paring until it did what I wanted it to do.

    the whole $($variable) is just a way to force it to expand it before it executes the line.

    Putting the parentheses in quotes let them pass through as proper string, without powershell mucking with them.

    I'm actually a little surprised it let the colon go in there without being in quotes but it just got stranger the more I played with it. You might find that in a script it parses slightly different and might need more tweaking, I've had occasional issues like that.

  • #45068
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    For whatever reason, the first $($Name) in the filename isn't necessary, just the second one in the username. That apparent inconsistency mystifies the living crud out of me.

    And this was easier than Get-ACL / Set-ACL? Gods. I'm going to lunch before I get any more discouraged.

    Thanks to all.

  • #45072
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Honestly, anything involving ACLs is a shit-show. And Microsoft knows it. That's why there's such a press for role-based authorization (e.g., DAC), and to move away from ACLs over time. Maintaining ACLs is impossible.

  • #45092
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    Totally agree with Don, ACL management is a cluster.

    Just for reference the powershell ACL method would be more like :

    $TargetPath = "e:\users\$Name"
    $FolderACL = Get-Acl -Path $TargetPath
    $ACLRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule("domain.com\$($Name)", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
    $FolderACL.AddAccessRule($ACLRule)
    Set-Acl -Path $TargetPath -AclObject $FolderACL

    Now that you have a better understanding of the icacls, you should see the main similarities, just in this one you are also explicitly listing propagation type, and if it is an Allow or Deny ACL type.

  • #45140
    Profile photo of Charlie Spencer
    Charlie Spencer
    Participant

    Okay, now everything looks better after a chicken salsa wrap and house-made chips. Glad to hear the issues aren't just with this newbie.

    It could be worse for me. I long ago mandated that there would only be two global groups in an ACL – one for read, one for write. If a user wants something else in a subfolder, we'll create a new top-level directory. At least I don't have to deal with those nested nightmares.

    Thanks. I'll take a break from attempting a real-world application and dive into Don's chapter on the Help system.

You must be logged in to reply to this topic.