diff --git a/tools/install-powershell.ps1 b/tools/install-powershell.ps1 index 12200ccb9e..1b5248b467 100644 --- a/tools/install-powershell.ps1 +++ b/tools/install-powershell.ps1 @@ -19,7 +19,6 @@ [CmdletBinding()] param( [Parameter()] - [ValidateNotNullOrEmpty()] [string] $Destination, [Parameter()] @@ -50,17 +49,34 @@ if (-not $Destination) { $Destination = "${Destination}-daily" } } - -if (Test-Path -Path $Destination) { - if ($DoNotOverwrite) { - throw "Destination folder '$Destination' already exist. Use a different path or omit '-DoNotOverwrite' to overwrite." - } - Remove-Item -Path $Destination -Recurse -Force -} -New-Item -ItemType Directory -Path $Destination -Force > $null -$Destination = Resolve-Path -Path $Destination | ForEach-Object -MemberName Path +$Destination = $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Destination) Write-Verbose "Destination: $Destination" -Verbose +Function Remove-Destination([string] $Destination) { + if (Test-Path -Path $Destination) { + if ($DoNotOverwrite) { + throw "Destination folder '$Destination' already exist. Use a different path or omit '-DoNotOverwrite' to overwrite." + } + Write-Verbose "Removing old installation: $Destination" -Verbose + if (Test-Path -Path "$Destination.old") { + Remove-Item "$Destination.old" -Recurse -Force + } + if ($IsWinEnv -and ($Destination -eq $PSHome)) { + # handle the case where the updated folder is currently in use + Get-ChildItem -Recurse -File -Path $PSHome | ForEach-Object { + if ($_.extension -eq "old") { + Remove-Item $_ + } else { + Move-Item $_.fullname "$($_.fullname).old" + } + } + } else { + # Unix systems don't keep open file handles so you can just move files/folders even if in use + Move-Item "$Destination" "$Destination.old" + } + } +} + $architecture = if (-not $IsWinEnv) { "x64" } else { @@ -79,7 +95,7 @@ try { } if ($architecture -ne "x64") { - throw "The OS architecture is '$architecture'. However, we currently only support daily package for x64 Windows." + throw "The OS architecture is '$architecture'. However, we currently only support daily package for x64." } ## Register source if not yet @@ -99,10 +115,9 @@ try { $package = Find-Package -Source powershell-core-daily -AllowPrereleaseVersions -Name $packageName Write-Verbose "Daily package found. Name: $packageName; Version: $($package.Version)" -Verbose - Install-Package -InputObject $package -Destination $tempDir -ExcludeVersion > $null + Install-Package -InputObject $package -Destination $tempDir -ExcludeVersion > $null $contentPath = [System.IO.Path]::Combine($tempDir, $packageName, "content") - Copy-Item -Path $contentPath\* -Destination $Destination -Recurse -Force } else { $metadata = Invoke-RestMethod https://api.github.com/repos/powershell/powershell/releases/latest $release = $metadata.tag_name -replace '^v' @@ -120,16 +135,29 @@ try { $packagePath = Join-Path -Path $tempDir -ChildPath $packageName Invoke-WebRequest -Uri $downloadURL -OutFile $packagePath + $contentPath = Join-Path -Path $tempDir -ChildPath "new" + New-Item -ItemType Directory -Path $contentPath > $null if ($IsWinEnv) { - Expand-Archive -Path $packagePath -DestinationPath $Destination + Expand-Archive -Path $packagePath -DestinationPath $contentPath } else { - tar zxf $packagePath -C $Destination + tar zxf $packagePath -C $contentPath } } + Remove-Destination $Destination + if (Test-Path $Destination) { + Write-Verbose "Copying files" -Verbose + # only copy files as folders will already exist at $Destination + Get-ChildItem -Recurse -Path "$contentPath" -File | ForEach-Object { + $DestinationFilePath = Join-Path $Destination $_.fullname.replace($contentPath,"") + Copy-Item $_.fullname -Destination $DestinationFilePath + } + } else { + Move-Item -Path $contentPath -Destination $Destination + } ## Change the mode of 'pwsh' to 'rwxr-xr-x' to allow execution - if (-not $IsWinEnv) { chmod 755 "$Destination/pwsh" } + if (-not $IsWinEnv) { chmod 755 $Destination/pwsh } if ($AddToPath) { if ($IsWinEnv -and (-not $env:Path.Contains($Destination))) { @@ -179,6 +207,9 @@ try { } Write-Host "PowerShell Core has been installed at $Destination" -ForegroundColor Green + if ($Destination -eq $PSHome) { + Write-Host "Please restart pwsh" -ForegroundColor Magenta + } } finally { Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue }