|
<# |
|
.SYNOPSIS |
|
Interactive PowerShell script to set environment variables for WSL access. |
|
|
|
.DESCRIPTION |
|
This script allows setting multiple environment variables that will be accessible in WSL. |
|
It's pre-seeded with GITHUB_TOKEN and prompts for additional key-value pairs. |
|
Each variable can have WSLENV flags applied for path conversion or case transformation. |
|
|
|
.EXAMPLE |
|
.\Set-WSLEnvironmentVariables.ps1 |
|
Runs in interactive mode for setting environment variables |
|
|
|
.EXAMPLE |
|
.\Set-WSLEnvironmentVariables.ps1 secrets.json |
|
Runs in file mode using JSON configuration |
|
|
|
.EXAMPLE |
|
.\Set-WSLEnvironmentVariables.ps1 .env |
|
Runs in file mode using .env file |
|
|
|
.NOTES |
|
WSLENV Flags: |
|
- /p : Convert Windows path to WSL path |
|
- /l : Convert to lowercase |
|
- /u : Convert to uppercase |
|
- /up : Convert path and append to existing value |
|
- (none) : Pass as-is |
|
#> |
|
|
|
[CmdletBinding()] |
|
param( |
|
[Parameter(Position=0)] |
|
[string]$ConfigFile |
|
) |
|
|
|
function Get-SanitizedValue { |
|
param( |
|
[string]$VariableName, |
|
[string]$Value, |
|
[int]$ShowChars = 4 |
|
) |
|
|
|
if ([string]::IsNullOrEmpty($Value)) { |
|
return "(not set)" |
|
} |
|
|
|
if ($VariableName.Contains("TOKEN") -or $VariableName.Contains("KEY") -or $VariableName.Contains("SECRET") -or $VariableName.Contains("PASSWORD")) { |
|
if ($Value.Length -le ($ShowChars * 2)) { |
|
# Value too short, just mask it all |
|
return "*" * $Value.Length |
|
} else { |
|
# Show first and last N chars with asterisks in between |
|
$firstChars = $Value.Substring(0, $ShowChars) |
|
$lastChars = $Value.Substring($Value.Length - $ShowChars, $ShowChars) |
|
$middleLength = $Value.Length - ($ShowChars * 2) |
|
return "$firstChars$('*' * $middleLength)$lastChars" |
|
} |
|
} |
|
|
|
return $Value |
|
} |
|
|
|
Write-Host "WSL Environment Variable Setup" -ForegroundColor Cyan |
|
Write-Host "=============================" -ForegroundColor Cyan |
|
Write-Host "" |
|
|
|
# Determine mode: Interactive vs File-based |
|
$isInteractiveMode = [string]::IsNullOrEmpty($ConfigFile) |
|
|
|
if ($isInteractiveMode) { |
|
Write-Host "Running in INTERACTIVE mode" -ForegroundColor Yellow |
|
Write-Host "" |
|
|
|
# Interactive mode: Check existing WSLENV to determine pre-seeded variables |
|
$currentWSLENV = [Environment]::GetEnvironmentVariable("WSLENV", "User") |
|
$envVars = @{} |
|
|
|
if ([string]::IsNullOrEmpty($currentWSLENV)) { |
|
# No existing WSLENV - start with GITHUB_TOKEN |
|
Write-Host "No existing WSLENV found. Starting with GITHUB_TOKEN as default." -ForegroundColor Yellow |
|
$envVars["GITHUB_TOKEN"] = @{ Value = ""; Flag = "" } |
|
} else { |
|
# Parse existing WSLENV and pre-seed with those variables |
|
Write-Host "Found existing WSLENV: $currentWSLENV" -ForegroundColor Green |
|
Write-Host "Pre-seeding with existing environment variables..." -ForegroundColor Green |
|
Write-Host "" |
|
|
|
$existingVars = $currentWSLENV -split ":" |
|
foreach ($varEntry in $existingVars) { |
|
if (![string]::IsNullOrEmpty($varEntry)) { |
|
$parts = $varEntry -split "/" |
|
$varName = $parts[0] |
|
$varFlag = if ($parts.Length -gt 1) { $parts[1] } else { "" } |
|
|
|
# Get current value from Windows environment |
|
$currentValue = [Environment]::GetEnvironmentVariable($varName, "User") |
|
|
|
$envVars[$varName] = @{ |
|
Value = if ($currentValue) { $currentValue } else { "" } |
|
Flag = $varFlag |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
Write-Host "Running in FILE mode: $ConfigFile" -ForegroundColor Yellow |
|
Write-Host "" |
|
|
|
# File mode: Load configuration from file |
|
if (-not (Test-Path $ConfigFile)) { |
|
Write-Host "Configuration file not found: $ConfigFile" -ForegroundColor Red |
|
exit 1 |
|
} |
|
|
|
$envVars = @{} |
|
$fileExtension = [System.IO.Path]::GetExtension($ConfigFile).ToLower() |
|
|
|
try { |
|
switch ($fileExtension) { |
|
'.json' { |
|
Write-Host "Loading JSON configuration..." -ForegroundColor Green |
|
$config = Get-Content $ConfigFile -Raw | ConvertFrom-Json |
|
|
|
foreach ($property in $config.PSObject.Properties) { |
|
$varName = $property.Name |
|
$varConfig = $property.Value |
|
|
|
if ($varConfig -is [string]) { |
|
# Simple string value |
|
$envVars[$varName] = @{ Value = $varConfig; Flag = "" } |
|
} else { |
|
# Object with value and flag |
|
$envVars[$varName] = @{ |
|
Value = if ($varConfig.Value) { $varConfig.Value } else { "" } |
|
Flag = if ($varConfig.Flag) { $varConfig.Flag } else { "" } |
|
} |
|
} |
|
} |
|
} |
|
'.env' { |
|
Write-Host "Loading .env configuration..." -ForegroundColor Green |
|
$lines = Get-Content $ConfigFile |
|
|
|
foreach ($line in $lines) { |
|
if ($line -match '^\s*#' -or [string]::IsNullOrWhiteSpace($line)) { |
|
continue # Skip comments and empty lines |
|
} |
|
|
|
if ($line -match '^([^=]+)=(.*)$') { |
|
$varName = $matches[1].Trim() |
|
$varValue = $matches[2].Trim() |
|
|
|
# Remove quotes if present |
|
if ($varValue -match "^[`"'](.*)[`"']$") { |
|
$varValue = $matches[1] |
|
} |
|
|
|
$envVars[$varName] = @{ Value = $varValue; Flag = "" } |
|
} |
|
} |
|
} |
|
default { |
|
Write-Host "Unsupported file format: $fileExtension" -ForegroundColor Red |
|
Write-Host "Supported formats: .json, .env" -ForegroundColor Yellow |
|
exit 1 |
|
} |
|
} |
|
|
|
Write-Host "Loaded $($envVars.Count) variables from $ConfigFile" -ForegroundColor Green |
|
|
|
} catch { |
|
Write-Host "Error reading configuration file: $($_.Exception.Message)" -ForegroundColor Red |
|
exit 1 |
|
} |
|
} |
|
|
|
if ($isInteractiveMode) { |
|
Write-Host "WSLENV Flag Options:" -ForegroundColor Yellow |
|
Write-Host " (empty) - Pass as-is (use for: API keys, tokens, simple values)" |
|
Write-Host " Example: GITHUB_TOKEN, ANTHROPIC_API_KEY" |
|
Write-Host "" |
|
Write-Host " /p - Convert Windows path to WSL path (use for: file paths, directories)" |
|
Write-Host " Example: C:\Tools becomes /mnt/c/Tools" |
|
Write-Host "" |
|
Write-Host " /l - Convert to lowercase (use for: case-sensitive systems)" |
|
Write-Host " Example: MyValue becomes myvalue" |
|
Write-Host "" |
|
Write-Host " /u - Convert to uppercase (use for: environment standards)" |
|
Write-Host " Example: myvalue becomes MYVALUE" |
|
Write-Host "" |
|
Write-Host " /up - Convert path AND add to existing WSL variable (use for: PATH-like variables)" |
|
Write-Host " Example: Add Windows path to existing WSL PATH variable" |
|
Write-Host "" |
|
|
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan |
|
Write-Host "║ STEP 1: Review Pre-seeded Variables ║" -ForegroundColor Cyan |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan |
|
Write-Host "" |
|
|
|
foreach ($varName in @($envVars.Keys)) { # Create array copy to avoid modification during enumeration |
|
$var = $envVars[$varName] |
|
$currentValue = $var.Value |
|
$flagText = if ([string]::IsNullOrEmpty($var.Flag)) { "(no flag)" } else { "/$($var.Flag)" } |
|
|
|
Write-Host "" |
|
Write-Host "Variable: $varName $flagText" -ForegroundColor Cyan |
|
|
|
if (![string]::IsNullOrEmpty($currentValue)) { |
|
$maskedValue = Get-SanitizedValue -VariableName $varName -Value $currentValue |
|
Write-Host "Current value: $maskedValue" -ForegroundColor White |
|
} else { |
|
Write-Host "Current value: (not set)" -ForegroundColor Gray |
|
} |
|
|
|
# Get user action for this variable |
|
if (![string]::IsNullOrEmpty($currentValue)) { |
|
# Variable has current value |
|
$action = Read-Host "Action for $varName - (k)eep current, (u)pdate value, or (r)emove? [k/u/r]" |
|
|
|
switch ($action.ToLower()) { |
|
'k' { |
|
Write-Host "Keeping current value for $varName" -ForegroundColor Green |
|
} |
|
'u' { |
|
if ($varName.Contains("TOKEN") -or $varName.Contains("KEY") -or $varName.Contains("SECRET")) { |
|
$newValue = Read-Host "Enter new value for $varName" -AsSecureString |
|
$newValue = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($newValue)) |
|
} else { |
|
$newValue = Read-Host "Enter new value for $varName" |
|
} |
|
|
|
if (![string]::IsNullOrWhiteSpace($newValue)) { |
|
$envVars[$varName].Value = $newValue |
|
Write-Host "Updated $varName" -ForegroundColor Green |
|
} else { |
|
Write-Host "Empty value provided, keeping current value" -ForegroundColor Yellow |
|
} |
|
} |
|
'r' { |
|
Write-Host "Removing $varName" -ForegroundColor Red |
|
$envVars.Remove($varName) |
|
continue |
|
} |
|
default { |
|
Write-Host "Invalid choice, keeping current value for $varName" -ForegroundColor Yellow |
|
} |
|
} |
|
} else { |
|
# Variable has no current value |
|
if ($varName.Contains("TOKEN") -or $varName.Contains("KEY") -or $varName.Contains("SECRET")) { |
|
$newValue = Read-Host "Enter value for $varName (press Enter to remove from WSLENV)" -AsSecureString |
|
$newValue = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($newValue)) |
|
} else { |
|
$newValue = Read-Host "Enter value for $varName (press Enter to remove from WSLENV)" |
|
} |
|
|
|
if ([string]::IsNullOrWhiteSpace($newValue)) { |
|
Write-Host "Removing $varName (no value provided)" -ForegroundColor Red |
|
$envVars.Remove($varName) |
|
continue |
|
} else { |
|
$envVars[$varName].Value = $newValue |
|
Write-Host "Set value for $varName" -ForegroundColor Green |
|
} |
|
} |
|
|
|
# Get flag (only if variable is being kept) |
|
if ($envVars.ContainsKey($varName)) { |
|
$newFlag = Read-Host "Enter WSLENV flag for $varName (press Enter to keep current: $flagText)" |
|
if (![string]::IsNullOrWhiteSpace($newFlag)) { |
|
$envVars[$varName].Flag = $newFlag.TrimStart('/') |
|
} |
|
} |
|
} |
|
|
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan |
|
Write-Host "║ STEP 2: Add Additional Environment Variables ║" -ForegroundColor Cyan |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan |
|
Write-Host "" |
|
Write-Host "Enter additional environment variables (press Enter with empty key to finish):" -ForegroundColor Green |
|
Write-Host "" |
|
|
|
# Interactive loop for additional variables |
|
while ($true) { |
|
$key = Read-Host "Environment variable name" |
|
|
|
# Exit condition |
|
if ([string]::IsNullOrWhiteSpace($key)) { |
|
break |
|
} |
|
|
|
# Validate key name |
|
if ($key -notmatch '^[A-Za-z_][A-Za-z0-9_]*$') { |
|
Write-Host "Invalid variable name. Use letters, numbers, and underscores only. Must start with letter or underscore." -ForegroundColor Red |
|
continue |
|
} |
|
|
|
# Check for duplicate |
|
if ($envVars.ContainsKey($key.ToUpper())) { |
|
Write-Host "Variable '$key' already exists. Skipping." -ForegroundColor Yellow |
|
continue |
|
} |
|
|
|
# Get value |
|
do { |
|
if ($key.ToUpper().Contains("TOKEN") -or $key.ToUpper().Contains("KEY") -or $key.ToUpper().Contains("SECRET")) { |
|
$value = Read-Host "Enter value for $key (will be hidden)" -AsSecureString |
|
$value = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($value)) |
|
} else { |
|
$value = Read-Host "Enter value for $key" |
|
} |
|
|
|
if ([string]::IsNullOrWhiteSpace($value)) { |
|
Write-Host "Value cannot be empty. Please try again." -ForegroundColor Red |
|
} |
|
} while ([string]::IsNullOrWhiteSpace($value)) |
|
|
|
# Get flag |
|
$flag = Read-Host "Enter WSLENV flag for $key (press Enter for none)" |
|
|
|
# Store the variable |
|
$envVars[$key.ToUpper()] = @{ |
|
Value = $value |
|
Flag = $flag.TrimStart('/') |
|
} |
|
|
|
Write-Host "Added: $($key.ToUpper())" -ForegroundColor Green |
|
Write-Host "" |
|
} |
|
} |
|
|
|
# Summary |
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan |
|
Write-Host "║ STEP 3: Review Variables to Set ║" -ForegroundColor Cyan |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan |
|
Write-Host "" |
|
foreach ($var in $envVars.GetEnumerator()) { |
|
$flagText = if ([string]::IsNullOrEmpty($var.Value.Flag)) { "(no flag)" } else { "/$($var.Value.Flag)" } |
|
$maskedValue = Get-SanitizedValue -VariableName $var.Key -Value $var.Value.Value |
|
Write-Host " $($var.Key): $maskedValue $flagText" -ForegroundColor White |
|
} |
|
|
|
Write-Host "" |
|
$confirm = Read-Host "Proceed with setting these variables? (y/N)" |
|
if ($confirm -ne 'y' -and $confirm -ne 'Y') { |
|
Write-Host "Cancelled." -ForegroundColor Yellow |
|
exit |
|
} |
|
|
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan |
|
Write-Host "║ STEP 4: Setting Environment Variables ║" -ForegroundColor Cyan |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan |
|
Write-Host "" |
|
|
|
# Set individual environment variables |
|
$successCount = 0 |
|
foreach ($var in $envVars.GetEnumerator()) { |
|
try { |
|
[Environment]::SetEnvironmentVariable($var.Key, $var.Value.Value, "User") |
|
Write-Host "✓ Set $($var.Key)" -ForegroundColor Green |
|
$successCount++ |
|
} |
|
catch { |
|
Write-Host "✗ Failed to set $($var.Key): $($_.Exception.Message)" -ForegroundColor Red |
|
} |
|
} |
|
|
|
if ($successCount -eq 0) { |
|
Write-Host "No variables were set. Exiting." -ForegroundColor Red |
|
exit 1 |
|
} |
|
|
|
# Build WSLENV string |
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan |
|
Write-Host "║ STEP 5: Configure WSLENV ║" -ForegroundColor Cyan |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan |
|
Write-Host "" |
|
|
|
# Get current WSLENV to preserve unrelated variables |
|
$currentWSLENV = [Environment]::GetEnvironmentVariable("WSLENV", "User") |
|
$existingParts = @() |
|
|
|
if (![string]::IsNullOrEmpty($currentWSLENV)) { |
|
# Find variables that exist in current WSLENV but are NOT in our envVars list |
|
# These will be preserved in the final WSLENV |
|
$existingParts = $currentWSLENV -split ":" | Where-Object { |
|
if (![string]::IsNullOrEmpty($_)) { |
|
$varName = ($_ -split "/" | Select-Object -First 1) |
|
$varName -notin $envVars.Keys |
|
} |
|
} |
|
} |
|
|
|
# Build new parts for our variables |
|
$newParts = @() |
|
foreach ($var in $envVars.GetEnumerator()) { |
|
if ([string]::IsNullOrEmpty($var.Value.Flag)) { |
|
$newParts += $var.Key |
|
} else { |
|
$newParts += "$($var.Key)/$($var.Value.Flag)" |
|
} |
|
} |
|
|
|
# Combine existing (filtered) + new parts |
|
$allParts = $existingParts + $newParts | Where-Object { ![string]::IsNullOrEmpty($_) } |
|
$wslenvValue = $allParts -join ":" |
|
|
|
try { |
|
[Environment]::SetEnvironmentVariable("WSLENV", $wslenvValue, "User") |
|
Write-Host "✓ Set WSLENV: $wslenvValue" -ForegroundColor Green |
|
} |
|
catch { |
|
Write-Host "✗ Failed to set WSLENV: $($_.Exception.Message)" -ForegroundColor Red |
|
exit 1 |
|
} |
|
|
|
Write-Host "" |
|
Write-Host "╔══════════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Green |
|
Write-Host "║ SETUP COMPLETE! ║" -ForegroundColor Green |
|
Write-Host "╚══════════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Green |
|
Write-Host "Environment variables have been set at the User level and configured for WSL access." |
|
Write-Host "" |
|
|
|
Write-Host "IMPORTANT: Restart Required" -ForegroundColor Red |
|
Write-Host "=========================" -ForegroundColor Red |
|
Write-Host "1. Close this PowerShell window" |
|
Write-Host "2. Open a new PowerShell or Terminal window" |
|
Write-Host "3. Start a new WSL session" |
|
Write-Host "" |
|
Write-Host "Why restart is needed:" -ForegroundColor Yellow |
|
Write-Host "- Windows needs to reload User environment variables" |
|
Write-Host "- WSL needs to read the updated WSLENV configuration" |
|
Write-Host "- Existing sessions won't see the new variables" |
|
Write-Host "" |
|
|
|
Write-Host "To verify environment variables are working:" -ForegroundColor Green |
|
Write-Host "" |
|
Write-Host "Option 1 - From PowerShell (after restart):" -ForegroundColor Cyan |
|
Write-Host " wsl -- printenv | Select-String '$($envVars.Keys -join '|')'" |
|
Write-Host "" |
|
Write-Host "Option 2 - Inside WSL distro (after restart):" -ForegroundColor Cyan |
|
Write-Host " # Start WSL session first:" |
|
Write-Host " wsl" |
|
Write-Host " # Then check variables:" |
|
Write-Host " printenv | grep -E '$($envVars.Keys -join '|')'" |
|
Write-Host " # Or check individual variables:" |
|
foreach ($var in $envVars.Keys) { |
|
Write-Host " echo `$`{$var`}" |
|
} |
|
Write-Host "" |
|
|
|
Write-Host "Expected output:" -ForegroundColor Yellow |
|
Write-Host "Each variable should show its name and value (values will be visible in WSL)" |