src/_Resolve-CciBootstrapArgument.ps1

function _Resolve-CciBootstrapArgument {
<#
.SYNOPSIS
    Fills in the entry point's parameters, asking only when there is a genuine
    choice to make.
.DESCRIPTION
    The declared entry point usually needs a value the tenant registry cannot
    know - which team this machine is for, say. Rather than make the technician
    remember a flag, the value is resolved from the command's own argument
    completer: exactly one candidate is taken silently, several are offered as a
    numbered list, and anything else falls back to a plain prompt.
 
    That reuses the completion the module already publishes, so a module gains
    this for free by registering a completer.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$Command,
        [string[]]$Required = @(),
        [hashtable]$Supplied = @{}
    )

    $splat = @{}
    foreach ($key in $Supplied.Keys) { $splat[$key] = $Supplied[$key] }

    foreach ($name in $Required) {
        if ($splat.ContainsKey($name)) { continue }

        $candidates = @()
        try {
            $line = "$Command -$name "
            $completion = [System.Management.Automation.CommandCompletion]::CompleteInput($line, $line.Length, $null)
            $candidates = @($completion.CompletionMatches | ForEach-Object { $_.CompletionText })
        }
        catch { }

        if ($candidates.Count -eq 1) {
            $splat[$name] = $candidates[0]
            Write-Host "cciget: $name = $($candidates[0]) (only option)."
            continue
        }
        if ($candidates.Count -gt 1) {
            Write-Host ''
            Write-Host " Which $($name.ToLowerInvariant())?"
            for ($i = 0; $i -lt $candidates.Count; $i++) {
                Write-Host (" [{0}] {1}" -f ($i + 1), $candidates[$i])
            }
            while ($true) {
                $answer = Read-Host " Enter 1-$($candidates.Count)"
                $index = 0
                if ([int]::TryParse($answer, [ref]$index) -and $index -ge 1 -and $index -le $candidates.Count) {
                    $splat[$name] = $candidates[$index - 1]
                    break
                }
                Write-Host ' Not one of the options.'
            }
            continue
        }

        $splat[$name] = Read-Host " $name"
    }

    $splat
}