Get and Set Folder Permissions with PowerShell

Managing permissions for numerous servers is the theme today. Drilling down into a folder, right-clicking properties, then reviewing security on the same folder for potentially dozens of computers is time consuming and, with the capabilities of scripting, unnecessary.

PowerShell lets us do this very easily. The first script allows you to view each account and their corresponding read/write permissions on any number of computers. By default the script will only search the local computer. You can filter to only display a specific right. A full list and explanation of each right is available here.

Function Get-Permission
{
[Cmdletbinding()]
Param(
  [string[]]$ComputerName = $Env:COMPUTERNAME,
 [Parameter(Mandatory=$true)]
  [string]$Folder,
  [string]$Rights
)
Process {
 $ComputerName |
 ForEach-Object {
 $Server = "$_"
 Write-Verbose "Getting Permissions for \\$Server\$Folder"
 (Get-Acl "\\$Server\$Folder").Access |
 Where { $_.FileSystemRights -LIKE "*$Rights*" } | Select IdentityReference, FileSystemRights, AccessControlType
}#EndForEach
}#EndProcess
}#EndFunction

Now for a simple example. Remember to supply a $ instead of a : after the drive letter, as this is designed to run remotely.

#Example of Get-Permission
Get-Permission -ComputerName "COMP1","COMP2" -Folder "C$\logs\SQL"
Now that you have verified the permissions list, you might need to make some adjustments. This set command will allow you to change $Access and $Rights for a specific $Account with minimal effort across your domain.
Function Set-Permission
{
[Cmdletbinding()]
Param(
  [string[]]$ComputerName = $env:COMPUTERNAME,
 [Parameter(Mandatory=$true)]
  [string]$Folder,
 [Parameter(Mandatory=$true)]
  [string]$Account,
  [string]$Access = "Allow",
  [string]$Right = "FullControl"
)
Process {
  $ComputerName|
  ForEach-Object {
  $Server = "$_"
  $Acl = Get-Acl "\\$Server\$Folder"
  $Acl.SetAccessRuleProtection($True,$False)
  $Rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$Account","$Right","ContainerInherit,ObjectInherit","None","$Access")
  $Acl.AddAccessRule($Rule)
  Set-Acl "\\$Server\$Folder" $Acl
  Write-Verbose "Permission Set for \\$Server\$Folder"
}#EndForEach
}#EndProcess
}#EndFunction
 And here is a quick example of how to execute the function. This can be used to allow or deny rights to the folder.
#Example Set-Permission
Set-Permission -ComputerName "Comp1","Comp2" -Folder "C$\logs\sql" -Account "Domain\ServiceUser" -Access "Allow" -Right "FullControl"
 

PowerShell: Get Files Containing a String

I have hundreds of script files, and as hard as I try, I don’t always name them effectively. Many of those scripts contain an obscure piece of code that I’m not very familiar with. I normally refer to previous scripts to remember the rarely used bits. While the standard windows search feature helps me narrow down which file I need when I’ve named the file efficiently, it fails to help a lot. When I’m looking for a script with a particular line of code on say, line 1021, where I did a weird time conversion, I’m not going to find it fast, if at all.

Last week I was hunting for a script that used the PowerShell feature of creating a Progress Bar. In the past I’ve mostly used the bar as a gimmick, but this time I wanted to keep track of how far along a script was in a long-running multi-server query. I quickly scripted something to search the contents of my documents for a specific piece of text. I even added a progress bar to this script. Granted the search is normally so fast that the bar doesn’t matter, but hey, I needed to practice the calculations for the progress bar anyways.


Function Search-Folder
{
  param(
  [Parameter(Mandatory=$true)]
    [string]$Folder,
  [Parameter(Mandatory=$true)]
    [string]$SearchTerm
  )
 $Files = Get-ChildItem $Folder
 $Count = $Files.Count
 $i = 0
 ForEach( $File in $Files )
 {
  $Percent = $i/$Count*100
  Write-Progress -Activity "Searching through files..." -Status "$Percent% Complete" -PercentComplete $Percent
  $i++
  $Text = Get-Content "$Folder\$File" -ErrorAction SilentlyContinue
  IF( $Text | WHERE { $Text -LIKE "*$SearchTerm*" } )
  { Write-Host $File }
 }#EndForEach
}#EndFunction

Most of the math and code here is to display the Progress Bar. The function takes two mandatory parameters, $Folder and $SearchTerm. It then loops through each file in the folder using Get-ChildItem and then Get-Content, filtering for the desired text string.

I commonly clear the screen with CLS before executing a function, just to keep the results easy to read. The below example execution will cycle through my PowerShellScripts folder and return the name of any files with the word progress in them.


Search-Folder -Folder "C:\Scripts\PowerShellScripts" -SearchTerm "progress"