Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/powershell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Installs PowerShell along with needed dependencies. Useful for base Dockerfiles

```json
"features": {
"ghcr.io/devcontainers/features/powershell:1": {}
"ghcr.io/devcontainers/features/powershell:2": {}
}
```

Expand Down
12 changes: 7 additions & 5 deletions src/powershell/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "powershell",
"version": "1.5.1",
"version": "2.0.0",
"name": "PowerShell",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/powershell",
"description": "Installs PowerShell along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
Expand All @@ -9,18 +9,20 @@
"type": "string",
"proposals": [
"latest",
"lts",
"preview",
"stable",
"none",
"7.4",
"7.3",
"7.2"
"7.5",
"7.4"
],
"default": "latest",
"description": "Select or enter a version of PowerShell."
},
"modules": {
"type": "string",
"default": "",
"description": "Optional comma separated list of PowerShell modules to install. If you need to install a specific version of a module, use '==' to specify the version (e.g. 'az.resources==2.5.0')"
"description": "Optional comma separated list of PowerShell modules to install. If you need to install a specific version of a module, use '==' to specify the version (e.g. 'az.resources==2.5.0')."
},
"powershellProfileURL": {
"type": "string",
Expand Down
125 changes: 115 additions & 10 deletions src/powershell/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ clean_cache() {
rm -rf /var/cache/dnf/*
fi
}
# Function to resolve PowerShell version from Microsoft redirect URLs
resolve_powershell_version() {
local version_tag="$1"
local redirect_url="https://aka.ms/powershell-release?tag=${version_tag}"

# Follow the redirect and extract the version from the final URL
local resolved_url
resolved_url=$(curl -sSL -o /dev/null -w '%{url_effective}' "${redirect_url}")

# Extract version from URL (e.g., https://github.com/PowerShell/PowerShell/releases/tag/v7.4.7 -> 7.4.7)
local resolved_version
resolved_version=$(echo "${resolved_url}" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+(-\w+\.\d+)?' || echo "")

if [ -z "${resolved_version}" ]; then
echo "Failed to resolve version for tag: ${version_tag}" >&2
return 1
fi

echo "${resolved_version}"
}
# Install dependencies for RHEL/CentOS/AlmaLinux (DNF-based systems)
install_using_dnf() {
dnf remove -y curl-minimal
Expand Down Expand Up @@ -100,6 +120,58 @@ detect_package_manager() {
fi
}

# Function to find the latest preview version from git tags
find_preview_version_from_git_tags() {
local variable_name=$1
local requested_version=${!variable_name}
local repository_url=$2

if [ -z "${googlegit_cmd_name}" ]; then
if type git > /dev/null 2>&1; then
git_cmd_name="git"
else
echo "Git not found. Cannot determine preview version."
return 1
fi
fi

# Fetch tags from remote repository
local tags
tags=$(git ls-remote --tags "${repository_url}" 2>/dev/null | grep -oP 'refs/tags/v\K[0-9]+\.[0-9]+\.[0-9]+-preview\.[0-9]+' | sort -V)

if [ -z "${tags}" ]; then
echo "No preview tags found in repository."
return 1
fi

local version=""

if [ "${requested_version}" = "preview" ] || [ "${requested_version}" = "latest" ]; then
# Get the latest preview version
version=$(echo "${tags}" | tail -n 1)
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+$ ]]; then
# Partial version provided (e.g., "7.6"), find latest preview matching that major.minor
version=$(echo "${tags}" | grep "^${requested_version}\." | tail -n 1)
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-preview$ ]]; then
# Version like "7.6.0-preview" provided, find latest preview for that version
local base_version="${requested_version%-preview}"
version=$(echo "${tags}" | grep "^${base_version}-preview\." | tail -n 1)
elif [[ "${requested_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-preview\.[0-9]+$ ]]; then
# Exact preview version provided, verify it exists
if echo "${tags}" | grep -q "^${requested_version}$"; then
version="${requested_version}"
fi
fi

if [ -z "${version}" ]; then
echo "Could not find matching preview version for: ${requested_version}"
return 1
fi

declare -g "${variable_name}=${version}"
echo "${variable_name}=${version}"
}

# Figure out correct version of a three part version number is not passed
find_version_from_git_tags() {
local variable_name=$1
Expand Down Expand Up @@ -159,7 +231,8 @@ apt_get_update()
for package in "$@"; do
if ! dnf list installed "$package" > /dev/null 2>&1; then
echo "Package $package not installed. Installing using dnf..."
dnf install -y "$package"
# Use --allowerasing to handle conflicts like curl-minimal vs curl
dnf install -y --allowerasing "$package"
else
echo "Package $package is already installed (DNF)."
fi
Expand Down Expand Up @@ -292,16 +365,30 @@ install_pwsh() {

install_using_github() {
# Fall back on direct download if no apt package exists in microsoft pool
check_packages curl ca-certificates gnupg2 dirmngr libc6 libgcc1 libgssapi-krb5-2 libstdc++6 libunwind8 libuuid1 zlib1g libicu[0-9][0-9]
if command -v apt-get > /dev/null 2>&1; then
# Debian/Ubuntu dependencies
check_packages curl ca-certificates gnupg2 dirmngr libc6 libgcc1 libgssapi-krb5-2 libstdc++6 libunwind8 libuuid1 zlib1g libicu[0-9][0-9]
elif command -v dnf > /dev/null 2>&1; then
# AlmaLinux/RHEL dependencies
check_packages curl ca-certificates gnupg2 glibc libgcc krb5-libs libstdc++ libuuid zlib libicu wget tar
fi
if ! type git > /dev/null 2>&1; then
check_packages git
fi

if [ "${architecture}" = "amd64" ]; then
if [ "${architecture}" = "amd64" ] || [ "${architecture}" = "x86_64" ]; then
architecture="x64"
elif [ "${architecture}" = "aarch64" ]; then
architecture="arm64"
fi
pwsh_url="https://github.com/PowerShell/PowerShell"
find_version_from_git_tags POWERSHELL_VERSION $pwsh_url
# Check if we need to find a preview version or stable version
if [[ "${POWERSHELL_VERSION}" == *"preview"* ]] || [ "${POWERSHELL_VERSION}" = "preview" ]; then
echo "Finding preview version..."
find_preview_version_from_git_tags POWERSHELL_VERSION "${pwsh_url}"
else
find_version_from_git_tags POWERSHELL_VERSION "${pwsh_url}"
fi

install_pwsh "${POWERSHELL_VERSION}"
if grep -q "Not Found" "${powershell_filename}"; then
install_prev_pwsh $pwsh_url
Expand All @@ -312,7 +399,6 @@ install_using_github() {
mkdir ~/powershell
tar -xvf powershell-${POWERSHELL_VERSION}-linux-x64.tar.gz -C ~/powershell


powershell_archive_sha256="$(cat release.html | tr '\n' ' ' | sed 's|<[^>]*>||g' | grep -oP "${powershell_filename}\s+\K[0-9a-fA-F]{64}" || echo '')"
if [ -z "${powershell_archive_sha256}" ]; then
echo "(!) WARNING: Failed to retrieve SHA256 for archive. Skipping validaiton."
Expand All @@ -323,13 +409,33 @@ install_using_github() {
tar xf "${powershell_filename}" -C "${powershell_target_path}"
chmod 755 "${powershell_target_path}/pwsh"
ln -sf "${powershell_target_path}/pwsh" /usr/bin/pwsh
add-shell "/usr/bin/pwsh"
# Add pwsh to /etc/shells
if command -v add-shell > /dev/null 2>&1; then
# Debian/Ubuntu - use add-shell
add-shell "/usr/bin/pwsh"
else
# AlmaLinux/RHEL - manually add to /etc/shells - add-shell is not available in almalinux repos and manual approach is simpler than adding a dependency just for this
if ! grep -q "/usr/bin/pwsh" /etc/shells; then
echo "/usr/bin/pwsh" >> /etc/shells
fi
fi
cd /tmp
rm -rf /tmp/pwsh
}

if ! type pwsh >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
if [ "${POWERSHELL_VERSION}" = "lts" ] || [ "${POWERSHELL_VERSION}" = "stable" ] || [ "${POWERSHELL_VERSION}" = "preview" ]; then
echo "Resolving PowerShell '${POWERSHELL_VERSION}' version from Microsoft..."
resolved_version=$(resolve_powershell_version "${POWERSHELL_VERSION}")
if [ -n "${resolved_version}" ]; then
echo "Resolved '${POWERSHELL_VERSION}' to version: ${resolved_version}"
POWERSHELL_VERSION="${resolved_version}"
else
echo "Warning: Could not resolve '${POWERSHELL_VERSION}' version. Falling back to 'latest'."
POWERSHELL_VERSION="latest"
fi
fi

# Source /etc/os-release to get OS info
. /etc/os-release
Expand All @@ -340,11 +446,10 @@ if ! type pwsh >/dev/null 2>&1; then
POWERSHELL_ARCHIVE_ARCHITECTURES="${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"
fi

if [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_UBUNTU}"* ]] && [[ "${POWERSHELL_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]]; then
if [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_UBUNTU}"* ]] && [[ "${POWERSHELL_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]] && [[ "${POWERSHELL_VERSION}" != *"preview"* ]]; then
install_using_apt || use_github="true"
elif [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"* ]]; then
elif [[ "${POWERSHELL_ARCHIVE_ARCHITECTURES}" = *"${POWERSHELL_ARCHIVE_ARCHITECTURES_ALMALINUX}"* ]] && [[ "${POWERSHELL_VERSION}" != *"preview"* ]]; then
install_using_dnf && install_powershell_dnf || use_github="true"

else
use_github="true"
fi
Expand Down
3 changes: 3 additions & 0 deletions test/powershell/install_modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ set -e
# Import test library for `check` command
source dev-container-features-test-lib

check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"

# Extension-specific tests
check "az.resources" pwsh -Command "(Get-Module -ListAvailable -Name Az.Resources).Version.ToString()"
check "az.storage" pwsh -Command "(Get-Module -ListAvailable -Name Az.Storage).Version.ToString()"
Expand Down
4 changes: 3 additions & 1 deletion test/powershell/install_powershell_fallback_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,10 @@ install_pwsh() {

install_using_github() {
mode=$1
if [ "${architecture}" = "amd64" ]; then
if [ "${architecture}" = "amd64" ] || [ "${architecture}" = "x86_64" ]; then
architecture="x64"
elif [ "${architecture}" = "aarch64" ]; then
architecture="arm64"
fi
pwsh_url="https://github.com/PowerShell/PowerShell"
POWERSHELL_VERSION="7.4.xyz"
Expand Down
14 changes: 14 additions & 0 deletions test/powershell/powershell_lts_version_almalinux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test LTS version installation on AlmaLinux
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_lts_version_debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test LTS version installation on Debian
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is LTS (not preview)" bash -c "pwsh --version | grep -v 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_preview_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test preview version installation
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_preview_version_almalinux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test preview version installation on AlmaLinux
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_preview_version_debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test preview version installation on Debian
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is preview" bash -c "pwsh --version | grep -i 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_stable_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test stable version installation
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is stable (not preview)" bash -c "pwsh --version | grep -v 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_stable_version_almalinux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test stable version installation on AlmaLinux
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is stable (not preview)" bash -c "pwsh --version | grep -v 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/powershell/powershell_stable_version_debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e

# Import test library for `check` command
source dev-container-features-test-lib

# Test stable version installation on Debian
check "pwsh is installed" bash -c "command -v pwsh"
check "pwsh version is stable (not preview)" bash -c "pwsh --version | grep -v 'preview'"
check "pwsh can execute basic command" bash -c "pwsh -Command 'Write-Output Hello'"

# Report result
reportResults
Loading