Public/Invoke-PermissionAudit.ps1
|
function Invoke-PermissionAudit { <# .SYNOPSIS Orchestrates a full NTFS and share permission audit and generates an HTML dashboard report. .DESCRIPTION Runs all four audit checks (direct user ACEs, broken inheritance, nested group depth, and share-level permissions) against the specified paths, then compiles the results into a single HTML dashboard report. Designed for SOC2, HIPAA, and cyber insurance reviews. .PARAMETER Path One or more file system paths to audit. Each path is scanned recursively up to MaxDepth. .PARAMETER OutputPath Directory where the HTML report will be saved. Defaults to the current directory. .PARAMETER MaxDepth Maximum folder recursion depth for NTFS checks. Prevents runaway scans on deep trees. Defaults to 3. .PARAMETER IncludeInherited When specified, includes inherited ACEs in the direct user ACE report. By default only explicitly assigned (non-inherited) ACEs are flagged. .EXAMPLE Invoke-PermissionAudit -Path '\\server\share\Finance', '\\server\share\HR' .EXAMPLE Invoke-PermissionAudit -Path 'D:\Data' -OutputPath 'C:\Reports' -MaxDepth 5 -IncludeInherited #> [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string[]]$Path, [Parameter()] [string]$OutputPath = (Get-Location).Path, [Parameter()] [ValidateRange(1, 20)] [int]$MaxDepth = 3, [Parameter()] [switch]$IncludeInherited ) begin { $timestamp = Get-Date -Format 'yyyy-MM-dd_HHmmss' $reportFile = Join-Path $OutputPath "PermissionAudit_$timestamp.html" $auditStart = Get-Date Write-Verbose "Permission audit starting at $auditStart" Write-Verbose "Paths to audit: $($Path -join ', ')" Write-Verbose "MaxDepth: $MaxDepth | IncludeInherited: $IncludeInherited" } process { # ── Section 1: Direct User ACEs ────────────────────────────────────── Write-Verbose 'Running direct user ACE scan...' $directUserParams = @{ Path = $Path MaxDepth = $MaxDepth ExcludeBuiltIn = $true } $directUserResults = Get-DirectUserACEs @directUserParams if (-not $IncludeInherited) { $directUserResults = $directUserResults | Where-Object { -not $_.IsInherited } } $directUserFindings = @($directUserResults | Where-Object { $_.Finding -eq 'DIRECT USER ACE' }) # ── Section 2: Broken Inheritance ──────────────────────────────────── Write-Verbose 'Running broken inheritance scan...' $brokenInheritResults = Get-BrokenInheritance -Path $Path -MaxDepth $MaxDepth $brokenInheritFindings = @($brokenInheritResults | Where-Object { $_.Finding -like 'INHERITANCE DISABLED*' }) # ── Section 3: Nested Group Depth ──────────────────────────────────── Write-Verbose 'Running nested group depth scan...' $nestedGroupResults = Get-NestedGroupReport -Path $Path -MaxNestingDepth 3 -MaxDepth $MaxDepth $nestedGroupFindings = @($nestedGroupResults | Where-Object { $_.Finding -like 'EXCESSIVE NESTING*' }) # ── Section 4: Share Permissions ───────────────────────────────────── Write-Verbose 'Running share permission scan...' $shareResults = Get-SharePermissionReport -ComputerName 'localhost' -ExcludeDefault $shareFindings = @($shareResults | Where-Object { $_.Finding -ne 'OK' }) # ── Compile Report ─────────────────────────────────────────────────── $auditEnd = Get-Date $auditDuration = $auditEnd - $auditStart $summary = [PSCustomObject]@{ AuditDate = $auditStart.ToString('yyyy-MM-dd HH:mm:ss') Duration = '{0:mm\:ss}' -f $auditDuration PathsScanned = $Path.Count DirectUserACEs = $directUserFindings.Count BrokenInheritance = $brokenInheritFindings.Count ExcessiveNesting = $nestedGroupFindings.Count ShareIssues = $shareFindings.Count TotalFindings = $directUserFindings.Count + $brokenInheritFindings.Count + $nestedGroupFindings.Count + $shareFindings.Count } Write-Verbose "Audit complete. Total findings: $($summary.TotalFindings)" # ── Generate HTML ──────────────────────────────────────────────────── $htmlParams = @{ Summary = $summary DirectUserResults = $directUserResults BrokenInheritResults = $brokenInheritResults NestedGroupResults = $nestedGroupResults ShareResults = $shareResults PathsAudited = $Path ReportFile = $reportFile } New-HtmlDashboard @htmlParams Write-Host "Audit report saved to: $reportFile" -ForegroundColor Green # Return summary object for pipeline use $summary } } |