Managing Permissions


Managing file permissions with scripting has always been a popular and challenging task. VBScript has no direct methods and using WMI is extremely complicated. Our answer has always been to use CACLS.EXE in a batch file script. Even though PowerShell provides a new approach, we still think using CACLS.EXE may be the best automation solution.

The Get-Acl cmdlet can be used in PowerShell to obtain security descriptor information for files, folders, printers, registry keys, and more. By default all information is displayed in a table format:

 PS C:\> get-acl c:\boot.ini     Directory: Microsoft.PowerShell.Core\FileSystem::C:\ Path                    Owner                      Access ----                    -----                      ------ boot.ini                BUILTIN\Administrators     NT AUTHORITY\SYSTEM Al... PS C:\> 

The problem is that some of the information is truncated. Therefore, you'll probably prefer to use something like this:

 PS C:\> get-acl boot.ini |format-list Path   : Microsoft.PowerShell.Core\FileSystem::C:\boot.ini Owner  : BUILTIN\Administrators Group  : NT AUTHORITY\SYSTEM Access : NT AUTHORITY\SYSTEM Allow  FullControl          BUILTIN\Administrators Allow  FullControl          BUILTIN\Power Users Allow  ReadAndExecute, Synchronize Audit  : Sddl   : O:BAG:SYD:PAI(A;;FA;;;SY)(A;;FA;;;BA)(A;;0x1200a9;;;PU) PS C:\> 

The Get-Acl cmdlet also works for directories:

 PS C:\> get-acl c:\users |format-list Path   : Microsoft.PowerShell.Core\FileSystem::C:\users Owner  : COMPANY\administrator Group  : COMPANY\None Access : BUILTIN\Administrators Allow  FullControl          NT AUTHORITY\SYSTEM Allow  FullControl          COMPANY\administrator Allow  FullControl          CREATOR OWNER Allow  268435456          BUILTIN\Users Allow  ReadAndExecute, Synchronize          BUILTIN\Users Allow  AppendData          BUILTIN\Users Allow  CreateFiles PS C:\> 

It will even work on registry keys:

 PS C:\> get-acl ` >> HKLM:\software\microsoft\windows\CurrentVersion\run|format-list >> Path   : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\micros          oft\windows\CurrentVersion\run Owner  : BUILTIN\Administrators Group  : NT AUTHORITY\SYSTEM Access : BUILTIN\Users Allow  ReadKey          BUILTIN\Users Allow  -2147483648          BUILTIN\Power Users Allow  SetValue, CreateSubKey, Delete, ReadKey          BUILTIN\Power Users Allow  -1073676288          BUILTIN\Administrators Allow  FullControl          BUILTIN\Administrators Allow  268435456          NT AUTHORITY\SYSTEM Allow  FullControl          NT AUTHORITY\SYSTEM Allow  268435456          CREATOR OWNER Allow  268435456 Audit  : Sddl   : O:BAG:SYD:AI(A;ID;KR;;;BU)(A;CIIOID;GR;;;BU)(A;ID;CCDCLCSWRPSDRC;;;PU) (A;CIIOID;SDGWGR;;;PU)(A;ID;KA;;;BA)(A;CIIOID;GA;;;BA)(A;ID;KA;;;SY)(A          ;CIIOID;GA;;;SY)(A;CIIOID;GA;;;CO) PS C:\> 

Notice that the cmdlet returns the owner. You can create a Get-Acl expression to display just that information:

 PS C:\> get-acl c:\* |format-table Path,Owner -autosize Path                                                            Owner ----                                                            ----- Microsoft.PowerShell.Core\FileSystem::C:\backinfo      BUILTIN\Admi... Microsoft.PowerShell.Core\FileSystem::C:\backups       MYCO\ATech Microsoft.PowerShell.Core\FileSystem::C:\deploy2000    MYCO\ATech Microsoft.PowerShell.Core\FileSystem::C:\deploy2003    MYCO\ATech Microsoft.PowerShell.Core\FileSystem::C:\Desktop Snapshot   MYCO\ATech Microsoft.PowerShell.Core\FileSystem::C:\Documents and Settings BUILTI Microsoft.PowerShell.Core\FileSystem::C:\HPAiOScrubber      MYCO\ATech Microsoft.PowerShell.Core\FileSystem::C:\IALog          BUILTIN\Admi.. ... 

We've truncated and edited the output to fit the page, but you get the idea.

The cmdlet doesn't have a recurse method, but we won't let that slow us down. If you want a report to show owners for a directory structure, you can use a script like this:

GetOwnerReport.ps1

image from book
 #GetOwnerReport $report="C:\OwnerReport.csv" $StartingDir=Read-Host "What directory do you want to start at?" Get-ChildItem $StartingDir -recurse |Get-Acl ` | select Path,Owner | Export-Csv $report -NoTypeInformation #send two beeps when report is finished write-Host `a `a `n"Report finished. See "$report 
