Skip to content

Instantly share code, notes, and snippets.

@JohanSelmosson
Last active April 5, 2022 12:08
Show Gist options
  • Save JohanSelmosson/7f7c1628e867e1213f7d1d92022f4c8f to your computer and use it in GitHub Desktop.
Save JohanSelmosson/7f7c1628e867e1213f7d1d92022f4c8f to your computer and use it in GitHub Desktop.
View Permissions on a folder structure
function GetFolderPermissionInfo {
[CmdletBinding()]
param (
[Parameter()]
[string]
$Path = $(get-location).ProviderPath,
[switch]
$ExportCsv,
[string]
$CSVPath="ACLReport-$(get-date -Format "yyyy-MM-dd_HHmm").csv",
[string[]]
$ExcludeFolders
)
function ListFoldersWithRobocopy {
param(
[string]$Path,
[string[]]$ExcludeFolders
)
#remove trailing backslash if there is one, Robocopy does not approve of those.
$path = $path.TrimEnd('\')
#$strExcludeFoldersOption = $null
if ($ExcludeFolders) {
[string]$strExcludeFoldersOption = "/XD "
foreach ($item in $ExcludeFolders) {
$strExcludeFoldersOption = $strExcludeFoldersOption + " ""$($item.TrimEnd('\'))"""
}
}
Write-Verbose "scanning this path: $Path"
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'robocopy'
# /L Logging only
# /S include Subfolders
# /NDL No Directory List - don’t log directory names.
# /XX eXclude "eXtra" files and dirs (present in destination but not source)
# /NC No Class - don’t log file classes. "New file"
# /NS No Size - don’t log file sizes.
# /NFL No File List
# /NJH No Job Header.
# /NJS No Job Summary.
# /FP Include Full Pathname of files in the output.
# /XD Exclude Directory
# /XJ Exclude Junction Points
# /LOG:c:\folder\filename.log
# /TEE Write to both log file and output to console
$psi.Arguments = @(' "{0}" NULL {1} /L /S /XX /NC /NS /NFL /NJH /NJS /XJ /FP ') -f $Path.ToString() ,$strExcludeFoldersOption
Write-Verbose $psi.Arguments
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
$process.PriorityClass = "BelowNormal"
$Output = new-object System.Collections.Generic.HashSet[string]
$Reader = $process.StandardOutput
while ($null -ne ($line = $reader.ReadLine())) {
Write-Verbose "$line"
if ($line -like '*\*') {
[void]$Output.Add( $line.trim() )
Write-Verbose "Adding $line to the list "
}
if ($line.trim().Length -ge 260) {
Write-Warning "Path is $($line.trim().Length) characters long: $($line.trim())"
}
}
$process.WaitForExit()
$Output
}
if (! (Test-Path -Path $Path -PathType Container)) {
Write-Warning "Not a folder, exiting.."
break
}
$DirectoryToSearch = $Path
$host.UI.RawUI.WindowTitle = "Searching $DirectoryToSearch"
if ($null -ne $ExcludeFolders) {
$folders = ListFoldersWithRobocopy -path $DirectoryToSearch -ExcludeFolders $ExcludeFolders
} else {
$folders = ListFoldersWithRobocopy -path $DirectoryToSearch
}
#Lists uninherited acl:s + all acls at the top folder
$i = 1
$NonInheritedACLs = ForEach ($Folder in $folders) {
try {
$Acl = Get-Acl -Path $Folder
}
catch {
[PSCustomObject]@{
'Folder Name' = $Folder
'Principal' = 'Reading of ACL denied'
'AccessControlType' = 'n/a'
'Permissions' = 'n/a'
'AreAccessRuleProtected' = 'n/a'
'InheritanceFlags' = 'n/a'
'PropagationFlags' = 'n/a'
}
continue
}
ForEach ($Access in $Acl.Access) {
if (($Access.IsInherited -ne 'True') -or ($DirectoryToSearch.TrimEnd('\') -eq $folder.TrimEnd('\')) ) {
[PSCustomObject]@{
'Folder Name' = $Folder
'Principal' = $Access.IdentityReference
'AccessControlType' = $Access.AccessControlType
'Permissions' = $Access.FileSystemRights
'AreAccessRuleProtected' = $ACL.AreAccessRulesProtected # True if inheritance is disabled on the folder
'InheritanceFlags' = $Access.InheritanceFlags
'PropagationFlags' = $Access.PropagationFlags
}
}
}
#print out the progress for every 50th folder processed
if ($i % 50 -eq 0) {
Write-Progress -activity "Reading ACL:s" -Status "$folder" -PercentComplete $([math]::Round(($i/($folders.count))*100))
}
$i++
}
Write-Progress -activity "Reading ACL:s" -Completed
if ($exportcsv) {
Write-Information "Exporting CSV to [$CSVPath]"
$NonInheritedACLs | Export-Csv -Path $CSVPath -UseCulture -NoTypeInformation -Encoding UTF8
}
return $NonInheritedACLs
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment