Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8610845
Enhance GitHub Action to support multiple OS and PowerShell versions;…
MariusStorhaug Apr 20, 2025
a26e566
Fix workflow strategy to ensure fail-fast behavior is explicitly set
MariusStorhaug Apr 20, 2025
c5bbec5
Add version testing step to Action-Test workflow
MariusStorhaug Apr 20, 2025
03ceafa
Refactor PowerShell installation process to improve version handling …
MariusStorhaug Apr 20, 2025
2362a3a
Enhance macOS installation process for PowerShell: add version retrie…
MariusStorhaug Apr 20, 2025
e108e4d
Refactor PowerShell installation process: improve version checking, u…
MariusStorhaug Apr 20, 2025
ad96cf2
Enhance version comparison logic in PowerShell installation: implemen…
MariusStorhaug Apr 20, 2025
df3c67e
Enhance version comparison logic in PowerShell installation: parse ve…
MariusStorhaug Apr 20, 2025
0fcd8c8
Fix version handling in PowerShell installation: trim 'v' prefix from…
MariusStorhaug Apr 20, 2025
4afaeb0
Fix version input handling and enhance version comparison logic in Po…
MariusStorhaug Apr 20, 2025
e67fd07
Enhance PowerShell installation logic: improve version comparison, st…
MariusStorhaug Apr 20, 2025
23bddd9
Enhance PowerShell installation on Linux: add version normalization, …
MariusStorhaug Apr 20, 2025
cb59766
Refactor PowerShell installation logic: improve version comparison fu…
MariusStorhaug Apr 20, 2025
9272ace
Refactor PowerShell installation action: improve input handling, stre…
MariusStorhaug Apr 20, 2025
4fb301b
Refactor action.yml: standardize input naming, remove unused package …
MariusStorhaug Apr 20, 2025
247296a
Refactor PowerShell installation steps: remove shared environment set…
MariusStorhaug Apr 20, 2025
e05baed
Refactor logging in PowerShell installation: replace custom log funct…
MariusStorhaug Apr 20, 2025
f6ff12f
Refactor action.yml: streamline description formatting, enhance error…
MariusStorhaug Apr 20, 2025
ba2b99a
Refactor Windows installation: enhance version detection logic, impro…
MariusStorhaug Apr 20, 2025
662112c
Refactor Linux installation: implement APT package manager support fo…
MariusStorhaug Apr 20, 2025
4b3e22e
Refactor Debian/Ubuntu installation: update APT package handling to d…
MariusStorhaug Apr 20, 2025
b944f3f
Refactor action.yml: standardize ellipsis formatting in echo and Writ…
MariusStorhaug Apr 20, 2025
102f5df
Refactor Action-Test.yml and action.yml: update version matrix for te…
MariusStorhaug Apr 20, 2025
630dd6a
remove uninstall
MariusStorhaug Apr 20, 2025
e924d13
Refactor Action-Test.yml: update version matrix to remove deprecated …
MariusStorhaug Apr 20, 2025
d13e05c
Refactor action.yml: improve PowerShell version detection logic and e…
MariusStorhaug Apr 20, 2025
e4428e1
Enhance output messaging: add requested PowerShell version to install…
MariusStorhaug Apr 20, 2025
1588830
Enhance Windows installation: add '/force' argument to msiexec for Po…
MariusStorhaug Apr 20, 2025
82866d5
Fix Windows installation: add 'REINSTALL=ALL' argument to msiexec for…
MariusStorhaug Apr 20, 2025
34bc667
Fix Windows installation: correct msiexec argument formatting for pro…
MariusStorhaug Apr 20, 2025
47cf607
Fix Windows installation: simplify msiexec command by removing Start-…
MariusStorhaug Apr 20, 2025
6db690c
Fix Windows installation: update msiexec command to use Start-Process…
MariusStorhaug Apr 20, 2025
a772963
Refactor PowerShell installation: enhance version resolution and impr…
MariusStorhaug Apr 20, 2025
4d59103
Refactor PowerShell installation: improve version resolution logic fo…
MariusStorhaug Apr 20, 2025
eea5f4d
Fix formatting in PowerShell version input description for consistency
MariusStorhaug Apr 20, 2025
a5f6597
Refactor Action-Test workflow: enhance version matrix to include 'nul…
MariusStorhaug Apr 20, 2025
985f7da
Refactor Action-Test workflow: update job name formatting for clarity…
MariusStorhaug Apr 20, 2025
948a179
Refactor PowerShell installation: improve logic for fetching the late…
MariusStorhaug Apr 20, 2025
45bce54
Refactor PowerShell installation: streamline version resolution logic…
MariusStorhaug Apr 20, 2025
ddd52b1
Refactor PowerShell installation: improve comments for clarity; stand…
MariusStorhaug Apr 20, 2025
d026fe5
Refactor PowerShell installation: correct APT package manager message…
MariusStorhaug Apr 20, 2025
0ae9ecf
Refactor PowerShell installation: add echo statements to display requ…
MariusStorhaug Apr 20, 2025
a9b92d6
Refactor PowerShell installation: update version input handling to on…
MariusStorhaug Apr 20, 2025
d7e3064
Refactor PowerShell installation: improve version resolution logic fo…
MariusStorhaug Apr 20, 2025
4967815
Refactor PowerShell installation: enhance version resolution for macO…
MariusStorhaug Apr 20, 2025
b08f77b
Refactor action metadata: update descriptions for clarity and consist…
MariusStorhaug Apr 21, 2025
0d5c320
docs: add blank line for improved readability in README.md
MariusStorhaug Apr 21, 2025
6e04ef4
Refactor PowerShell installation: update curl command to fail silentl…
MariusStorhaug Apr 21, 2025
9b2d4fc
Refactor PowerShell installation: update curl command to use jq for i…
MariusStorhaug Apr 21, 2025
5fb5941
Refactor PowerShell installation: enhance API calls with authenticati…
MariusStorhaug Apr 21, 2025
b9fb488
Refactor PowerShell installation: add GITHUB_TOKEN environment variab…
MariusStorhaug Apr 21, 2025
c269d85
Refactor Action-Test workflow: add GITHUB_TOKEN to environment variab…
MariusStorhaug Apr 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/linters/.jscpd.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"consoleFull"
],
"ignore": [
"**/tests/**"
"**/tests/**",
"**/action.yml"
],
"absolute": true
}
45 changes: 40 additions & 5 deletions .github/workflows/Action-Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,50 @@ permissions:

