Public/Export-AACWafQuestionnaire.ps1
|
function Export-AACWafQuestionnaire { <# .EXTERNALHELP Azure.Admin.Console-help.xml .SYNOPSIS Writes the Well-Architected questionnaire - one question per design principle, for what no API can test - as a CSV the team answers and Invoke-AACWafAssessment -AttestationPath scores. .DESCRIPTION One row per design principle of each pillar (-Pillar, all five by default): Pillar, Principle, Question, Answer, Evidence, Owner, AnsweredOn, and Learn (the principle on Microsoft Learn). Open it in Excel or any editor and fill in: Answer Yes, Partly, No or NotApplicable (empty: not answered yet - the principle stays not assessed unless a check covers it) Evidence where to find the proof: a wiki page, a test report, a ticket Owner who answered, or who owns the gap Yes scores 100, Partly 50, No 0; NotApplicable leaves it out. Nothing in Azure is read or changed. An existing file is only replaced with -Force (its answers would be lost). .PARAMETER Path Where to write the CSV. .PARAMETER Pillar Only these pillars' principles. .PARAMETER Force Replace the file if it exists. .EXAMPLE Export-AACWafQuestionnaire -Path .\waf-answers.csv All 24 design principles' questions, ready to answer. .EXAMPLE Export-AACWafQuestionnaire -Path .\reliability.csv -Pillar Reliability Then: Invoke-AACWafAssessment -Pillar Reliability -AttestationPath .\reliability.csv .OUTPUTS System.IO.FileInfo #> [CmdletBinding()] [OutputType([System.IO.FileInfo])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Path, [ValidateSet('Reliability', 'Security', 'Cost Optimization', 'Operational Excellence', 'Performance Efficiency')] [string[]] $Pillar = @('Reliability', 'Security', 'Cost Optimization', 'Operational Excellence', 'Performance Efficiency'), [switch] $Force ) trap { if ($_.Exception -is [System.Management.Automation.PipelineStoppedException]) { return }; $PSCmdlet.ThrowTerminatingError((Show-AACError -ErrorRecord $_ -Cmdlet $PSCmdlet)) } $fullPath = $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) if ((Test-Path -LiteralPath $fullPath) -and -not $Force) { $problem = [System.IO.IOException]::new("Azure Admin Console didn't replace '$fullPath': it exists, and its answers would be lost.") $problem.Data['AACHint'] = 'Add -Force to replace it, or choose another -Path.' throw $problem } $catalog = Get-AACWafCatalog $rows = foreach ($p in @($catalog.Principles.Keys | Where-Object { $_ -in $Pillar })) { foreach ($principle in $catalog.Principles[$p]) { [pscustomobject][ordered]@{ Pillar = $p; Principle = $principle.Name; Question = $principle.Question; Answer = ''; Evidence = ''; Owner = ''; AnsweredOn = ''; Learn = $principle.Link } } } $folder = Split-Path -Path $fullPath -Parent if ($folder -and -not (Test-Path -LiteralPath $folder)) { $null = New-Item -ItemType Directory -Path $folder -Force } @($rows) | Export-Csv -LiteralPath $fullPath -NoTypeInformation -Encoding utf8 Write-AACMarkup "[grey58]Wrote $(@($rows).Count) question(s) to $([Spectre.Console.Markup]::Escape($fullPath)). Answer Yes, Partly, No or NotApplicable, then pass it to Invoke-AACWafAssessment -AttestationPath.[/]" Get-Item -LiteralPath $fullPath } |