Public/Install-PWSHYBKPIVTool.ps1

function Install-PWSHYBKPIVTool {
    <#
    .SYNOPSIS
        Installs yubico-piv-tool.exe via its Yubico-published MSI, if not already installed.
    .DESCRIPTION
        Reads the installation section of the module configuration, resolves the target
        architecture (auto-detected from the OS unless overridden in config), and - unless the
        exe is already present at the resolved path - downloads the matching MSI over HTTPS
        (TLS 1.2 enforced) and installs it silently via msiexec.exe. Requires an elevated
        PowerShell session: installing software system-wide needs Administrator rights, and
        this cmdlet fails fast with a clear error rather than silently re-launching elevated.
        Supports -WhatIf/-Confirm since it installs software.
    .PARAMETER Force
        Reinstall even if yubico-piv-tool.exe is already present at the resolved install path.
    .INPUTS
        None. This cmdlet does not accept pipeline input.
    .OUTPUTS
        String. Full path to the installed yubico-piv-tool.exe.
    .EXAMPLE
        Install-PWSHYBKPIVTool
        Installs yubico-piv-tool.exe if not already present, using the configured version and
        auto-detected architecture.
    .EXAMPLE
        Install-PWSHYBKPIVTool -Force
        Reinstalls yubico-piv-tool.exe even if already present.
    .LINK
        https://developers.yubico.com/yubico-piv-tool/Actions/
    .LINK
        Get-PWSHYBKPIVStatus
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    [OutputType([string])]
    param(
        [Parameter()]
        [switch] $Force
    )

    $config = Read-PWSHYBKPIVConfigFile
    Write-PWSHYBKPIVLog -Config $config -Level Debug -CmdletName $MyInvocation.MyCommand.Name `
        -Message 'Cmdlet invoked' -BoundParameters $PSBoundParameters

    $architecture = Resolve-PWSHYBKPIVArchitecture -Architecture $config.installation.architecture
    $installPath  = Get-PWSHYBKPIVInstallPath -Installation $config.installation -Architecture $architecture

    if ((Test-Path -Path $installPath -PathType Leaf) -and -not $Force) {
        Write-Verbose "yubico-piv-tool.exe already installed at '$installPath'; skipping. Use -Force to reinstall."
        return $installPath
    }

    if (-not (Test-PWSHYBKPIVElevated)) {
        $errorMessage = 'Installing yubico-piv-tool requires an elevated PowerShell session. Re-run PowerShell as Administrator.'
        Write-PWSHYBKPIVLog -Config $config -Level Error -CmdletName $MyInvocation.MyCommand.Name -Message $errorMessage
        throw $errorMessage
    }

    $downloadUrl = Get-PWSHYBKPIVDownloadUrl -Installation $config.installation -Architecture $architecture

    if ($PSCmdlet.ShouldProcess($installPath, "Install yubico-piv-tool $($config.installation.version) ($architecture)")) {
        $tempMsiPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "yubico-piv-tool-$($config.installation.version)-$architecture.msi"
        try {
            Save-PWSHYBKPIVDownloadFile -Uri $downloadUrl -OutFile $tempMsiPath
            Invoke-PWSHYBKPIVMsiInstall -MsiPath $tempMsiPath

            if (-not (Test-Path -Path $installPath -PathType Leaf)) {
                throw "msiexec.exe reported success but yubico-piv-tool.exe was not found at '$installPath' afterward."
            }

            Write-Verbose "yubico-piv-tool.exe $($config.installation.version) ($architecture) installed at '$installPath'."
            Write-PWSHYBKPIVLog -Config $config -Level Information -CmdletName $MyInvocation.MyCommand.Name `
                -Message "Installed yubico-piv-tool $($config.installation.version) ($architecture) at '$installPath'"
            $installPath
        } catch {
            Write-PWSHYBKPIVLog -Config $config -Level Error -CmdletName $MyInvocation.MyCommand.Name -Message "Install failed: $_"
            throw
        } finally {
            Remove-Item -Path $tempMsiPath -ErrorAction SilentlyContinue
        }
    }
}