From 83e1d64669cc170ef6e1456d1e15f931dc6a4062 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 14 Nov 2017 10:45:08 -0800 Subject: [PATCH] Enable install-powershell.ps1 to update the current running powershell (#5429) 1. Remove `[validate]` attribute from parameter so this script can be invoked directly from the web. This doesn't have any negative impact as the $Destination parameter will have a default value if null or empty. 2. Move removal of destination folder later as installing the package requires package management module and archive module (on Windows) 3. On Windows, because files have open handles when run from existing powershell-daily install, I rename the existing files and copy over the new ones. User needs to exit and restart `pwsh` to take effect (similar to macOS/Linux where you have to exit and restart anyways) --- tools/install-powershell.ps1 | 63 +++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) 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 }