Public/Get-RaidinessIntake.ps1
|
function Get-RaidinessIntake { <# .SYNOPSIS The intake questionnaire: the questions, and any answers already given. .DESCRIPTION Roughly seventeen checks cannot say anything without an intake answer. Whether processing must stay inside the EU Data Boundary, whether unmanaged devices are controlled, how big the first pilot group is, whether there is an AI usage policy: none of that is visible in Graph, because it is a decision, not a setting. Unanswered, those checks report "not measured" -- never a false "in order". With no -Path this writes nothing and emits one object per question, so the whole questionnaire is a pipeline away: Get-RaidinessIntake | Where-Object Section -eq 'security' | Format-Table Key, Question With -Path it writes a file to fill in: JSON by default, or CSV, which is what an intake actually looks like in practice -- a spreadsheet on the table between you and the customer. Fill in the Answer column and hand it back to Set-RaidinessIntake. .PARAMETER Path File to write the questionnaire to. Omit to emit objects instead. .PARAMETER Format Json (default) or Csv. .PARAMETER From An earlier intake.json or run folder, to pre-fill the answers with. .PARAMETER Section Only these sections (repeatable), e.g. security, choice, pilot. .PARAMETER Force Overwrite an existing file. .EXAMPLE Get-RaidinessIntake -Path ./intake.csv -Format Csv # fill in the Answer column, then: Set-RaidinessIntake -RunPath ./raidiness/2026-09-02-1431 -FromFile ./intake.csv #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string] $Path, [ValidateSet('Json', 'Csv')] [string] $Format = 'Json', [string] $From, [string[]] $Section, [switch] $Force ) $ErrorActionPreference = 'Stop' $catalog = Read-RaidinessIntakeCatalog $questions = $catalog.Questions if ($Section) { $questions = @($questions | Where-Object { $_.Section -in $Section }) if ($questions.Count -eq 0) { throw "No questions in section(s) $($Section -join ', '). Known sections: $(($catalog.Sections.key) -join ', ')." } } $existing = @{} if ($From) { foreach ($pair in (Read-RaidinessIntakeAnswer -Path $From).GetEnumerator()) { $existing[$pair.Key] = $pair.Value } } foreach ($question in $questions) { foreach ($key in @($question.Key) + $question.Aliases) { if ($existing.ContainsKey($key) -and $null -eq $question.Answer) { $question.Answer = $existing[$key] } } } if (-not $Path) { return $questions } if ((Test-Path -Path $Path) -and -not $Force) { throw "$Path already exists. Pass -Force to overwrite it." } if ($Format -eq 'Csv') { $questions | Select-Object @{ n = 'Key'; e = { $_.Key } }, @{ n = 'Section'; e = { $_.SectionTitle } }, @{ n = 'Question'; e = { $_.Question } }, @{ n = 'Type'; e = { $_.Type } }, @{ n = 'Options'; e = { $_.Options -join ' | ' } }, @{ n = 'Answer'; e = { $_.Answer } } | Export-Csv -Path $Path -NoTypeInformation -Encoding utf8 } else { $document = [ordered]@{ raidinessIntake = [ordered]@{ version = '1.0' generatedAt = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ') note = 'Fill in "answers". The "questions" list is regenerated on every Get-RaidinessIntake and ignored when read back.' } questions = @($questions | ForEach-Object { [ordered]@{ key = $_.Key section = $_.SectionTitle question = $_.Question type = $_.Type options = $_.Options } }) answers = [ordered]@{} } foreach ($question in $questions) { $document.answers[$question.Key] = $question.Answer } ConvertTo-Json -InputObject $document -Depth 8 | Out-File -FilePath $Path -Encoding utf8 } $answered = @($questions | Where-Object { $null -ne $_.Answer -and "$($_.Answer)".Trim() -ne '' }).Count Write-Host "Questionnaire written to $((Resolve-Path $Path).Path) — $($questions.Count) question(s), $answered answered." -ForegroundColor Green Write-Host 'Fill it in, then: Set-RaidinessIntake -RunPath <run folder> -FromFile <this file>' -ForegroundColor Cyan } |