Public/Get-BrokenInheritance.ps1
|
function Get-BrokenInheritance { <# .SYNOPSIS Finds folders where NTFS permission inheritance has been disabled. .DESCRIPTION Scans the specified paths and reports on folders where access rule inheritance has been turned off (AreAccessRulesProtected = True). Broken inheritance is not necessarily wrong -- it is commonly used on departmental root folders -- but every instance should be documented and justified. Undocumented broken inheritance is a frequent compliance finding and a common vector for permission drift. .PARAMETER Path One or more file system paths to scan. .PARAMETER MaxDepth Maximum folder recursion depth. Defaults to 3. .EXAMPLE Get-BrokenInheritance -Path 'D:\Shares\Finance' .EXAMPLE Get-BrokenInheritance -Path '\\server\data' -MaxDepth 5 #> [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string[]]$Path, [Parameter()] [ValidateRange(1, 20)] [int]$MaxDepth = 3 ) begin { function Get-FoldersToDepth { param( [string]$RootPath, [int]$Depth ) $folders = @([PSCustomObject]@{ FullName = $RootPath; Depth = 0 }) if ($Depth -ge 1) { $children = Get-ChildItem -Path $RootPath -Directory -Recurse -Depth ($Depth - 1) -ErrorAction SilentlyContinue foreach ($child in $children) { $relativePath = $child.FullName.Substring($RootPath.Length).TrimStart('\', '/') $currentDepth = ($relativePath -split '[\\/]').Count $folders += [PSCustomObject]@{ FullName = $child.FullName; Depth = $currentDepth } } } $folders } $results = [System.Collections.Generic.List[PSObject]]::new() } process { foreach ($scanPath in $Path) { if (-not (Test-Path -Path $scanPath)) { Write-Warning "Path not found: $scanPath" continue } Write-Verbose "Scanning for broken inheritance: $scanPath (MaxDepth: $MaxDepth)" $folders = Get-FoldersToDepth -RootPath $scanPath -Depth $MaxDepth foreach ($folder in $folders) { try { $acl = Get-Acl -Path $folder.FullName -ErrorAction Stop } catch { Write-Warning "Cannot read ACL on $($folder.FullName): $_" continue } $inheritanceEnabled = -not $acl.AreAccessRulesProtected $aceCount = $acl.Access.Count $uniqueIdentities = ($acl.Access | Select-Object -ExpandProperty IdentityReference -Unique).Count $finding = if (-not $inheritanceEnabled) { "INHERITANCE DISABLED - $aceCount explicit ACEs, $uniqueIdentities unique identities" } else { 'OK' } $result = [PSCustomObject]@{ Path = $folder.FullName InheritanceEnabled = $inheritanceEnabled ACECount = $aceCount UniqueIdentities = $uniqueIdentities Finding = $finding } $results.Add($result) } } } end { $results } } |