tasks/70-WslDistros.ps1
|
@{ Id = 'WslDistros' DisplayName = 'WSL distros' Description = 'Installs configured WSL distros and relocates each to WslHome via `wsl --manage --move`' Action = { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(Mandatory)] [System.Collections.IDictionary] $Paths ) Write-Header -Name 'WSL Distros' if (-not (Get-Command wsl -ErrorAction SilentlyContinue)) { Write-Status -Level Skip -Message ' [SKIP] WSL is not installed.' return } # Force UTF-8 output from wsl.exe so parsing isn't broken by UTF-16LE. # Restore the previous value (or remove it) on the way out so the env # var doesn't leak into the parent shell. $previousWslUtf8 = $env:WSL_UTF8 $env:WSL_UTF8 = '1' try { # `wsl --manage --move` was introduced in WSL 2.4.4 (Nov 2024). Fail # cleanly on older versions instead of producing a confusing error. $wslHelp = wsl --help 2>&1 | Out-String if ($wslHelp -notmatch '--manage') { Write-Status -Level Skip -Message ' [SKIP] WSL --manage is not supported (requires WSL 2.4.4+). Run `wsl --update` and retry.' return } # Docker Desktop manages its own WSL distros; relocating them via # `wsl --manage --move` will break Docker. Use the "Disk image location" # setting in Docker Desktop's Resources -> Advanced UI instead. $excluded = @('docker-desktop', 'docker-desktop-data') # --- Step 1: install configured distros that aren't installed yet --- $configured = @(Get-WslDistrosConfig) if ($configured.Count -gt 0) { $existing = @(wsl -l -q | Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim() }) foreach ($name in $configured) { if ($name -in $existing) { continue } if ($PSCmdlet.ShouldProcess($name, 'wsl --install -d')) { Write-Status -Level Info -Message " [INFO] Installing WSL distro '$name'..." wsl --install -d $name --no-launch 2>&1 | Format-ToolOutput if ($LASTEXITCODE -ne 0) { throw ("wsl --install -d {0} failed with exit code {1}." -f $name, $LASTEXITCODE) } Write-Status -Level Info -Message " [INFO] $name installed." } } } # --- Step 2: relocate every installed distro to the configured target --- # Re-query so any distro installed in Step 1 is included. $distros = wsl -l -q | Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim() } if (-not $distros) { Write-Status -Level Skip -Message ' [SKIP] No WSL distros found.' return } $toMigrate = foreach ($name in $distros) { if ($name -in $excluded) { Write-Status -Level Skip -Message " [SKIP] $name (managed by Docker Desktop; relocate via Docker settings instead)" continue } $targetDir = Join-Path $Paths.WslHome $name if (Test-Path -Path $targetDir -PathType Container) { Write-Status -Level Info -Message " [INFO] $name already exists at $targetDir" continue } [PSCustomObject]@{ Name = $name; Target = $targetDir } } if (-not $toMigrate) { return } if ($PSCmdlet.ShouldProcess('WSL', 'Shut down before relocating distros')) { Write-Status -Level Info -Message ' [INFO] Shutting down WSL before migrating...' wsl --shutdown 2>&1 | Format-ToolOutput } foreach ($d in $toMigrate) { if ($PSCmdlet.ShouldProcess($d.Name, "Relocate to $($d.Target)")) { Write-Status -Level Info -Message " [INFO] Relocating $($d.Name) to $($d.Target)..." wsl --manage $d.Name --move "$($d.Target)\" 2>&1 | Format-ToolOutput Write-Status -Level Info -Message " [INFO] $($d.Name) migrated." } } } finally { if ($null -eq $previousWslUtf8) { Remove-Item Env:\WSL_UTF8 -ErrorAction SilentlyContinue } else { $env:WSL_UTF8 = $previousWslUtf8 } } } } |