diff --git a/src/powershell/README.md b/src/powershell/README.md index f09ac1f02..59a391a2b 100644 --- a/src/powershell/README.md +++ b/src/powershell/README.md @@ -18,6 +18,7 @@ Installs PowerShell along with needed dependencies. Useful for base Dockerfiles | version | Select or enter a version of PowerShell. | string | latest | | modules | 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') | string | - | | powershellProfileURL | Optional (publicly accessible) URL to download PowerShell profile. | string | - | +| preserveHistory | Optional Enable to preserve the powershell history across container restart/rebuilds | boolean | true | ## Customizations diff --git a/src/powershell/devcontainer-feature.json b/src/powershell/devcontainer-feature.json index 009f4c238..906d4bbcf 100644 --- a/src/powershell/devcontainer-feature.json +++ b/src/powershell/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "powershell", - "version": "2.0.2", + "version": "2.0.3", "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.", @@ -28,6 +28,11 @@ "type": "string", "default": "", "description": "Optional (publicly accessible) URL to download PowerShell profile." + }, + "preserveHistory": { + "type": "boolean", + "default": true, + "description": "Optional Enable to preserve the powershell history across container restart/rebuilds" } }, "customizations": { @@ -44,6 +49,16 @@ ] } }, + "mounts": [ + { + "type": "volume", + "source": "${devcontainerId}-powershell-history", + "target": "/dc/powershell" + } + ], + "onCreateCommand": { + "powershell": "/usr/local/share/powershell/scripts/oncreate.sh" + }, "installsAfter": [ "ghcr.io/devcontainers/features/common-utils" ] diff --git a/src/powershell/install.sh b/src/powershell/install.sh index cabd2cbb4..942bf6d8e 100755 --- a/src/powershell/install.sh +++ b/src/powershell/install.sh @@ -9,12 +9,16 @@ set -e +# Capture the location of this script once so later directory changes do not affect relative file lookups. +SOURCE_DIR="$(pwd)" + # Clean up rm -rf /var/lib/apt/lists/* POWERSHELL_VERSION=${VERSION:-"latest"} POWERSHELL_MODULES="${MODULES:-""}" POWERSHELL_PROFILE_URL="${POWERSHELLPROFILEURL}" +PRESERVE_HISTORY="${PRESERVEHISTORY}" MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" #MICROSOFT_GPG_KEYS_URI=$(curl https://packages.microsoft.com/keys/microsoft.asc -o /usr/share/keyrings/microsoft-archive-keyring.gpg) @@ -494,7 +498,30 @@ if [ -n "$POWERSHELL_PROFILE_URL" ]; then echo "Downloading PowerShell Profile from: $POWERSHELL_PROFILE_URL" # Get profile path from currently installed pwsh profilePath=$(pwsh -noni -c '$PROFILE.AllUsersAllHosts') - sudo -E curl -sSL -o "$profilePath" "$POWERSHELL_PROFILE_URL" + # Download to a temp file first so a non-200 response never overwrites the profile + tmpProfile="$(mktemp)" + http_status=$(curl -sSL -w '%{http_code}' -o "$tmpProfile" "$POWERSHELL_PROFILE_URL") + if [ "$http_status" = "200" ]; then + mv "$tmpProfile" "$profilePath" + else + echo "Failed to download PowerShell profile (HTTP ${http_status}). Skipping profile update." >&2 + rm -f "$tmpProfile" + fi +fi + +# Copy persistent history setup script +ONCREATE_SOURCE="${SOURCE_DIR}/oncreate.sh" +SCRIPTS_DIR="/usr/local/share/powershell/scripts" +mkdir -p "$SCRIPTS_DIR" +echo "Checking oncreate.sh" +if [ ! -f "$ONCREATE_SOURCE" ]; then + echo "oncreate.sh not found at expected path: $ONCREATE_SOURCE" >&2 + exit 1 +fi +if [ -f "$ONCREATE_SOURCE" ]; then + cp "$ONCREATE_SOURCE" "$SCRIPTS_DIR/oncreate.sh" + sed -i "s|preserveHistoryFromInstallSh|${PRESERVE_HISTORY}|" "$SCRIPTS_DIR/oncreate.sh" + chmod +x "$SCRIPTS_DIR/oncreate.sh" fi # Clean up diff --git a/src/powershell/oncreate.sh b/src/powershell/oncreate.sh new file mode 100644 index 000000000..c9f6f5a0a --- /dev/null +++ b/src/powershell/oncreate.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e + +PRESERVE_HISTORY="preserveHistoryFromInstallSh" +HISTORY_SAVE_LINE='Set-PSReadLineOption -HistorySavePath /dc/powershell/history.txt' + +if [ "${PRESERVE_HISTORY}" = "true" ]; then + if [ "$(stat -c '%u:%g' "/dc/powershell")" = "$(id -u):$(id -g)" ]; then + echo "Already owned by the current user, nothing to do" + elif [ "$(id -u)" -eq 0 ]; then + chown -R "$(id -u):$(id -g)" "/dc/powershell" + elif command -v sudo >/dev/null 2>&1; then + sudo chown -R "$(id -u):$(id -g)" "/dc/powershell" + else + echo "Warning: unable to chown /dc/powershell (current user not root and no sudo available); history may not persist." >&2 + fi + profile_path="$(pwsh -NoProfile -Command '$PROFILE')" + mkdir -p "$(dirname "$profile_path")" + touch "$profile_path" + + if ! grep -Fxq "$HISTORY_SAVE_LINE" "$profile_path"; then + printf '\n%s\n' "$HISTORY_SAVE_LINE" >> "$profile_path" + fi +fi