Lab Ops 5 - Access Rights in PowerShell

In my last post I had a section in my script to create access right to a share I had just created and as promised I wanted to dissect that a bit more.

To recap what I wanted to do was to create a share with sufficient privileges to use that share for storing VMs as part of my VDI demo. In order to understand what permissions might be needed I used the wizard in Server manager to create a share (FileServer1\\VMTest), checked that I could use the Remote Desktop Services part of Server Manager to successfully create a pooled VDI collection and then examine its permissions.

The share has everyone full control access..

Share settings

and these are the File Access Rights on that share..

Share secirity settings

The SMB settings are set by the -fullAccess, for example in my script

#Orange$ is the name of the physical host (my big orange Dell Precision laptop)

New-SmbShare -Name $Share -Path $SharePath -CachingMode None -FullAccess contoso\Orange$,contoso\administrator  

The Access Rights are stored in Access Control Lists (ACLs) comprising individual Access Control Entries (ACEs) where an entry might state the contoso\Andrew has full control of a path and its folders and subfolders.  Out of the box in PowerShell there are just two command involved get-ACL to get this list and Set-ACL to modify setting on a path.  TechNet recommend that you create a share (say x:\test) set up its permissions and pass this across to your new share

Get-Acl -path “X:\Test” | Set-Acl -path “ X:\My New Share”

which is fine but in my case I am building a setup form scratch and I don’t wan to have to use an interface to create the template.  So it occurred to me I could write the ACL out to a file with one row per ACE and here’s my script to get the ACL for that VMTest share in the above screenshot..

#to a CSV for later use
$CSVFile = \\Orange\E`$\UK Demo Kit\Powershell\FileShareACL.CSV

#If the file is already there delete it
If(Test-Path $CSVFile) {Remove-Item $CSVFile}
$Header = "Path|IdentityReference|FileSystemRights|AccessControlType|IsInherited|InheritanceFlags|PropogationFlags"
Add-Content -Value $Header -Path $CSVFile
$TemplatePath = "X:\shares\VMTest"
$ACLList = get-acl $TemplatePath | ForEach-Object {$_.Access}
foreach($ACL in $ACLList)
{
$LineItem = $TemplatePath+ "|" + $ACL.IdentityReference + "|" + $ACL.FileSystemRights + "|" + $ACL.AccessControlType + "|" + $ACL.IsInherited + "|" + $ACL.InheritanceFlags + "|" + $ACL.PropogationFlags
Add-Content -Value $LineItem -Path $CSVFile
}

The Add-Content command allows me add write into a file, but not that alothough I have specified this as a CSV file it is in fact pipe (“|”) delimtied because it’s generally madness to use commas as separators as they get used inside the values as in this case..

Path|IdentityReference|FileSystemRights|AccessControlType|IsInherited|InheritanceFlags|PropogationFlags
X:\shares\VMTest|BUILTIN\Administrators|FullControl|Allow|False|None|
X:\shares\VMTest|BUILTIN\Administrators|FullControl|Allow|True|ContainerInherit, ObjectInherit|
X:\shares\VMTest|NT AUTHORITY\SYSTEM|FullControl|Allow|True|ContainerInherit, ObjectInherit|
X:\shares\VMTest|CREATOR OWNER|268435456|Allow|True|ContainerInherit, ObjectInherit|
X:\shares\VMTest|BUILTIN\Users|ReadAndExecute, Synchronize|Allow|True|ContainerInherit, ObjectInherit|
X:\shares\VMTest|BUILTIN\Users|AppendData|Allow|True|ContainerInherit|
X:\shares\VMTest|BUILTIN\Users|CreateFiles|Allow|True|ContainerInherit|

so Inheritance flags and access rights can have multiple values inside one ACE.  While there are several examples of this sort of script out there I had to do some digging to find out how to use this file, So here’s my crude but effective attempt..

$ACEList = Import-CSV -Path "\\orange\E`$\UK Demo Kit\Powershell\FileShareACL.CSV" -Delimiter "|"
$TestPath = "C:\Test"
If (test-path -Path $TestPath) {Remove-item -Path $TestPath}
MD $TestPath
$ACL = Get-Acl -Path $TestPath
ForEach($LineItem in $ACEList)
{

If($LineItem.FileSystemRights -eq 268435456) {$LineItem.FileSystemRights = "FullControl"}
If($LineItem.FileSystemRights -eq "ReadAndExecute, Synchronize"){$LineItem.FileSystemRights = "ReadAndExecute"}

$NewRights = [System.Security.AccessControl.FileSystemRights]::($LineItem.FileSystemRights)
$NewAcess = [System.Security.AccessControl.AccessControlType]::($LineItem.AccessControlType)
$InheritanceFlags = [System.Security.AccessControl.InheritanceFlags]($LineItem.InheritanceFlags)
$PropogationFlags = [System.Security.AccessControl.PropagationFlags]::None
$NewGroup = New-Object System.Security.Principal.NTAccount($LineItem.IdentityReference)

$ACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($NewGroup, $NewRights,$InheritanceFlags,$PropogationFlags,$NewAcess)
$ACL.SetAccessRule($ACE)
}
Set-Acl -Path $TestPath -AclObject $ACL

While this not be a solution for you it does show up some interesting points in PowerShell and in setting security:

  • There’s no command to make a new ACL you have to start with one from somewhere
  • Once I have declared $AceList as my csv file it is that file. For example I can get PowerShell to display it an all its glory using $ACEList | out-gridview to see it as a table
  • I have declared the separator I used to get round the comma problem with the -Delimiter “|” setting
  • I can loop through each line of my file with a simple foreach loop and so $LineItem represents each line and I can references the columns in that line with the standard . notation used in .Net e.g. $LineItem.FileSystemRights.
  • The stuff in square brackets might look hard to remember but PowerShell will auto complete this so once I typed in [System. I could select Security and so on to build up the correct syntax.
  • I have marked a line in my csv file in red because the File System Rights are set to a number in my case 268435456.  This is an example of an Access Control mask a set of bits that will cause an error when I try and create $ACE, so I have an exception in my code (also in red) to trap that and in my case just assign full control.
  • There is a another problem line marked in purple in my csv and that’s because this also threw an error.  I looked up the synchronize option and realised it gets set by default and so I put in another exception in y script (in purple) to trap that and just apply ReadAndExecute rights.
  • I had to refer to the .Net documentation here to work out what order to put the parameters in to create a new ACE (the line beginning $ACE = New-Object…)
  • Having built up the ACL in the loop it’s really easy to apply it your object ands of course this could be used for multiple objects in another loop for that

So what I have done here is a bit of a sledgehammer to crack a nut, but you might be able to use some of the principles to solve your real world problem for example you might just knock up a CSV file with permissions you want to set on an object.

Finally there’s this properly tested File System Security PowerShell Module on the TechNet gallery although it’s not yet been tested on Windows Server 2012 or R2.