Skip to content

Commit c03a876

Browse files
Refactor installation logic for PowerShell across platforms to skip installation if the requested version is already installed
1 parent 55afe33 commit c03a876

File tree

1 file changed

+69
-51
lines changed

1 file changed

+69
-51
lines changed

action.yml

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Install PowerShell
22
description: |
3-
Install a specific versionor the latest stable version of PowerShell Core
3+
Install a specific version, or the latest stable version, of PowerShell Core
44
on any GitHub runner (Linux, macOS, Windows).
55
Skips the install if the requested version is already present.
66
author: PSModule
@@ -29,7 +29,6 @@ runs:
2929
run: |
3030
# Install-PowerShell
3131
set -e
32-
3332
echo "Requested version: [$REQUESTED_VERSION]"
3433
3534
# Only resolve to latest version if explicitly set to 'latest' (case-insensitive)
@@ -73,30 +72,26 @@ runs:
7372
URL="https://github.com/PowerShell/PowerShell/releases/download/v${REQUESTED_VERSION}/${DEB_NAME}"
7473
echo "Downloading from: $URL"
7574
wget -q "$URL" -O "$DEB_NAME"
76-
echo "Starting installation of PowerShell [$REQUESTED_VERSION)]..."
75+
echo "Starting installation of PowerShell [$REQUESTED_VERSION]..."
7776
sudo dpkg -i "$DEB_NAME" || sudo apt-get -f install -y
78-
echo "Installation complete. PowerShell [$REQUESTED_VERSION] is now available."
7977
elif command -v rpm >/dev/null; then
8078
# RHEL/Fedora/CentOS based
8179
echo "Detected RHEL/Fedora/CentOS based system..."
82-
8380
if [[ "$ARCH" == "aarch64" ]]; then
8481
RPM_NAME="powershell-${REQUESTED_VERSION}-1.rh.${ARCH}.rpm"
8582
else
8683
RPM_NAME="powershell-${REQUESTED_VERSION}-1.rh.x86_64.rpm"
8784
fi
88-
8985
URL="https://github.com/PowerShell/PowerShell/releases/download/v${REQUESTED_VERSION}/${RPM_NAME}"
9086
echo "Downloading from: $URL"
9187
wget -q "$URL" -O "$RPM_NAME"
92-
echo "Starting installation of PowerShell [$REQUESTED_VERSION)]..."
88+
echo "Starting installation of PowerShell [$REQUESTED_VERSION]..."
9389
sudo rpm -i "$RPM_NAME" || sudo yum install -y "$RPM_NAME"
94-
echo "Installation complete. PowerShell [$REQUESTED_VERSION] is now available."
9590
else
9691
echo "Unsupported Linux distribution. Cannot determine package format."
9792
exit 1
9893
fi
99-
echo "PowerShell [$REQUESTED_VERSION] installed successfully."
94+
echo "Installation complete. PowerShell [$REQUESTED_VERSION] is now available."
10095
10196
- name: Install PowerShell (macOS)
10297
if: runner.os == 'macOS'
@@ -108,7 +103,6 @@ runs:
108103
run: |
109104
# Install-PowerShell
110105
set -e
111-
112106
echo "Requested version: [$REQUESTED_VERSION]"
113107
114108
# Only resolve to latest version if explicitly set to 'latest' (case-insensitive)
@@ -151,15 +145,13 @@ runs:
151145
152146
URL="https://github.com/PowerShell/PowerShell/releases/download/v${REQUESTED_VERSION}/${PKG_NAME}"
153147
echo "Downloading from: $URL"
154-
155148
echo "Starting installation of PowerShell [$REQUESTED_VERSION]..."
156149
157150
if ! curl -sSL "$URL" -o "$PKG_NAME"; then
158151
echo "Error: Failed to download PowerShell package"
159152
exit 1
160153
fi
161154
sudo installer -pkg "$PKG_NAME" -target /
162-
163155
echo "Installation complete. PowerShell [$REQUESTED_VERSION] is now available."
164156
165157
- name: Install PowerShell (Windows)
@@ -173,7 +165,7 @@ runs:
173165
# Install-PowerShell
174166
Write-Host "Requested version: [$env:REQUESTED_VERSION]"
175167
176-
# Only resolve to latest version if explicitly set to 'latest' (case-insensitive)
168+
# Resolve 'latest' → concrete version
177169
$req = $env:REQUESTED_VERSION
178170
if ($req -and $req.Trim().ToLower() -eq 'latest') {
179171
$latest = (
@@ -191,24 +183,25 @@ runs:
191183
exit 1
192184
}
193185
186+
# Detect currently installed version (if any)
187+
$detected = $null
194188
try {
195189
$detected = (pwsh -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()')
196190
Write-Host "Currently installed PowerShell version: $detected"
197191
} catch {
198192
Write-Host "PowerShell is not currently installed"
199-
$detected = $null
200193
}
201194
202195
if ($detected -eq $env:REQUESTED_VERSION) {
203196
Write-Host "PowerShell $detected already installed. Skipping."
204197
exit 0
205198
}
206199
207-
# Check if we need to handle a downgrade scenario
200+
# Downgrade detection
208201
$isDowngrade = $false
209202
if ($detected -and $detected -ne $env:REQUESTED_VERSION) {
210203
try {
211-
$detectedVersion = [version]$detected
204+
$detectedVersion = [version]$detected
212205
$requestedVersion = [version]$env:REQUESTED_VERSION
213206
if ($detectedVersion -gt $requestedVersion) {
214207
Write-Host "Downgrade detected: $detected → $($env:REQUESTED_VERSION)"
@@ -221,47 +214,72 @@ runs:
221214
}
222215
}
223216
217+
# If downgrade → fully uninstall current PowerShell 7
218+
if ($isDowngrade) {
219+
Write-Host "Uninstalling existing PowerShell version before downgrade..."
220+
221+
# Search both 64-bit and 32-bit uninstall hives
222+
$regPaths = @(
223+
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
224+
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
225+
)
226+
227+
$pwshEntries = Get-ItemProperty -Path $regPaths -ErrorAction SilentlyContinue |
228+
Where-Object {
229+
$_.Publisher -eq 'Microsoft Corporation' -and
230+
$_.DisplayName -like 'PowerShell 7*' -and
231+
$_.DisplayName -notlike '*Preview*' -and
232+
$_.DisplayVersion -and
233+
$_.DisplayVersion.StartsWith($detected)
234+
}
235+
236+
$targetEntry = $pwshEntries | Select-Object -First 1
237+
if (-not $targetEntry) {
238+
Write-Host "Warning: Could not find an uninstall entry for PowerShell $detected"
239+
} else {
240+
$uninstallCmd = if ($targetEntry.QuietUninstallString) {
241+
$targetEntry.QuietUninstallString
242+
} else {
243+
$targetEntry.UninstallString
244+
}
245+
246+
# If the uninstall command is MSI-based and lacks /quiet, add it
247+
if ($uninstallCmd -match 'msiexec') {
248+
if ($uninstallCmd -notmatch '/quiet') { $uninstallCmd += ' /quiet' }
249+
if ($uninstallCmd -notmatch '/norestart') { $uninstallCmd += ' /norestart' }
250+
}
251+
252+
Write-Host "Running uninstall command:`n$uninstallCmd"
253+
$proc = Start-Process 'cmd.exe' -ArgumentList '/c', $uninstallCmd -Wait -PassThru
254+
if ($proc.ExitCode -ne 0) {
255+
Write-Host "Error: Uninstall failed (exit code $($proc.ExitCode))."
256+
exit 1
257+
}
258+
259+
# Double-check removal
260+
try {
261+
$after = (pwsh -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()')
262+
if ($after) {
263+
Write-Host "Error: PowerShell is still present ($after) after uninstall. Aborting downgrade."
264+
exit 1
265+
}
266+
} catch { }
267+
}
268+
}
269+
270+
# Download requested MSI
224271
$msi = "PowerShell-$($env:REQUESTED_VERSION)-win-x64.msi"
225272
$url = "https://github.com/PowerShell/PowerShell/releases/download/v$($env:REQUESTED_VERSION)/$msi"
226273
Write-Host "Downloading from: $url"
227274
228-
if (-not (Invoke-WebRequest -Uri $url -OutFile $msi -UseBasicParsing -PassThru)) {
229-
Write-Host "Error: Failed to download PowerShell package"
230-
exit 1
231-
}
275+
$null = Invoke-WebRequest -Uri $url -OutFile $msi -UseBasicParsing -ErrorAction Stop
232276
277+
# Install requested version
233278
Write-Host "Starting installation of PowerShell [$($env:REQUESTED_VERSION)]..."
234-
235-
if ($isDowngrade) {
236-
# For downgrades, uninstall the existing version first, then install the new one
237-
Write-Host "Downgrade detected - uninstalling existing PowerShell version first..."
238-
239-
# Find PowerShell installation to uninstall
240-
$uninstallString = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
241-
Where-Object { $_.DisplayName -like "*PowerShell*" -and $_.Publisher -eq "Microsoft Corporation" } |
242-
Select-Object -First 1 -ExpandProperty UninstallString
243-
244-
if ($uninstallString) {
245-
Write-Host "Found existing PowerShell installation, uninstalling..."
246-
# Extract the product code from the uninstall string
247-
if ($uninstallString -match '{[0-9A-F-]+}') {
248-
$productCode = $matches[0]
249-
Write-Host "Uninstalling PowerShell with product code: $productCode"
250-
Start-Process msiexec.exe -ArgumentList '/x', $productCode, '/quiet', '/norestart' -Wait
251-
Write-Host "Uninstall completed"
252-
} else {
253-
Write-Host "Warning: Could not extract product code from uninstall string: $uninstallString"
254-
}
255-
} else {
256-
Write-Host "Warning: Could not find PowerShell installation to uninstall"
257-
}
258-
259-
# Now install the new version
260-
Write-Host "Installing PowerShell [$($env:REQUESTED_VERSION)]..."
261-
Start-Process msiexec.exe -ArgumentList '/i', $msi, '/quiet', '/norestart' -Wait
262-
} else {
263-
# For upgrades or fresh installs, use regular install
264-
Start-Process msiexec.exe -ArgumentList '/i', $msi, '/quiet', '/norestart' -Wait
279+
$msiProcess = Start-Process msiexec.exe -ArgumentList '/i', $msi, '/quiet', '/norestart' -Wait -PassThru
280+
if ($msiProcess.ExitCode -ne 0) {
281+
Write-Host "Error: Installation failed (exit code $($msiProcess.ExitCode))."
282+
exit 1
265283
}
266284
267285
Write-Host "Installation complete. PowerShell [$($env:REQUESTED_VERSION)] is now available."

0 commit comments

Comments
 (0)