Public/Invoke-RaidinessCheckup.ps1

function Invoke-RaidinessCheckup {
    <#
    .SYNOPSIS
        The whole checkup in one command: sign in, collect, assess, export.

    .DESCRIPTION
        Does what Connect-Raidiness, Invoke-Raidiness and
        Export-RaidinessReport do, in that order, into one run folder — with
        the progress bar, the log and the intake in the right places. Every
        step is still available on its own; this only saves typing four
        commands and keeping their paths in step.

        Nothing about the run changes: it is read-only, it signs in
        interactively, and a source it cannot read becomes "not measured" with
        the reason recorded, never a guess.

        The run folder afterwards holds:

          data/ the collected evidence, and the intake answers
          report.html the interactive report — the one to open
          report.md the same report as plain markdown
          run.json the machine-readable run, for comparing later
          llm-bundle/ material for your own model, if -LLM
          report.pdf if -Pdf
          raidiness.log what happened, and what could not be read

    .PARAMETER Path
        Where the run folders live. By default, Raidiness uses a Raidiness
        folder in the current user's Documents folder, so no elevated
        PowerShell session is needed when the current directory is protected.

    .PARAMETER Intake
        A filled-in questionnaire (from Get-RaidinessIntake) to apply first.

    .PARAMETER AskIntake
        Ask the intake questions in the console before assessing.

    .PARAMETER GraphRequestTimeoutSeconds
        Maximum time, in seconds, for each Microsoft Graph request. This is
        independent of TimeoutSeconds, which controls report/browser work.

    .EXAMPLE
        Invoke-RaidinessCheckup -Customer 'Contoso Ltd' -Modules All -LLM

    .EXAMPLE
        Get-RaidinessIntake -Path ./intake.csv -Format Csv
        Invoke-RaidinessCheckup -Customer 'Contoso Ltd' -Intake ./intake.csv
    #>

    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [string] $Path = (Get-RaidinessDefaultRunPath),
        [string] $Customer = 'Your organisation',
        [string] $TenantId,

        [ValidateSet('All', 'MsGraph', 'ExchangeOnline', 'Teams', 'SharePoint', 'PowerPlatform')]
        [string[]] $Modules = @('MsGraph'),

        [switch] $IncludeSlow,
        [switch] $HashUpns,
        [switch] $NoPrompt,
        [switch] $Quiet,
        [ValidateRange(1, 2147483647)]
        [int] $GraphRequestTimeoutSeconds = 100,

        [string] $Intake,
        [switch] $AskIntake,

        [switch] $Markdown,
        [switch] $LLM,
        [switch] $IncludeIdentities,
        [switch] $Pdf,
        [switch] $NoBrowser,
        [switch] $NoOpen,
        [string] $BrowserPath,
        [int] $TimeoutSeconds = 180
    )

    $ErrorActionPreference = 'Stop'
    $started = Get-Date

    # Sign in only when there is no session: re-running a checkup should not
    # cost a second interactive sign-in.
    if (($Modules -contains 'MsGraph' -or $Modules -contains 'All') -and -not (Get-MgContext)) {
        Connect-Raidiness -TenantId $TenantId
    }

    $summary = Invoke-Raidiness -Path $Path -TenantId $TenantId -Modules $Modules `
        -IncludeSlow:$IncludeSlow -HashUpns:$HashUpns -NoPrompt:$NoPrompt -Quiet:$Quiet `
        -GraphRequestTimeoutSeconds $GraphRequestTimeoutSeconds

    # Invoke-Raidiness made the folder; this is the newest one under -Path.
    $latest = Join-Path $Path 'latest.txt'
    if (-not (Test-Path -Path $latest)) { throw "The collection did not create a run folder under $Path." }
    $runPath = Join-Path (Resolve-Path -Path $Path).Path (Get-Content -Path $latest -Raw).Trim()

    if ($Intake) {
        Set-RaidinessIntake -RunPath $runPath -FromFile $Intake
    }
    elseif ($AskIntake) {
        Set-RaidinessIntake -RunPath $runPath -Interactive
    }
    else {
        # No answers means roughly seventeen checks can only say "not
        # measured". Say so once, with the command that fixes it.
        Write-Host ''
        Write-Host 'No intake answers: the checks that depend on them stay "not measured".' -ForegroundColor Yellow
        Write-Host " Get-RaidinessIntake -Path ./intake.csv -Format Csv # fill it in, then re-run with -Intake ./intake.csv" -ForegroundColor Yellow
    }

    Export-RaidinessReport -RunPath $runPath -Customer $Customer `
        -Markdown:$Markdown -LLM:$LLM -IncludeIdentities:$IncludeIdentities `
        -Pdf:$Pdf -NoBrowser:$NoBrowser -NoOpen:$NoOpen `
        -BrowserPath $BrowserPath -TimeoutSeconds $TimeoutSeconds

    $elapsed = (Get-Date) - $started
    Write-Host ''
    Write-Host ("Checkup finished in {0:n0}s — {1}" -f $elapsed.TotalSeconds, $runPath) -ForegroundColor Green

    [pscustomobject]@{
        PSTypeName = 'Raidiness.Checkup'
        RunPath    = $runPath
        Customer   = $Customer
        Modules    = $summary
        Seconds    = [math]::Round($elapsed.TotalSeconds, 1)
    }
}