jobs:
ActionTestBasic:
name: Action-Test - [Basic]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
version: ['latest', '7.4.7', '7.5.0']
runs-on: ${{ matrix.os }}
name: '${{ matrix.os }} - [${{ matrix.version }}]'
steps:
# Need to check out as part of the test, as its a local action
- name: Checkout repo
uses: actions/checkout@v4

- name: Action-Test
uses: ./
with:
working-directory: ./tests
subject: PSModule
Version: ${{ matrix.version }}

- name: Verify installed version
shell: pwsh
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
# Requested version that came from the matrix
$requested = '${{ matrix.version }}'

# When empty / 'null' / 'latest' → resolve to latest stable release
if ([string]::IsNullOrWhiteSpace($requested) -or
$requested.Trim().ToLower() -in @('latest','null')) {

$requested = (
Invoke-RestMethod -Uri 'https://api.github.com/repos/PowerShell/PowerShell/releases/latest' `
-Headers @{
'Accept' = 'application/vnd.github+json'
'Authorization' = "Bearer $($env:GITHUB_TOKEN)"
'X-GitHub-Api-Version' = '2022-11-28'
}
).tag_name.TrimStart('v')
Write-Host "Resolved 'latest' → $requested"
}

# Actual version installed by the action
$installed = ($PSVersionTable.PSVersion).ToString()
Write-Host "Installed PowerShell version: $installed"
Write-Host "Expected PowerShell version: $requested"

if ($installed -ne $requested) {
throw "Failed: expected $requested but got $installed"
}
62 changes: 53 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
# Template-Action
# Install-PowerShell

A template repository for GitHub Actions
A cross‑platform GitHub Action that installs a specific **PowerShell Core** version—or the latest stable release—on any GitHub‑hosted runner
(Linux, macOS, or Windows). The action automatically skips installation when the requested version is already present.

## Usage

### Inputs
Add the action to a job in your workflow file:

### Secrets

### Outputs
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

### Example
- name: Install PowerShell
uses: PSModule/install-powershell@v1
with:
Version: 7.5.0

```yaml
Example here
- name: Run a PowerShell script
shell: pwsh
run: |
Write-Host "Using PowerShell $($PSVersionTable.PSVersion)"
```

## Inputs

| Input | Required | Default | Description |
| ------- | -------- | ------- | ----------- |
| `Version` | `false` | `latest` | Desired PowerShell Core version (e.g. `7.4.1`). Use `latest` to install the newest stable release. |

## Secrets

This action does **not** require any secrets.

## Outputs

This action does **not** generate any outputs.

## How it works

* **Version resolution**
If `Version` is set to `latest` (case‑insensitive), the action queries the GitHub API for the newest stable release tag in the
`PowerShell/PowerShell` repository and substitutes that version.

* **Skip logic**
Before installing, the action checks the current runner to see whether the requested version is already available
(`pwsh -Command $($PSVersionTable.PSVersion)`). If it matches, the step ends immediately.

* **Platform‑specific installers**

| Runner OS | Install strategy |
| --------- | ---------------- |
| **Linux** (Debian/Ubuntu‑based) | Uses APT if available; otherwise downloads the `.deb` asset directly from the release page and installs with `dpkg`. |
| **macOS** | Prefers Homebrew Cask (`brew install --cask powershell`) and falls back to downloading the `.pkg` installer. ARCH detection (`arm64` / `x64`) is automatic. |
| **Windows** | Downloads the corresponding `.msi` package and installs silently with `msiexec`. |

* **Error handling**
The step fails with a clear error message if the requested version cannot be resolved or if the operating‑system distribution is unsupported (e.g., non‑APT Linux distros).
229 changes: 192 additions & 37 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,48 +1,203 @@
name: {{ NAME }}
description: {{ DESCRIPTION }}
name: Install PowerShell
description: |
Install a specific version —or the latest stable version— of PowerShell Core
on any GitHub runner (Linux, macOS, Windows).
Skips the install if the requested version is already present.
author: PSModule
branding:
icon: upload-cloud
color: white
icon: terminal
color: purple

inputs:
subject:
description: The subject to greet
required: false
default: World
Debug:
description: Enable debug output.
required: false
default: 'false'
Verbose:
description: Enable verbose output.
required: false
default: 'false'
Version:
description: Specifies the version of the GitHub module to be installed. The value must be an exact version.
required: false
Prerelease:
description: Allow prerelease versions if available.
description: |
PowerShell version to install (e.g. `7.4.1`).
Defaults to install the latest stable release.
required: false
default: 'false'
WorkingDirectory:
description: The working directory where the script will run from.
required: false
default: ${{ github.workspace }}
default: 'latest'

runs:
using: composite
steps:
- name: {{ NAME }}
uses: PSModule/GitHub-Script@v1
- name: Install PowerShell (Linux)
if: runner.os == 'Linux'
shell: bash
env:
REQUESTED_VERSION: ${{ inputs.Version }}
GITHUB_TOKEN: ${{ github.token }}
run: |
set -e

echo "Requested version: [$REQUESTED_VERSION]"

# Only resolve to latest version if explicitly set to 'latest' (case-insensitive)
case "${REQUESTED_VERSION:-}" in
[Ll][Aa][Tt][Ee][Ss][Tt])
REQUESTED_VERSION=$(
curl -s -f \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/PowerShell/PowerShell/releases/latest |
jq -r '.tag_name' | sed 's/^v//'
)
echo "Latest stable PowerShell release detected: $REQUESTED_VERSION"
;;
"")
echo "Error: Version input is required (or use 'latest')"
exit 1
;;
esac

DETECTED_VERSION=$(pwsh -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()' 2>/dev/null || true)
if [[ "$DETECTED_VERSION" == "$REQUESTED_VERSION" ]]; then
echo "PowerShell $DETECTED_VERSION already installed. Skipping."
exit 0
fi

if command -v apt-get >/dev/null; then
echo "Using APT package manager (Debian/Ubuntu)..."

if ! grep -q "packages.microsoft.com" /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null; then
wget -qO- https://packages.microsoft.com/keys/microsoft.asc \
| sudo tee /etc/apt/trusted.gpg.d/microsoft.asc > /dev/null
DIST_CODENAME=$(lsb_release -cs)
sudo add-apt-repository \
"deb [arch=$(dpkg --print-architecture)] https://packages.microsoft.com/ubuntu/$DIST_CODENAME/prod $DIST_CODENAME main"
fi

sudo apt-get update -y
EXACT_PKG=$(apt-cache madison powershell | awk '{print $3}' \
| grep -E "^${REQUESTED_VERSION}(-|$)" | head -n1 || true)

if [[ -n "$EXACT_PKG" ]]; then
sudo apt-get install -y powershell=$EXACT_PKG
else
ARCH=$(dpkg --print-architecture)
DEB_NAME="powershell_${REQUESTED_VERSION}-1.deb_${ARCH}.deb"
URL="https://github.com/PowerShell/PowerShell/releases/download/v${REQUESTED_VERSION}/${DEB_NAME}"
wget -q "$URL" -O "$DEB_NAME"
sudo dpkg -i "$DEB_NAME" || sudo apt-get -f install -y
fi
else
echo "Unsupported Linux distribution (no apt-get)."
exit 1
fi

- name: Install PowerShell (macOS)
if: runner.os == 'macOS'
shell: bash
env:
{{ ORG }}_{{ NAME }}_INPUT_subject: ${{ inputs.subject }}
with:
Debug: ${{ inputs.Debug }}
Prerelease: ${{ inputs.Prerelease }}
Verbose: ${{ inputs.Verbose }}
Version: ${{ inputs.Version }}
WorkingDirectory: ${{ inputs.WorkingDirectory }}
Script: |
# {{ NAME }}
${{ github.action_path }}/scripts/main.ps1
REQUESTED_VERSION: ${{ inputs.Version }}
GITHUB_TOKEN: ${{ github.token }}
run: |
set -e

echo "Requested version: [$REQUESTED_VERSION]"

# Convert to lowercase for comparison (macOS-compatible method)
REQ_VER_LOWER=$(echo "$REQUESTED_VERSION" | tr '[:upper:]' '[:lower:]')

# Only resolve to latest version if explicitly set to 'latest'
if [[ "$REQ_VER_LOWER" == "latest" ]]; then
REQUESTED_VERSION=$(
curl -s -f \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/PowerShell/PowerShell/releases/latest |
jq -r '.tag_name' | sed 's/^v//'
)
echo "Latest stable PowerShell release detected: $REQUESTED_VERSION"
fi

# Validate REQUESTED_VERSION is not empty
if [[ -z "${REQUESTED_VERSION}" ]]; then
echo "Error: Could not determine a valid PowerShell version."
exit 1
fi

DETECTED_VERSION=$(pwsh -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()' 2>/dev/null || true)
if [[ "$DETECTED_VERSION" == "$REQUESTED_VERSION" ]]; then
echo "PowerShell $DETECTED_VERSION already installed. Skipping."
exit 0
fi

# Try Homebrew first (simplified approach)
if command -v brew >/dev/null; then
echo "Using Homebrew package manager..."
# Homebrew handles 'latest' automatically when no version is specified
if [[ "$REQ_VER_LOWER" == "latest" ]]; then
brew install --cask powershell
else
# Try specific version formula first
if brew install --cask "powershell@$REQUESTED_VERSION" 2>/dev/null; then
echo "Successfully installed via Homebrew"
else
# Fall back to generic formula if versioned one doesn't exist
echo "Version-specific formula not found, installing latest via Homebrew"
brew install --cask powershell
fi
fi
else
# Fall back to direct download
echo "Homebrew not available, downloading directly..."
ARCH=$(uname -m)
case "$ARCH" in
"arm64") PKG_NAME="powershell-${REQUESTED_VERSION}-osx-arm64.pkg" ;;
*) PKG_NAME="powershell-${REQUESTED_VERSION}-osx-x64.pkg" ;;
esac

URL="https://github.com/PowerShell/PowerShell/releases/download/v${REQUESTED_VERSION}/${PKG_NAME}"
echo "Downloading from: $URL"
if ! curl -sSL "$URL" -o "$PKG_NAME"; then
echo "Error: Failed to download PowerShell package"
exit 1
fi
sudo installer -pkg "$PKG_NAME" -target /
fi

- name: Install PowerShell (Windows)
if: runner.os == 'Windows'
shell: powershell
env:
REQUESTED_VERSION: ${{ inputs.Version }}
GITHUB_TOKEN: ${{ github.token }}
run: |
Write-Host "Requested version: [$REQUESTED_VERSION]"
# Only resolve to latest version if explicitly set to 'latest' (case-insensitive)
$req = $env:REQUESTED_VERSION
if ($req -and $req.Trim().ToLower() -eq 'latest') {
$latest = (
Invoke-RestMethod -Uri 'https://api.github.com/repos/PowerShell/PowerShell/releases/latest' `
-Headers @{
'Accept' = 'application/vnd.github+json'
'Authorization' = "Bearer $($env:GITHUB_TOKEN)"
'X-GitHub-Api-Version' = '2022-11-28'
}
).tag_name.TrimStart('v')
Write-Host "Latest stable PowerShell release detected: $latest"
$env:REQUESTED_VERSION = $latest
} elseif ([string]::IsNullOrWhiteSpace($req)) {
Write-Host "Error: Version input is required (or use 'latest')"
exit 1
}

try {
$detected = (pwsh -NoLogo -NoProfile -Command '$PSVersionTable.PSVersion.ToString()')
} catch {
$detected = $null
}

Write-Host "Detected PowerShell version: $detected"
Write-Host "Requested PowerShell version: $env:REQUESTED_VERSION"

if ($detected -eq $env:REQUESTED_VERSION) {
Write-Host "PowerShell $detected already installed. Skipping."
exit 0
}

$msi = "PowerShell-$($env:REQUESTED_VERSION)-win-x64.msi"
$url = "https://github.com/PowerShell/PowerShell/releases/download/v$($env:REQUESTED_VERSION)/$msi"
Invoke-WebRequest -Uri $url -OutFile $msi -UseBasicParsing
Start-Process msiexec.exe -ArgumentList '/i', $msi, '/quiet', '/norestart' -Wait
Loading
Loading