private/Select-OSDeployCoreCacheWindowsRE.ps1

#Requires -PSEdition Core

function Select-OSDeployCoreCacheWindowsRE {
    <#
    .SYNOPSIS
        Selects an imported Windows Recovery Environment image
 
    .DESCRIPTION
        Gets imported Windows Recovery Environment images, optionally limits results to a
        Windows build major, and returns the only result
        automatically when exactly one is available. Auto mode returns the newest matching
        image without displaying a selector. Otherwise, multiple results are displayed in a
        native console table that supports Up and Down arrow navigation, Enter to select, and
        Escape to cancel.
 
        An interactive, nonredirected console is required only when multiple results must
        be displayed. The function writes a warning and returns no object when no matching
        images exist or interactive selection cannot be displayed.
 
    .PARAMETER Architecture
        Limits results to amd64 or arm64 before automatic or interactive selection.
 
    .PARAMETER BuildMajor
        Limits results to Windows build major 26200 or 26300 before automatic or
        interactive selection.
 
    .PARAMETER Auto
        Returns the newest matching recovery image without displaying an interactive selector.
 
    .EXAMPLE
        PS> Select-OSDeployCoreCacheWindowsRE -Architecture amd64 -BuildMajor 26200
 
        Returns or displays imported amd64 images matching Windows build 26200.
 
    .EXAMPLE
        PS> Select-OSDeployCoreCacheWindowsRE -Architecture amd64 -BuildMajor 26300 -Auto
 
        Returns the newest imported amd64 image matching Windows build 26300.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns the selected Windows RE source,
        or no object when none is selected or available.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 0.1.0
        Date: 2026-08-28
 
    .LINK
        Get-OSDeployCoreWindowsRE
    #>

    [CmdletBinding()]
    param (
        [ValidateSet('amd64', 'arm64')]
        [System.String]
        $Architecture,

        [ValidateSet(26200, 26300)]
        [int]
        $BuildMajor,

        [System.Management.Automation.SwitchParameter]
        $Auto
    )

    $params = @{}
    if ($Architecture) { $params.Architecture = $Architecture }

    $results = Get-OSDeployCoreWindowsRE @params
    if ($PSBoundParameters.ContainsKey('BuildMajor') -and $results) {
        $results = $results | Where-Object { ([version]$_.OSVersion).Build -eq $BuildMajor }
    }

    if ($results) {
        if ($Auto) {
            $selectedResult = $results | Sort-Object { [version]$_.OSVersion } -Descending | Select-Object -First 1
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Auto mode: selected latest WinRE '$($selectedResult.Name)' version $($selectedResult.OSVersion)"
            return $selectedResult
        }

        if (@($results).Count -eq 1) {
            Write-HostDateTimeDarkGray 'Auto-selected the only available Windows Recovery Image'
            return $results
        }

        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Recovery Images: $env:ProgramData\OSDeployCore\cache\windows-re"

        if ([Console]::IsInputRedirected -or [Console]::IsOutputRedirected) {
            Write-Warning "[$(Get-Date -Format s)] An interactive console is required to select a Windows Recovery Image"
            return
        }

        $resultItems = @($results)
        $displayResults = @($resultItems | Select-Object Name, Architecture, OSVersion, Version, Languages, ImageSize)
        $columnNames = @('Name', 'Architecture', 'OSVersion', 'Version', 'Languages', 'ImageSize')
        $tableRows = for ($resultIndex = 0; $resultIndex -lt $displayResults.Count; $resultIndex++) {
            $displayResult = $displayResults[$resultIndex]
            [PSCustomObject]@{
                Result = $resultItems[$resultIndex]
                Values = @($columnNames | ForEach-Object { [string]$displayResult.$_ })
            }
        }

        $columnWidths = foreach ($columnIndex in 0..($columnNames.Count - 1)) {
            $maximumValueLength = ($tableRows | ForEach-Object { $_.Values[$columnIndex].Length } | Measure-Object -Maximum).Maximum
            [Math]::Max($columnNames[$columnIndex].Length, $maximumValueLength)
        }

        $header = (($columnNames | ForEach-Object -Begin { $columnIndex = 0 } -Process {
                    $value = $_.PadRight($columnWidths[$columnIndex])
                    $columnIndex++
                    $value
                }) -join ' ')

        $selectedIndex = 0
        $consoleTop = [Console]::CursorTop
        do {
            [Console]::SetCursorPosition(0, $consoleTop)
            Write-Host
            Write-Host -ForegroundColor Cyan "Select a Recovery Image (Up/Down to select, Enter to continue, Escape to cancel)"
            Write-Host $header

            for ($rowIndex = 0; $rowIndex -lt $tableRows.Count; $rowIndex++) {
                $tableRow = (($tableRows[$rowIndex].Values | ForEach-Object -Begin { $columnIndex = 0 } -Process {
                                $value = $_.PadRight($columnWidths[$columnIndex])
                                $columnIndex++
                                $value
                            }) -join ' ')

                if ($rowIndex -eq $selectedIndex) {
                    Write-Host "> $tableRow" -ForegroundColor Black -BackgroundColor Cyan
                }
                else {
                    Write-Host " $tableRow"
                }
            }

            $key = [Console]::ReadKey($true).Key
            switch ($key) {
                'UpArrow' { if ($selectedIndex -gt 0) { $selectedIndex-- } }
                'DownArrow' { if ($selectedIndex -lt ($tableRows.Count - 1)) { $selectedIndex++ } }
                'Escape' {
                    [Console]::WriteLine()
                    return
                }
            }
        } until ($key -eq 'Enter')

        [Console]::WriteLine()
        return $tableRows[$selectedIndex].Result
    }
    else {
        Write-Warning "[$(Get-Date -Format s)] No WinRE sources available for selection"
        return $null
    }
}