image from book

The script prompts you for a starting directory. It then uses Get-Childitem to pass every item to Get-Acl and recurse through subdirectories. You'll notice that we piped output to Select-Object to get just the Path and Owner properties. Finally, we send the data to a CSV file. The script beeps a few times to let you know it is finished and displays a message.

Getting access control lists is half the job. You might still want to reset permissions through PowerShell. To be honest, this is not the easiest task to do in PowerShell. You need to understand .NET security objects and NTFS security descriptors. This means the technical discussions are well outside the scope of this book. Setting an access control rule is a matter of bit masking access rights against a security token. Depending on what bits match a security principal's account, determines whether you can view a file, make changes to a file, or take ownership.

You can use Set-Acl to update an object's access rule. However, you have to construct a .NET security object or get the security descriptor from an existing object, modify it, and apply it to another object. This is not an insurmountable task, just very tedious, and from our perspective, labor intensive. Even so, we'll show you how you can change access control using PowerShell. The script, ChangeACL.ps1, takes a simplified approach and grants permissions you specify to the specified security principal on all objects in the specified starting directory and subdirectories.

ChangeACL.ps1

image from book
 #ChangeACL.ps1 $Right="FullControl" #The possible values for Rights are # ListDirectory # ReadData # WriteData # CreateFiles # CreateDirectories # AppendData # ReadExtendedAttributes # WriteExtendedAttributes # Traverse # ExecuteFile # DeleteSubdirectoriesAndFiles # ReadAttributes # WriteAttributes # Write # Delete # ReadPermissions # Read # ReadAndExecute # Modify # ChangePermissions # TakeOwnership # Synchronize # FullControl $StartingDir=Read-Host " What directory do you want to start at?" $Principal=Read-Host " What security principal do you want to grant" ` "$Right to? `n Use format domain\username or domain\group" #define a new access rule #the $rule line has been artificially broken for print purposes #It needs to be one line. The online version of the script is properly #formatted. $rule=new-object System.Security.AccessControl.FileSystemAccessRule ($Principal,$Right,"Allow") foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {   $acl=get-acl $file.FullName   #display filename and old permissions   write-Host -foregroundcolor Yellow $file.FullName   #uncomment if you want to see old permissions   #write-Host $acl.AccessToString `n   #Add this access rule to the ACL   $acl.SetAccessRule($rule)   #Write the changes to the object   set-acl $File.Fullname $acl   #display new permissions   $acl=get-acl $file.FullName   Write-Host -foregroundcolor Green "New Permissions"   Write-Host $acl.AccessToString `n } 
image from book

This script creates a simple access rule that allows a specific right. If you can use a broad right such as Modify or Full Control, you'll find it easy to work with the script. We've hard-coded in the $Right variable. The script prompts you for directory path and the name of the security principal to which you wish to apply the right.

The real work of the script is creating a new FileSystemAccess rule object. Creating the object requires that we specify the name of the security principal, the right to be applied, and whether to allow or deny the right. With this rule we can recurse through the file system starting at the specified directory. For each file, we get the current access control list using Get-Acl:

 $acl=get-acl $file.FullName 

Next we add the new access rule to the ACL:

 $acl.SetAccessRule($rule) 

Now we call Set-Acl to write the new and modified ACL back to the object.

 set-acl $File.Fullname $acl 

