From 7362786618a3609bf1b0ef128af418c67e59adbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 00:33:56 +0000 Subject: [PATCH 1/5] Initial plan From ac00fa29223dae5dd0566569318bfeec8bb2455c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 00:59:48 +0000 Subject: [PATCH 2/5] Fix silent error handling in PowerShell install scripts causing false success messages When aspire.exe was locked by another process, Move-Item in Backup-ExistingCliExecutable failed as a non-terminating error and execution continued, causing Expand-Archive to also fail silently and the success message to be displayed regardless. - Wrap Move-Item in Backup-ExistingCliExecutable with try/catch + -ErrorAction Stop in both get-aspire-cli.ps1 and get-aspire-cli-pr.ps1, throwing a clear actionable message when the backup fails - Add -ErrorAction Stop to Expand-Archive in both scripts so extraction failures are caught by the existing catch block - Add exit-code check for tar in get-aspire-cli.ps1 (pr variant already had it) Co-authored-by: radical <1472+radical@users.noreply.github.com> --- eng/scripts/get-aspire-cli-pr.ps1 | 9 +++++++-- eng/scripts/get-aspire-cli.ps1 | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/eng/scripts/get-aspire-cli-pr.ps1 b/eng/scripts/get-aspire-cli-pr.ps1 index 95b645e5ed1..f99860cc0fe 100755 --- a/eng/scripts/get-aspire-cli-pr.ps1 +++ b/eng/scripts/get-aspire-cli-pr.ps1 @@ -401,7 +401,12 @@ function Backup-ExistingCliExecutable { Write-Message "Backing up existing CLI: $TargetExePath -> $backupPath" -Level Verbose # Rename existing executable to .old.[timestamp] - Move-Item -Path $TargetExePath -Destination $backupPath -Force + try { + Move-Item -Path $TargetExePath -Destination $backupPath -Force -ErrorAction Stop + } + catch { + throw "Failed to back up existing CLI at '$TargetExePath'. The file may be in use by another process. Please close any running Aspire CLI instances and try again. Error: $($_.Exception.Message)" + } return $backupPath } } @@ -498,7 +503,7 @@ function Expand-AspireCliArchive { throw "Expand-Archive cmdlet not found. Please use PowerShell 5.0 or later to extract ZIP files." } - Expand-Archive -Path $ArchiveFile -DestinationPath $DestinationPath -Force + Expand-Archive -Path $ArchiveFile -DestinationPath $DestinationPath -Force -ErrorAction Stop } elseif ($ArchiveFile -match "\.tar\.gz$") { # Use tar for tar.gz files diff --git a/eng/scripts/get-aspire-cli.ps1 b/eng/scripts/get-aspire-cli.ps1 index e06ce223bdd..6d208fef9f2 100755 --- a/eng/scripts/get-aspire-cli.ps1 +++ b/eng/scripts/get-aspire-cli.ps1 @@ -633,7 +633,12 @@ function Backup-ExistingCliExecutable { Write-Message "Backing up existing CLI: $TargetExePath -> $backupPath" -Level Verbose # Rename existing executable to .old.[timestamp] - Move-Item -Path $TargetExePath -Destination $backupPath -Force + try { + Move-Item -Path $TargetExePath -Destination $backupPath -Force -ErrorAction Stop + } + catch { + throw "Failed to back up existing CLI at '$TargetExePath'. The file may be in use by another process. Please close any running Aspire CLI instances and try again. Error: $($_.Exception.Message)" + } return $backupPath } } @@ -725,7 +730,7 @@ function Expand-AspireCliArchive { throw "Expand-Archive cmdlet not found. Please use PowerShell 5.0 or later to extract ZIP files." } - Expand-Archive -Path $ArchiveFile -DestinationPath $DestinationPath -Force + Expand-Archive -Path $ArchiveFile -DestinationPath $DestinationPath -Force -ErrorAction Stop } else { # Use tar for tar.gz files on Unix systems @@ -737,6 +742,9 @@ function Expand-AspireCliArchive { try { Set-Location $DestinationPath & tar -xzf $ArchiveFile + if ($LASTEXITCODE -ne 0) { + throw "tar command failed with exit code $LASTEXITCODE" + } } finally { Set-Location $currentLocation From 5f99dc6c9a7e6023865b504ef8624684d1eab9df Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Thu, 19 Mar 2026 22:57:48 -0400 Subject: [PATCH 3/5] Fix installer PowerShell error handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/scripts/get-aspire-cli-pr.ps1 | 10 +++++----- eng/scripts/get-aspire-cli.ps1 | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/eng/scripts/get-aspire-cli-pr.ps1 b/eng/scripts/get-aspire-cli-pr.ps1 index f99860cc0fe..bcd5e790a39 100755 --- a/eng/scripts/get-aspire-cli-pr.ps1 +++ b/eng/scripts/get-aspire-cli-pr.ps1 @@ -432,7 +432,7 @@ function Restore-CliExecutableFromBackup { Remove-Item -Path $TargetExePath -Force -ErrorAction SilentlyContinue } - Move-Item -Path $BackupPath -Destination $TargetExePath -Force + Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop } } @@ -487,7 +487,7 @@ function Expand-AspireCliArchive { # Create destination directory if it doesn't exist if (-not (Test-Path $DestinationPath)) { Write-Message "Creating destination directory: $DestinationPath" -Level Verbose - New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null + New-Item -ItemType Directory -Path $DestinationPath -Force -ErrorAction Stop | Out-Null } else { # Backup existing executable before extraction @@ -662,7 +662,7 @@ function New-TempDirectory { Write-Message "Creating temporary directory: $tempDir" -Level Verbose try { - New-Item -ItemType Directory -Path $tempDir -Force | Out-Null + New-Item -ItemType Directory -Path $tempDir -Force -ErrorAction Stop | Out-Null return $tempDir } catch { @@ -1067,7 +1067,7 @@ function Install-BuiltNugets { } if ($PSCmdlet.ShouldProcess($NugetHiveDir, "Create directory")) { - New-Item -ItemType Directory -Path $NugetHiveDir -Force | Out-Null + New-Item -ItemType Directory -Path $NugetHiveDir -Force -ErrorAction Stop | Out-Null } Write-Message "Copying nugets from $DownloadDir to $NugetHiveDir" -Level Verbose @@ -1083,7 +1083,7 @@ function Install-BuiltNugets { foreach ($file in $nupkgFiles) { if ($PSCmdlet.ShouldProcess($file.FullName, "Copy to $NugetHiveDir")) { - Copy-Item $file.FullName -Destination $NugetHiveDir + Copy-Item $file.FullName -Destination $NugetHiveDir -ErrorAction Stop } } diff --git a/eng/scripts/get-aspire-cli.ps1 b/eng/scripts/get-aspire-cli.ps1 index 6d208fef9f2..dc3090347e0 100755 --- a/eng/scripts/get-aspire-cli.ps1 +++ b/eng/scripts/get-aspire-cli.ps1 @@ -664,7 +664,7 @@ function Restore-CliExecutableFromBackup { Remove-Item -Path $TargetExePath -Force -ErrorAction SilentlyContinue } - Move-Item -Path $BackupPath -Destination $TargetExePath -Force + Move-Item -Path $BackupPath -Destination $TargetExePath -Force -ErrorAction Stop } } @@ -716,7 +716,7 @@ function Expand-AspireCliArchive { # Create destination directory if it doesn't exist if (-not (Test-Path $DestinationPath)) { Write-Message "Creating destination directory: $DestinationPath" -Level Verbose - New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null + New-Item -ItemType Directory -Path $DestinationPath -Force -ErrorAction Stop | Out-Null } else { # Backup existing executable before extraction @@ -1011,7 +1011,7 @@ function Install-AspireExtension { if ($PSCmdlet.ShouldProcess($extractDir, "Extract extension archive")) { # Expand the zip archive if ($Script:IsModernPowerShell) { - Expand-Archive -Path $ExtensionArchive -DestinationPath $extractDir -Force + Expand-Archive -Path $ExtensionArchive -DestinationPath $extractDir -Force -ErrorAction Stop } else { Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($ExtensionArchive, $extractDir) @@ -1174,7 +1174,7 @@ function Install-AspireCli { if ($PSCmdlet.ShouldProcess($InstallPath, "Create temporary directory")) { Write-Message "Creating temporary directory: $tempDir" -Level Verbose try { - New-Item -ItemType Directory -Path $tempDir -Force | Out-Null + New-Item -ItemType Directory -Path $tempDir -Force -ErrorAction Stop | Out-Null } catch { throw "Failed to create temporary directory: $tempDir - $($_.Exception.Message)" @@ -1322,7 +1322,7 @@ function Start-AspireCliInstallation { Write-Message "Creating installation directory: $resolvedInstallPath" -Level Info if ($PSCmdlet.ShouldProcess($resolvedInstallPath, "Create installation directory")) { try { - New-Item -ItemType Directory -Path $resolvedInstallPath -Force | Out-Null + New-Item -ItemType Directory -Path $resolvedInstallPath -Force -ErrorAction Stop | Out-Null } catch { throw "Failed to create installation directory: $resolvedInstallPath - $($_.Exception.Message)" From 1830f0207399198c7650a5c742b398e9d27dc2b1 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Thu, 19 Mar 2026 23:51:43 -0400 Subject: [PATCH 4/5] Handle installer cleanup errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/scripts/get-aspire-cli-pr.ps1 | 6 +++--- eng/scripts/get-aspire-cli.ps1 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/scripts/get-aspire-cli-pr.ps1 b/eng/scripts/get-aspire-cli-pr.ps1 index bcd5e790a39..9b99bbc2b7f 100755 --- a/eng/scripts/get-aspire-cli-pr.ps1 +++ b/eng/scripts/get-aspire-cli-pr.ps1 @@ -456,7 +456,7 @@ function Remove-OldCliBackupFiles { foreach ($backupFile in $oldBackupFiles) { if ($PSCmdlet.ShouldProcess($backupFile.FullName, "Delete old backup")) { try { - Remove-Item -Path $backupFile.FullName -Force + Remove-Item -Path $backupFile.FullName -Force -ErrorAction Stop Write-Message "Deleted old backup file: $($backupFile.FullName)" -Level Verbose } catch { @@ -688,7 +688,7 @@ function Remove-TempDirectory { Write-Message "Cleaning up temporary files..." -Level Verbose try { if ($PSCmdlet.ShouldProcess($TempDir, "Remove temporary directory")) { - Remove-Item $TempDir -Recurse -Force + Remove-Item $TempDir -Recurse -Force -ErrorAction Stop } } catch { @@ -1062,7 +1062,7 @@ function Install-BuiltNugets { if (Test-Path $NugetHiveDir) { Write-Message "Removing existing nuget directory: $NugetHiveDir" -Level Verbose if ($PSCmdlet.ShouldProcess($NugetHiveDir, "Remove existing directory")) { - Remove-Item $NugetHiveDir -Recurse -Force + Remove-Item $NugetHiveDir -Recurse -Force -ErrorAction Stop } } diff --git a/eng/scripts/get-aspire-cli.ps1 b/eng/scripts/get-aspire-cli.ps1 index dc3090347e0..ff7ebe656cc 100755 --- a/eng/scripts/get-aspire-cli.ps1 +++ b/eng/scripts/get-aspire-cli.ps1 @@ -688,7 +688,7 @@ function Remove-OldCliBackupFiles { foreach ($backupFile in $oldBackupFiles) { if ($PSCmdlet.ShouldProcess($backupFile.FullName, "Delete old backup")) { try { - Remove-Item -Path $backupFile.FullName -Force + Remove-Item -Path $backupFile.FullName -Force -ErrorAction Stop Write-Message "Deleted old backup file: $($backupFile.FullName)" -Level Verbose } catch { From c2efe75127e0862677e9f294d17f3d2667099421 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 20 Mar 2026 14:54:06 -0400 Subject: [PATCH 5/5] Align PowerShell installer backup semantics Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/scripts/get-aspire-cli-pr.ps1 | 16 +++++++++------- eng/scripts/get-aspire-cli.ps1 | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/eng/scripts/get-aspire-cli-pr.ps1 b/eng/scripts/get-aspire-cli-pr.ps1 index 95b645e5ed1..3e3686acdca 100755 --- a/eng/scripts/get-aspire-cli-pr.ps1 +++ b/eng/scripts/get-aspire-cli-pr.ps1 @@ -382,9 +382,9 @@ function Get-CliExecutablePath { return Join-Path $DestinationPath $exeName } -# Function to backup existing CLI executable before overwriting -# This allows installation to proceed even when the CLI is running -# The running process still has a handle to the old file, but the file can be renamed +# Function to back up an existing CLI executable before overwriting it. +# This matches self-update semantics by deleting stale *.old.* backups first. +# On Windows, a running process can still block the rename. function Backup-ExistingCliExecutable { [CmdletBinding(SupportsShouldProcess)] [OutputType([string])] @@ -399,7 +399,9 @@ function Backup-ExistingCliExecutable { if ($PSCmdlet.ShouldProcess($TargetExePath, "Backup to $backupPath")) { Write-Message "Backing up existing CLI: $TargetExePath -> $backupPath" -Level Verbose - + + Remove-OldCliBackupFiles -TargetExePath $TargetExePath + # Rename existing executable to .old.[timestamp] Move-Item -Path $TargetExePath -Destination $backupPath -Force return $backupPath @@ -485,8 +487,8 @@ function Expand-AspireCliArchive { New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null } else { - # Backup existing executable before extraction - # This allows installation to proceed even when the CLI is running + # Back up the existing executable before extraction. + # On Windows, this can still fail if the file is locked by a running process. $backupPath = Backup-ExistingCliExecutable -TargetExePath $targetExePath } @@ -523,7 +525,7 @@ function Expand-AspireCliArchive { } # Clean up old backup files on successful extraction - if ($backupPath -and (Test-Path $targetExePath)) { + if (Test-Path $targetExePath) { Remove-OldCliBackupFiles -TargetExePath $targetExePath } diff --git a/eng/scripts/get-aspire-cli.ps1 b/eng/scripts/get-aspire-cli.ps1 index e06ce223bdd..922bb0987f4 100755 --- a/eng/scripts/get-aspire-cli.ps1 +++ b/eng/scripts/get-aspire-cli.ps1 @@ -614,9 +614,9 @@ function Get-CliExecutablePath { return Join-Path $DestinationPath $exeName } -# Function to backup existing CLI executable before overwriting -# This allows installation to proceed even when the CLI is running -# The running process still has a handle to the old file, but the file can be renamed +# Function to back up an existing CLI executable before overwriting it. +# This matches self-update semantics by deleting stale *.old.* backups first. +# On Windows, a running process can still block the rename. function Backup-ExistingCliExecutable { [CmdletBinding(SupportsShouldProcess)] [OutputType([string])] @@ -631,7 +631,9 @@ function Backup-ExistingCliExecutable { if ($PSCmdlet.ShouldProcess($TargetExePath, "Backup to $backupPath")) { Write-Message "Backing up existing CLI: $TargetExePath -> $backupPath" -Level Verbose - + + Remove-OldCliBackupFiles -TargetExePath $TargetExePath + # Rename existing executable to .old.[timestamp] Move-Item -Path $TargetExePath -Destination $backupPath -Force return $backupPath @@ -714,8 +716,8 @@ function Expand-AspireCliArchive { New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null } else { - # Backup existing executable before extraction - # This allows installation to proceed even when the CLI is running + # Back up the existing executable before extraction. + # On Windows, this can still fail if the file is locked by a running process. $backupPath = Backup-ExistingCliExecutable -TargetExePath $targetExePath } @@ -744,7 +746,7 @@ function Expand-AspireCliArchive { } # Clean up old backup files on successful extraction - if ($backupPath -and (Test-Path $targetExePath)) { + if (Test-Path $targetExePath) { Remove-OldCliBackupFiles -TargetExePath $targetExePath }