private/Install-SoftwareMicrosoftPwsh.ps1
|
function Install-SoftwareMicrosoftPwsh { <# .SYNOPSIS Installs Microsoft PowerShell using winget .DESCRIPTION Detects pwsh.exe and installs the package configured in OSDeploy module metadata when the command is unavailable. The default package is Microsoft.PowerShell. The function passes installer overrides that enable PATH registration, Microsoft Update, remoting, manifest registration, and Explorer context menu integration unless metadata supplies a different override. After installation, the function refreshes the current process environment and locates pwsh.exe. WhatIf and Confirm apply to the winget installation. .EXAMPLE PS> Install-SoftwareMicrosoftPwsh Installs the configured PowerShell package when pwsh.exe is unavailable. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.String. Returns native winget output when PowerShell is installed. System.Management.Automation.PSCustomObject. Returns package, version, command path, installer override, winget path, and operation status details. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-08-28 Requires Windows and winget. The installed package ID and installer override can be supplied by $global:OSDeployModule.Software.pwsh. .LINK https://learn.microsoft.com/en-us/powershell/scripting/install/install-powershell-on-windows #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([pscustomobject])] param ( ) if (-not $IsWindows) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftPwsh 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)] 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)] 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 } } |