Public/Set-DevVmPersistentPath.ps1

<#
.SYNOPSIS
Add a runtime to the user's persistent PATH environment variable.
 
.DESCRIPTION
Set-DevVmPersistentPath adds the specified runtime version to the user's PATH environment variable permanently.
This allows the runtime to be available in all future terminal sessions without requiring activation.
 
The function:
- Adds the runtime path to the beginning of the user PATH (highest priority)
- Removes any existing entries for the same runtime to prevent duplicates
- Requires no administrator privileges (modifies user-level PATH only)
- Updates both the persistent PATH and the current session PATH
 
.PARAMETER Runtime
The name of the runtime (e.g., 'node', 'java', 'maven').
 
.PARAMETER Version
The version of the runtime to add to PATH.
 
.PARAMETER BasePath
The base installation path for the runtime.
 
.PARAMETER BinPath
The subdirectory containing executables (default: 'bin').
 
.EXAMPLE
Set-DevVmPersistentPath -Runtime node -Version 18.16.0 -BasePath C:\node
 
Adds Node.js 18.16.0 to the user's persistent PATH.
 
.EXAMPLE
Set-DevVmPersistentPath -Runtime java -Version 17.0.5 -BasePath C:\java -BinPath 'bin'
 
Adds Java 17.0.5 to the user's persistent PATH with a custom bin subdirectory.
 
.NOTES
This function modifies the user-level PATH environment variable. The changes will take effect
in new terminal sessions. The current session is also updated immediately.
#>

function Set-DevVmPersistentPath {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([System.Boolean])]
    param(
        [Parameter(Mandatory)]
        [string]$Runtime,

        [Parameter(Mandatory)]
        [string]$Version,

        [Parameter(Mandatory)]
        [string]$BasePath,

        [string]$BinPath = 'bin'
    )

    if (-not $PSCmdlet.ShouldProcess("User PATH", "Add persistent PATH for $Runtime $Version")) {
        return $false
    }

    try {
        # Build the version path
        $versionPath = Join-Path -Path $BasePath -ChildPath $Version
        $fullPath = if ($BinPath -and (Test-Path (Join-Path $versionPath $BinPath))) {
            Join-Path $versionPath $BinPath
        } else {
            $versionPath
        }

        if (-not (Test-Path $fullPath)) {
            Write-Error "Path does not exist: $fullPath"
            return $false
        }

        # Get current user PATH
        $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
        $pathArray = @($userPath -split ';' | Where-Object { $_ })

        # Remove any existing paths for this runtime's base
        $baseLower = $BasePath.ToLower()
        $pathArray = @($pathArray | Where-Object {
            $_.ToLower() -notlike "$baseLower*"
        })

        # Add new path at the beginning (highest priority)
        $pathArray = @($fullPath) + $pathArray

        # Remove duplicates
        $pathArray = @($pathArray | Select-Object -Unique)

        # Update user PATH
        $newPath = $pathArray -join ';'
        [Environment]::SetEnvironmentVariable('Path', $newPath, 'User')

        Write-Information "Successfully added $Runtime $Version to persistent PATH" -InformationAction Continue
        Write-Information " Path: $fullPath" -InformationAction Continue
        Write-Information " Scope: User (no admin required)" -InformationAction Continue

        # Also update current session
        $env:Path = $newPath + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')

        return $true
    }
    catch {
        Write-Error "Failed to persist PATH: $_"
        return $false
    }
}