The script finishes the loop by displaying the new ACL so you can see the change.

As you've seen, using Set-Acl is not simple, especially if you have complex permissions. Therefore, you may find it easier to use CACLS.EXE from within a PowerShell script:

SetPermswithCACLS.ps1

image from book
 #SetPermsWithCACLS.ps1 # CACLS rights are usually # F = FullControl # C = Change # R = Readonly # W = Write $StartingDir=Read-Host " What directory do you want to start at?" $Right=Read-Host " What CALCS right do you want to grant? Valid choices are F, C, R or W" Switch ($Right) {   "F" {$Null}   "C" {$Null}   "R" {$Null}   "W" {$Null}   default {     Write-Host -foregroundcolor "Red" `     `n $Right.ToUpper() "is an invalid choice. Please Try again."`n     exit   } } $Principal=Read-Host " What security principal do you want to grant" ` "CACLS right"$Right.ToUpper()"to?" `n ` "Use format domain\username or domain\group" $Verify=Read-Host `n "You are about to change permissions on all" ` "files starting at"$StartingDir.ToUpper() `n "for security"` "principal"$Principal.ToUpper() ` "with new right of"$Right.ToUpper()"."`n ` "Do you want to continue ? [Y,N]" if ($Verify -eq "Y") {  foreach ($file in $(Get-ChildItem $StartingDir -recurse)) {   #display filename and old permissions   write-Host -foregroundcolor Yellow $file.FullName   #uncomment if you want to see old permissions   #CACLS $file.FullName   #ADD new permission with CACLS   CACLS $file.FullName /E /P "${Principal}:${Right}" >$NULL   #display new permissions   Write-Host -foregroundcolor Green "New Permissions"   CACLS $file.FullName  } } 
image from book

This script first prompts you for a starting directory, and a permission right you want to grant. We've used a Switch statement to make sure a valid parameter for CACLS is entered. As long as the user has entered F, C, W, or R the script continues, and prompts you for the name of a security principal you want to add to the access control list. Because this is a major operation, we've included a prompt using Read-Host to provide a summary of what the script is about to do. If anything other than Y is entered, the script ends with no changes being made. Otherwise, the ForEach loop is executed.

Within this ForEach loop, we use Get-Childitem to enumerate all the files in the starting directory path and recurse through all subdirectories. The script displays the current file as a progress indicator, and then calls Cacls.exe. Because of the way PowerShell processes Win32 commands such as Cacls.exe, we need to enclose the program's parameters in quotes. You'll also notice that instead of using:

 CACLS $file.FullName /e /p "$Principal:$Right" 

We used:

 CACLS $file.FullName /e /p "${Principal}:${Right}" 

In PowerShell, an expression like Foo:Bar is treated as <namespace>:<name>, which is like $global:profile or $env:windir. In order for PowerShell to treat the Cacls.exe parameter as a command line parameter, we must delimit the variable name using braces as we've done in this example. The script finishes by displaying the new access control permissions for each file.

If you've used Cacls.exe before, you may have noticed that we used /E /P to assign permissions. According to Cacls' Help screen, /P is used to modify permissions for an existing entry. You would use /G to grant permissions to a new user. In Cmd.exe, either /G or /P will work regardless of whether or not the user already existed in the access control list.

This is not the case In PowerShell. PowerShell actually appears to enforce the Cacls.exe parameters. You can use /G if a user does not exist in the file's access control list. However, you must use /P if the user already exists. When you attempt to use /G to modify an existing user's permission, Cacls.exe will run, but no change will be made.

So, how do you know if you should use /P or /G without checking every file first? Not to worry. You can use /P regardless of whether or not the user exists in the access control list, which is what we've done here. The moral is - don't assume that every single Cmd.exe tool and command works identically in PowerShell. Most should, but if it doesn't, you have to look at how PowerShell is interpreting the expression.

One final note about the script - we could have used /T with Cacls.exe to change permissions on all files and subdirectories. The end result would have been the same, but then we couldn't have demonstrated some of PowerShell's output features.



Windows PowerShell. TFM
Internet Forensics
ISBN: 982131445
EAN: 2147483647
Year: 2004
Pages: 289

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net