private/Software/Install-MicrosoftPwsh.ps1

<#
.SYNOPSIS
Installs Microsoft PowerShell 7.6 using winget.
 
.DESCRIPTION
Ensures PowerShell 7.6 is available by installing it with winget when needed,
using recommended installer override switches.
 
.OUTPUTS
System.Management.Automation.PSCustomObject
 
.EXAMPLE
Install-MicrosoftPwsh
 
Installs PowerShell 7.6 if it is not already available.
 
.NOTES
Author: David Segura
Company: Recast Software
This function is supported only on Windows and requires winget.
 
.LINK
https://learn.microsoft.com/en-us/powershell/scripting/install/install-powershell-on-windows?view=powershell-7.6
Change Summary:
#>

function Install-MicrosoftPwsh {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    [OutputType([pscustomobject])]
    param (
    )

    if (-not $IsWindows) {
        throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Install-MicrosoftPwsh is supported only on Windows."
    }

    $winget = Get-Command -Name 'winget' -ErrorAction SilentlyContinue
    if (-not $winget) {
        throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] winget is required but was not found. Install App Installer from Microsoft Store and try again."
    }

    $packageId = 'Microsoft.PowerShell'
    $installerOverride = '/passive ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=1 REGISTER_MANIFEST=1 USE_MU=1 ENABLE_MU=1 ADD_PATH=1'

    if ($global:OSDeployModule -and $global:OSDeployModule.Software.pwsh) {
        if ($global:OSDeployModule.Software.pwsh.wingetid) {
            $packageId = [string]$global:OSDeployModule.Software.pwsh.wingetid
        }

        if ($global:OSDeployModule.Software.pwsh.override) {
            $installerOverride = [string]$global:OSDeployModule.Software.pwsh.override
        }
    }

    $existingPwsh = Get-Command -Name 'pwsh' -ErrorAction SilentlyContinue
    $wasInstalled = $false
    $skippedInstall = $false

    if (-not $existingPwsh) {
        if ($PSCmdlet.ShouldProcess($packageId, 'Install PowerShell 7 using winget')) {
            Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PowerShell 7 is not installed. Installing with winget..." -ForegroundColor DarkGray

            & $winget.Source install --id $packageId -e -h --override $installerOverride --accept-source-agreements --accept-package-agreements
            if ($LASTEXITCODE -ne 0) {
                throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PowerShell 7 installation failed with exit code $LASTEXITCODE."
            }

            Update-OSDeploySessionEnvironment

            $existingPwsh = Get-Command -Name 'pwsh' -ErrorAction SilentlyContinue
            if (-not $existingPwsh) {
                $fallbackPwshPath = Join-Path -Path ${env:ProgramFiles} -ChildPath 'PowerShell\7\pwsh.exe'
                if (Test-Path -Path $fallbackPwshPath) {
                    $existingPwsh = Get-Command -Name $fallbackPwshPath -ErrorAction SilentlyContinue
                }
            }

            if (-not $existingPwsh) {
                throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PowerShell 7 was installed but pwsh was not found in PATH. Open a new PowerShell session and run the command again."
            }

            $wasInstalled = $true
        }
        else {
            $skippedInstall = $true
        }
    }
    else {
        $installedVersion = (& $existingPwsh.Source -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()').Trim()
        Write-Host "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] PowerShell 7 is already installed: $installedVersion" -ForegroundColor Green
    }

    $finalVersion = $null
    if ($existingPwsh) {
        $finalVersion = (& $existingPwsh.Source -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()').Trim()
    }

    [pscustomobject]@{
        ProductId         = $packageId
        Version           = $finalVersion
        WasInstalled      = $wasInstalled
        CommandPath       = if ($existingPwsh) { $existingPwsh.Source } else { $null }
        WingetCommand     = $winget.Source
        InstallerOverride = $installerOverride
        SkippedInstall    = $skippedInstall
    }
}