private/Step-BuildBootInstallWinPEAppPwsh.ps1

function Step-BuildBootInstallWinPEAppPwsh {
    <#
    .SYNOPSIS
        Downloads, caches, and installs PowerShell 7 in the mounted WinPE image
 
    .DESCRIPTION
        Selects the PowerShell archive for global BuildMedia.Architecture, downloads it
        into the shared microsoft-powershell7 cache when needed, and expands it into
        Program Files\PowerShell\7 in the mounted image. Downloads use curl.exe when
        available and otherwise use Invoke-WebRequest.
 
        The function appends the application name to global BuildMedia.InstalledApps and
        loads the mounted SYSTEM registry hive to add PowerShell 7 to Path and PowerShell
        module locations to PSModulePath.
 
    .PARAMETER AppName
        Specifies the application name recorded in global BuildMedia.InstalledApps. The
        current implementation resets this value to PowerShell 7.6.4.
 
    .PARAMETER amd64Url
        Specifies an AMD64 download URL. The current implementation uses its built-in
        architecture-specific PowerShell 7.6.4 URLs instead of this value.
 
    .EXAMPLE
        PS> Step-BuildBootInstallWinPEAppPwsh
 
        Caches and installs the PowerShell 7 archive matching the current build architecture.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.String. Native reg.exe commands can write status text to the success stream.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-30
 
        Requires global BuildMedia with Architecture, MountPath, and InstalledApps properties
        and script OSDeployCorePath. Requires network access for cache misses and permission
        to load the mounted SYSTEM registry hive. Modifies the shared cache, mounted image,
        mounted registry hive, and global InstalledApps collection.
    #>

    [CmdletBinding()]
    param (
        [System.String]
        $AppName = 'PowerShell 7.6.4',
        [System.String]
        $amd64Url = 'https://github.com/PowerShell/PowerShell/releases/download/v7.6.4/PowerShell-7.6.4-win-x64.zip'
    )

    $Architecture  = $global:BuildMedia.Architecture
    $MountPath     = $global:BuildMedia.MountPath
    $WinPEAppsPath = Join-Path $Script:OSDeployCorePath 'cache' 'winpe-apps'
    $CacheDir      = Join-Path $WinPEAppsPath 'microsoft-powershell7'

    $AppName = 'PowerShell 7.6.4'
    if ($Architecture -eq 'amd64') {
        $DownloadUri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.6.4/PowerShell-7.6.4-win-x64.zip'
    }
    if ($Architecture -eq 'arm64') {
        $DownloadUri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.6.4/PowerShell-7.6.4-win-arm64.zip'
    }

    if (-not (Test-Path -Path $CacheDir)) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Creating PowerShell 7 cache: $CacheDir"
        New-Item -Path $CacheDir -ItemType Directory -Force | Out-Null
    }
    else {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Using PowerShell 7 cache: $CacheDir"
    }

    $DownloadFile = Split-Path $DownloadUri -Leaf
    if (-not (Test-Path "$CacheDir\$DownloadFile")) {
        $downloadPath = Join-Path $CacheDir $DownloadFile
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] [$($MyInvocation.MyCommand)] Downloading PowerShell 7: $DownloadFile"
        if (Get-Command 'curl.exe' -ErrorAction SilentlyContinue) {
            & curl.exe --silent --location --retry 5 --continue-at - --output $downloadPath $DownloadUri
        }
        else {
            Invoke-WebRequest -UseBasicParsing -Uri $DownloadUri -OutFile $downloadPath
        }
    }
    if (Test-Path "$CacheDir\$DownloadFile") {
        Expand-Archive -Path "$CacheDir\$DownloadFile" -DestinationPath "$MountPath\Program Files\PowerShell\7" -Force

        # Record the installed app
        $global:BuildMedia.InstalledApps += $AppName
    }
    #=================================================
    # Add PowerShell 7 PATH to WinPE ... Thanks Johan Arwidmark
    & reg LOAD HKLM\Mount "$MountPath\Windows\System32\Config\SYSTEM"
    Start-Sleep -Seconds 3
    $RegistryKey = 'HKLM:\Mount\ControlSet001\Control\Session Manager\Environment'

    $CurrentPath = (Get-Item -path $RegistryKey ).GetValue('Path', '', 'DoNotExpandEnvironmentNames')
    $NewPath = $CurrentPath + ';%ProgramFiles%\PowerShell\7\'
    $Result = New-ItemProperty -Path $RegistryKey -Name 'Path' -PropertyType ExpandString -Value $NewPath -Force

    $CurrentPSModulePath = (Get-Item -path $RegistryKey ).GetValue('PSModulePath', '', 'DoNotExpandEnvironmentNames')
    $NewPSModulePath = $CurrentPSModulePath + ';%ProgramFiles%\PowerShell\;%ProgramFiles%\PowerShell\7\;%SystemRoot%\system32\config\systemprofile\Documents\PowerShell\Modules\'
    $Result = New-ItemProperty -Path $RegistryKey -Name 'PSModulePath' -PropertyType ExpandString -Value $NewPSModulePath -Force

    Get-Variable Result | Remove-Variable
    Get-Variable RegistryKey | Remove-Variable
    [gc]::collect()
    Start-Sleep -Seconds 3
    & reg UNLOAD HKLM\Mount
}