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 } |