Private/New-AACFinding.ps1
|
function New-AACFinding { <# .SYNOPSIS Makes one finding in the shape every expert command (cost, access, attack paths, health, compliance, failover, dependencies, utilization, drift) returns, so findings sort, filter and export the same way everywhere. .DESCRIPTION Severity Critical, High, Medium, Low or Info Category what kind of finding ('Standing privileged access', ...) Finding what was found, in one line Resource, ResourceType, ResourceGroup, Subscription, ResourceId Detail the evidence Impact why it matters - the business impact Remediation what to do Effort Low, Medium or High - to put quick wins first Link where to read more (https) -Property adds command-specific properties after these. #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Returns a new object; nothing outside the process changes.')] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] [string] $TypeName, [Parameter(Mandatory)] [ValidateSet('Critical', 'High', 'Medium', 'Low', 'Info')] [string] $Severity, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [string] $Finding, [string] $ResourceId, [string] $Resource, [string] $ResourceType, [string] $ResourceGroup, [string] $Subscription, [string] $Detail, [string] $Impact, [string] $Remediation, [ValidateSet('', 'Low', 'Medium', 'High')] [string] $Effort = '', [string] $Link, [System.Collections.IDictionary] $Property = @{} ) $item = [ordered]@{ Severity = $Severity Category = $Category Finding = $Finding Resource = $(if ($Resource) { $Resource } elseif ($ResourceId) { ($ResourceId.TrimEnd('/') -replace '^.*/', '') } else { '' }) ResourceType = $(if ($ResourceType) { $ResourceType } elseif ($ResourceId -match '(?i)/providers/(.+)/[^/]+$') { ($Matches[1] -replace '/[^/]+/(?=[^/]+$)', '/').ToLowerInvariant() } else { '' }) ResourceGroup = $(if ($ResourceGroup) { $ResourceGroup } elseif ($ResourceId -match '(?i)/resourceGroups/([^/]+)') { $Matches[1] } else { '' }) Subscription = $Subscription Detail = $Detail Impact = $Impact Remediation = $Remediation Effort = $Effort Link = $Link ResourceId = $ResourceId } foreach ($key in $Property.Keys) { $item[[string]$key] = $Property[$key] } $object = [pscustomobject]$item $object.PSObject.TypeNames.Insert(0, $TypeName) $object } |