Private/Get-AACWafAssessment.ps1
|
function Get-AACWafAssessment { <# .SYNOPSIS The Well-Architected assessment Invoke-AACWafAssessment and Test-AACGoLiveReadiness share: the scope, the one Resource Graph batch (Get-AACWafQuery), the questionnaire's answers, and the scores (ConvertTo-AACWafAssessment) - with progress. .DESCRIPTION -Request: @{ SubscriptionId; ManagementGroupId; ResourceGroupName; Pillar; HeatMapBy; ExcludeCheck; NoAdvisor; NoDefender; AttestationPath (a full path, or empty); CostTag; OwnerTag; KeepDuplicates }. Returns @{ Result; Scope; Notices; Catalog }. #> [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory)] [hashtable] $Request ) Invoke-AACProgress -ScriptBlock { Update-AACProgress -Id 'scope' -Indeterminate -Description 'Finding the subscriptions' $scope = Resolve-AACScope -SubscriptionId $request.SubscriptionId -ManagementGroupId $request.ManagementGroupId Update-AACProgress -Id 'scope' -Complete -Description "Scope: $($scope.Label)" $catalog = Get-AACWafCatalog $types = @($catalog.Checks | Where-Object { $_.Pillar -in $request.Pillar } | ForEach-Object { $_.Type } | Select-Object -Unique) $advisorCategory = @{ Reliability = 'HighAvailability'; Security = 'Security'; 'Cost Optimization' = 'Cost'; 'Operational Excellence' = 'OperationalExcellence'; 'Performance Efficiency' = 'Performance' } $categories = if ($request.NoAdvisor) { @() } else { @($request.Pillar | ForEach-Object { $advisorCategory[$_] }) } $queries = Get-AACWafQuery -ResourceType $types -ResourceGroupName $request.ResourceGroupName -AdvisorCategory $categories -NoDefender:($request.NoDefender -or 'Security' -notin $request.Pillar) Update-AACProgress -Id 'read' -Total $queries.Count -Description 'Reading resources, backups, Advisor and Defender for Cloud (one Resource Graph batch)' $read = Invoke-AACGraphBatch -Query $queries -SubscriptionId $scope.GraphScope -AllowFailure @($queries.Keys | Where-Object { $_ -ne 'resources' }) -OnProgress { param($QueryName, $Done, $Total) Update-AACProgress -Id 'read' -Increment 1 -Description "Read the $QueryName ($Done of $Total)" } Update-AACProgress -Id 'read' -Complete -Description ('Read {0:N0} resource(s) to check, {1:N0} Advisor recommendation(s), {2:N0} Defender assessment(s)' -f @($read.Rows['resources']).Count, @(if ($read.Rows.Contains('advisor')) { $read.Rows['advisor'] }).Count, @(if ($read.Rows.Contains('assessments')) { $read.Rows['assessments'] }).Count) $notices = [System.Collections.Generic.List[string]]::new() foreach ($key in @($read.Errors.Keys | Sort-Object)) { $notices.Add("The $key couldn't be read, so its checks are left out: $($read.Errors[$key] -replace '\s+', ' ')") } $attestation = @(if ($request.AttestationPath) { Read-AACWafAttestation -Path $request.AttestationPath -Catalog $catalog }) if ($request.AttestationPath) { $notices.Add("$($attestation.Count) answer(s) read from the questionnaire $(Split-Path -Leaf $request.AttestationPath).") } Update-AACProgress -Id 'score' -Indeterminate -Description 'Evaluating the checks and scoring the principles' $names = @{} foreach ($id in $scope.Ids) { $names[$id.ToLowerInvariant()] = if ($scope.Names.Contains($id.ToLowerInvariant())) { $scope.Names[$id.ToLowerInvariant()] } else { $id } } $result = ConvertTo-AACWafAssessment -Read $read.Rows -Catalog $catalog -Pillar $request.Pillar -SubscriptionName $names -HeatMapBy $request.HeatMapBy -ExcludeCheck $request.ExcludeCheck -CostTag $request.CostTag -OwnerTag $request.OwnerTag -Attestation $attestation -KeepDuplicates:([bool]$request.KeepDuplicates) Update-AACProgress -Id 'score' -Complete -Description ('{0:N0} check(s) on {1:N0} resource(s): {2:N0} result(s), {3:N0} failed ({4:N0} high)' -f $result.Stats.Assessed, $result.Stats.Resources, $result.Stats.Results, $result.Stats.Failed, $result.Stats.High) @{ Result = $result; Scope = $scope; Notices = $notices.ToArray(); Catalog = $catalog } } } |