Public/Start-NSPSslManager.ps1

function Start-NSPSslManager {
    <#
    .SYNOPSIS
        The interactive menu for public SSL certificates: start a request, or finish one when the
        issuer's ZIP arrives.
    .DESCRIPTION
        Lists the requests under -Path with their state. Pick a number to finish that request
        (Complete-NSPSslRequest), N to start a new one (New-NSPSslRequest; the CSR goes to the
        clipboard), O to open the folder, Q to quit. Blank answers take the defaults shown in
        brackets; www.<domain> is added unless you answer n. A new request takes up to five names,
        the domain and www included.

        Replaces Wrapper.sh from NSP-SSLCertificates.
    .PARAMETER Path
        The folder that holds request folders (see New-NSPSslRequest).
    .PARAMETER NoNameLimit
        Allow new requests more than five names.
    .EXAMPLE
        Start-NSPSslManager
    .EXAMPLE
        Start-NSPSslManager -Path D:\NSP-SSLCertificates\Rebase
    #>

    [CmdletBinding()]
    param(
        [string]$Path,
        [switch]$NoNameLimit
    )

    $root = Get-NSPSslWorkRoot -Path $Path
    $ask = {
        param([string]$Prompt, [string]$Default)
        $answer = Read-Host $(if ($Default) { "$Prompt [$Default]" } else { $Prompt })
        if ([string]::IsNullOrWhiteSpace($answer)) { $Default } else { $answer.Trim() }
    }

    while ($true) {
        $requests = @(Get-NSPSslRequest -Path $root)
        Write-Host ''
        Write-Host "SSL certificate requests in $root" -ForegroundColor Cyan
        if (-not $requests) { Write-Host ' (none yet)' }
        for ($i = 0; $i -lt $requests.Count; $i++) {
            $request = $requests[$i]
            $color = switch ($request.Status) { 'CertificateReady' { 'Yellow' } 'Completed' { 'Green' } default { 'Gray' } }
            $detail = if ($request.Expires) { "expires $($request.Expires.ToString('yyyy-MM-dd'))" } else { "created $($request.Created.ToString('yyyy-MM-dd'))" }
            Write-Host (' {0,2}: {1,-40} {2,-20} {3}' -f ($i + 1), $request.Domain, $request.Status, $detail) -ForegroundColor $color
        }
        Write-Host ''
        $choice = Read-Host 'Number = finish that request, N = new request, O = open folder, Q = quit'

        try {
            if ($choice -match '^\d+$' -and [int]$choice -ge 1 -and [int]$choice -le $requests.Count) {
                $request = $requests[[int]$choice - 1]
                $layout = Get-NSPSslRequestLayout -Folder $request.Folder
                if ($request.Status -eq 'AwaitingCertificate') {
                    Write-Host "Put the issuer's ZIP (IIS format) in $($layout.Inputs) first." -ForegroundColor Yellow
                    if ((& $ask 'Open that folder now? (y/n)' 'y') -match '^[yY]') { Invoke-Item -LiteralPath $layout.Inputs }
                    continue
                }
                if ($request.Status -eq 'Completed' -and (& $ask 'Already completed. Build the deliverables again? (y/n)' 'n') -notmatch '^[yY]') { continue }

                $password = Read-Host 'PFX password' -AsSecureString
                $confirm = Read-Host 'PFX password again' -AsSecureString
                if ((ConvertFrom-NSPSslSecureString -SecureString $password) -ne (ConvertFrom-NSPSslSecureString -SecureString $confirm)) {
                    Write-Host 'The passwords did not match.' -ForegroundColor Red
                    continue
                }
                if (-not (ConvertFrom-NSPSslSecureString -SecureString $password)) {
                    Write-Host 'A PFX password is required.' -ForegroundColor Red
                    continue
                }
                $result = Complete-NSPSslRequest -Folder $request.Folder -PfxPassword $password
                $result | Format-List Subject, Names, NotAfter, Chain, PfxPath, FullChainPath | Out-Host
                Write-Host 'Send the PFX password separately from the PFX.' -ForegroundColor Yellow
                if ((& $ask 'Open the deliverables folder? (y/n)' 'y') -match '^[yY]') { Invoke-Item -LiteralPath $layout.Deliverables }
            } elseif ($choice -match '^[nN]') {
                $domain = & $ask 'Domain (the certificate''s main name, e.g. vpn.contoso.com)' ''
                if (-not $domain) { continue }
                $sans = [Collections.Generic.List[string]]::new()
                while ($true) {
                    if (-not $NoNameLimit -and $sans.Count -ge 4) {
                        Write-Host ' That is 5 names, the limit (start the menu with -NoNameLimit for more).' -ForegroundColor Yellow
                        break
                    }
                    $san = & $ask 'Another name for the certificate (blank when done)' ''
                    if (-not $san) { break }
                    if (Test-NSPSslDnsName -Name $san) { $sans.Add($san) } else { Write-Host " '$san' is not a valid name." -ForegroundColor Red }
                }
                $parameters = @{
                    Domain                 = $domain
                    SubjectAlternativeName = $sans.ToArray()
                    IncludeWww             = ($domain -notmatch '^(\*|www)\.' -and ($NoNameLimit -or $sans.Count -lt 4) -and (& $ask "Add www.$domain too? (y/n)" 'y') -match '^[yY]')
                    NoNameLimit            = [bool]$NoNameLimit
                    Organization           = & $ask 'Organization' 'Network Systems Plus, Inc.'
                    City                   = & $ask 'City' 'Sioux City'
                    State                  = & $ask 'State' 'IA'
                    Country                = & $ask 'Country (2 letters)' 'US'
                    Path                   = $root
                    CopyToClipboard        = $true
                }
                $existing = Get-NSPSslRequestLayout -Folder (Join-Path $root (ConvertTo-NSPSslFolderName -Domain $domain))
                if (Test-Path -LiteralPath $existing.KeyPath) {
                    if ((& $ask "$domain already has a key. Start over with a new one (the old one is archived)? (y/n)" 'n') -notmatch '^[yY]') { continue }
                    $parameters.Force = $true
                }
                $result = New-NSPSslRequest @parameters
                Write-Host ''
                Write-Host $result.Csr
                Write-Host 'The CSR is on the clipboard. Paste it into the issuer''s order page.' -ForegroundColor Green
                Write-Host "When the certificate is issued, choose IIS as the download format and put the ZIP in $($result.Inputs)." -ForegroundColor Green
            } elseif ($choice -match '^[oO]') {
                if (-not (Test-Path -LiteralPath $root)) { New-Item -ItemType Directory -Path $root -Force | Out-Null }
                Invoke-Item -LiteralPath $root
            } elseif ($choice -match '^[qQ]') {
                return
            }
        } catch {
            Write-Host $_.Exception.Message -ForegroundColor Red
        }
    }
}