HiveBrain v1.2.0
Get Started
← Back to all entries
patternshellMinor

Cleanly setting ACLs

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
settingcleanlyacls

Problem

So this is my full script that I've been working on. My plan is to Create New, Folder, Create AD Group FS-TESTSHARE-R, Create AD Group FS-TESTSHARE-RW, Apply Both groups to the new share folder, Set Full Read permissions to FS-TESTSHARE-R, Set Full Read/Rights permissions to FS-TESTSHARE-RW, and Set full access permissions to Domain Admins and local Administrators.

I'm Pretty sure I have all of the syntax correct now (thanks to some awesome assistance I've received here), but I was hoping for some clarification on setting ACLs.

At the bottom I've redone how I was attempting to get, create, and set the ACLs Thanks to @themadtechnician), but I was curious as to if I've got all syntax correct or if I should create the set for each of the $objUser instead of putting them all in parentheses (is this the cleanest way to do this)...

```
$Parent = read-host -prompt "Enter full parent path that will contain the new folder (ie. \\eccofs01\Groups\ECCO IT\)"
$Name = read-host -prompt "Enter New Folder Name."
$Path = "$($parent)$($Name)"
$Location = read-host -prompt "Enter the AD Security Group Location (i.e. Global, Americas, Europe, Asia Pacific)"

Import-Module ActiveDirectory

#Create Security Groups
$GroupParams1= @{
'Name' = "FS-$NAME-RW"
'SamAccountName' = "FS-$NAME-RW"
'GroupCategory' = "Security"
'GroupScope' = "Global"
'DisplayName' = "$NAME Read-Write Access"
'Path' = "CN=$LOCATION,CN=SECURITY GROUPS,CN=FILE SHARE GROUPS,DC=ESG,DC=INTL"
'Description' = "Members of this group have read-write access to $Path."
}

New-ADGroup @GroupParams1

$GroupParams2= @{
'Name' = "FS-$NAME-R"
'SamAccountName' = "FS-$NAME-R"
'GroupCategory' = "Security"
'GroupScope' = "Global"
'DisplayName' = "$NAME Read-Write Access"
'Path' = "CN=$LOCATION,CN=SECURITY GROUPS,CN=FILE SHARE GROUPS,DC=ESG,DC=INTL"
'Description' = "Members of this group have read access to $Path"
}

New-ADGroup @GroupParams2

# Create New Folder
New-Item

Solution

To streamline the permission handling you may want to wrap ACE creation in a function and set the ACL just once at after all ACEs were added:

function New-Ace {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [Security.Principal.NTAccount]$Account,
    [Parameter(Mandatory=$false, Position=1)]
    [Security.AccessControl.FileSystemRights]$Permissions = 'ReadAndExecute',
    [Parameter(Mandatory=$false, Position=2)]
    [Security.AccessControl.InheritanceFlags]$InheritanceFlags = 'ContainerInherit,ObjectInherit',
    [Parameter(Mandatory=$false, Position=3)]
    [Security.AccessControl.PropagationFlags]$PropagationFlags = 'None',
    [Parameter(Mandatory=$false, Position=4)]
    [Security.AccessControl.AccessControlType]$Type = 'Allow'
  )

  New-Object Security.AccessControl.FileSystemAccessRule(
    $Account, $Permissions, $InheritanceFlags, $PropagationFlags, $Type
  )
}

$domain = 'DOMAIN'

$acl = Get-Acl $path

'Administrators', "$domain\Domain Admins" | ForEach-Object {
  $acl.AddAccessRule((New-Ace $_ 'FullControl'))
}
$acl.AddAccessRule((New-Ace "$domain\FS-$NAME-RW" 'Modify'))
$acl.AddAccessRule((New-Ace "$domain\FS-$NAME-R" 'ReadAndExecute'))

Set-Acl $path $acl


Other improvements might include determining the administrators and domain admins group names independent of the system's locale by their well-known SIDs, e.g.:

$administrators = ([wmi]"Win32_Sid.Sid='S-1-5-32-544'").AccountName

$domain_admins  = Get-WmiObject -Class Win32_Account |
                  Where-Object { $_.SID -like '*-512' } |
                  Select-Object -Expand Caption


Another thing you could do is map names to permissions like this:

$permissions = @{
  'Administrators'        = 'FullControl'
  "$domain\Domain Admins" = 'FullControl'
  "$domain\FS-$NAME-RW"   = 'Modify'
  "$domain\FS-$NAME-R"    = 'ReadAndExecute'
}


and use the hashtable as input for the ACE creation:

$permissions.Keys | ForEach-Object {
  $acl.AddAccessRule((New-Ace $_ $permissions[$_]))
}


Of course this implies that all ACEs have the same type and flags, otherwise you'd have to use a more elaborate data structure.

Code Snippets

function New-Ace {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [Security.Principal.NTAccount]$Account,
    [Parameter(Mandatory=$false, Position=1)]
    [Security.AccessControl.FileSystemRights]$Permissions = 'ReadAndExecute',
    [Parameter(Mandatory=$false, Position=2)]
    [Security.AccessControl.InheritanceFlags]$InheritanceFlags = 'ContainerInherit,ObjectInherit',
    [Parameter(Mandatory=$false, Position=3)]
    [Security.AccessControl.PropagationFlags]$PropagationFlags = 'None',
    [Parameter(Mandatory=$false, Position=4)]
    [Security.AccessControl.AccessControlType]$Type = 'Allow'
  )

  New-Object Security.AccessControl.FileSystemAccessRule(
    $Account, $Permissions, $InheritanceFlags, $PropagationFlags, $Type
  )
}

$domain = 'DOMAIN'

$acl = Get-Acl $path

'Administrators', "$domain\Domain Admins" | ForEach-Object {
  $acl.AddAccessRule((New-Ace $_ 'FullControl'))
}
$acl.AddAccessRule((New-Ace "$domain\FS-$NAME-RW" 'Modify'))
$acl.AddAccessRule((New-Ace "$domain\FS-$NAME-R" 'ReadAndExecute'))

Set-Acl $path $acl
$administrators = ([wmi]"Win32_Sid.Sid='S-1-5-32-544'").AccountName

$domain_admins  = Get-WmiObject -Class Win32_Account |
                  Where-Object { $_.SID -like '*-512' } |
                  Select-Object -Expand Caption
$permissions = @{
  'Administrators'        = 'FullControl'
  "$domain\Domain Admins" = 'FullControl'
  "$domain\FS-$NAME-RW"   = 'Modify'
  "$domain\FS-$NAME-R"    = 'ReadAndExecute'
}
$permissions.Keys | ForEach-Object {
  $acl.AddAccessRule((New-Ace $_ $permissions[$_]))
}

Context

StackExchange Code Review Q#125408, answer score: 5

Revisions (0)

No revisions yet.