Skip to content

Instantly share code, notes, and snippets.

@sycomix
Last active July 15, 2025 08:33
Show Gist options
  • Select an option

  • Save sycomix/b887f72867aaec27d0c0e6d4ddee999b to your computer and use it in GitHub Desktop.

Select an option

Save sycomix/b887f72867aaec27d0c0e6d4ddee999b to your computer and use it in GitHub Desktop.
secondary deploy script
<#
.SYNOPSIS
Installs a custom WSL2 distribution from a .tar file, creates a new user,
and generates a Windows Terminal profile.
.DESCRIPTION
This script automates the final setup of a custom WSL2 distro. It handles
importing the tarball, creating a specified user with sudo privileges, setting
that user as the default for login, and providing a JSON snippet for easy
integration into the Windows Terminal settings.
.NOTES
Author: Gemini
Version: 1.4
Requires: An existing .tar file created by the WSL2 Distro Builder script.
Changes:
- Fixed CRLF line ending issue in the user creation command string.
- Implemented a more robust, multi-step user creation process to ensure the home directory is created correctly.
- Fixed bug where the GUID for the Windows Terminal profile was not being generated correctly.
- Fixed PowerShell parsing error for variables in strings by using ${} delimiters.
.PARAMETER TarPath
The full path to the .tar file of the custom WSL distribution.
.PARAMETER DistroName
The name you want to assign to the new WSL distribution (e.g., "MyCustomOS").
.EXAMPLE
.\Install-CustomWSL.ps1 -TarPath "C:\work\MyDevOS.tar" -DistroName "MyDevOS"
This will start the interactive installation process for the specified distro.
#>
param(
[Parameter(Mandatory=$true)]
[string]$TarPath,
[Parameter(Mandatory=$true)]
[string]$DistroName
)
# --- Main Script ---
# Function to check if a WSL distro exists
function Test-WslDistroExists {
param ([string]$Name)
$distros = wsl --list --quiet
return $distros -contains $Name
}
# 1. Validate inputs and set paths
if (-not (Test-Path -Path $TarPath -PathType Leaf)) {
Write-Host "❌ Error: The file '$TarPath' was not found." -ForegroundColor Red
exit
}
$InstallLocation = Join-Path $env:LOCALAPPDATA $DistroName
Write-Host "Distro will be installed to: $InstallLocation" -ForegroundColor Cyan
# 2. Check for existing distro and confirm overwrite
if (Test-WslDistroExists -Name $DistroName) {
Write-Host "⚠️ A distribution named '$DistroName' already exists." -ForegroundColor Yellow
$confirm = Read-Host "Do you want to unregister and replace it? (y/n)"
if ($confirm -ne 'y') {
Write-Host "Installation cancelled."
exit
}
Write-Host "Unregistering existing '$DistroName' distribution..."
wsl --unregister $DistroName
if ($LASTEXITCODE -ne 0) { throw "Failed to unregister the existing distribution." }
# Clean up the old installation directory
if (Test-Path -Path $InstallLocation) {
Remove-Item -Recurse -Force $InstallLocation
}
}
# 3. Get new user details
Write-Host "`nPlease provide details for the primary user of this new distro." -ForegroundColor Cyan
$UserName = Read-Host "Enter the desired username (e.g., 'syco')"
if ([string]::IsNullOrEmpty($UserName)) {
Write-Host "❌ Username cannot be empty. Exiting." -ForegroundColor Red
exit
}
$Password = Read-Host -AsSecureString "Enter the password for '$UserName'"
# 4. Import the new distribution
Write-Host "Importing '$DistroName' from '$TarPath'..." -ForegroundColor Green
New-Item -Path $InstallLocation -ItemType Directory -Force | Out-Null
wsl --import $DistroName $InstallLocation $TarPath --version 2
if ($LASTEXITCODE -ne 0) { throw "Failed to import the WSL distribution." }
Write-Host "✅ Import complete."
# 5. Create new user and configure sudo
Write-Host "Creating user '$UserName' inside the new distro..."
# Convert the secure password to a plain text string for the shell command
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
$PlainTextPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
$userSetupCommands = "
set -e;
useradd -m -s /bin/bash ${UserName};
echo '${UserName}:${PlainTextPassword}' | chpasswd;
if getent group sudo >/dev/null; then usermod -aG sudo ${UserName}; fi;
if getent group wheel >/dev/null; then usermod -aG wheel ${UserName}; fi;
"
# FIXED: Explicitly replace Windows (CRLF) line endings with Linux (LF) endings.
$LfUserSetupCommands = $userSetupCommands.Replace("`r`n", "`n")
wsl -d $DistroName -u root -- bash -c $LfUserSetupCommands
if ($LASTEXITCODE -ne 0) {
Write-Host "⚠️ Could not automatically create user. You may need to log in as root to create a user manually." -ForegroundColor Yellow
} else {
Write-Host "✅ User '$UserName' created successfully."
}
# 6. Set the new user as the default for login
Write-Host "Setting '$UserName' as the default user..."
$wslConfContent = @"
[user]
default=${UserName}
"@
# Use a here-string with bash to correctly write the multi-line content to /etc/wsl.conf
wsl -d $DistroName -u root -- bash -c "cat <<'EOF' > /etc/wsl.conf
$wslConfContent
EOF"
if ($LASTEXITCODE -ne 0) {
Write-Host "⚠️ Could not set the default user automatically." -ForegroundColor Yellow
} else {
Write-Host "✅ Default user set."
}
# 7. Generate Windows Terminal Profile
Write-Host "`nGenerating Windows Terminal profile..." -ForegroundColor Green
$guid = [guid]::NewGuid().ToString()
$profileJson = @"
{
"guid": "{${guid}}",
"hidden": false,
"name": "${DistroName}",
"commandline": "wsl.exe -d ${DistroName}",
"startingDirectory": "//wsl`$/${DistroName}/home/${UserName}",
"icon": "ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1de9727a}.png"
}
"@
$jsonFilePath = Join-Path $pwd "terminal-profile-for-$($DistroName).json"
$profileJson | Set-Content -Path $jsonFilePath
Write-Host "✅ Windows Terminal profile generated!" -ForegroundColor Magenta
Write-Host "--------------------------------------------------------"
Write-Host "To add this to Windows Terminal, follow these steps:"
Write-Host "1. Open Windows Terminal."
Write-Host "2. Go to Settings (Ctrl + ,)."
Write-Host "3. Click 'Open JSON file' in the bottom-left corner."
Write-Host "4. Copy the following JSON snippet and paste it into the 'list' array in your settings.json file."
Write-Host " (A copy has also been saved to '$jsonFilePath')"
Write-Host "--------------------------------------------------------"
Write-Host $profileJson -ForegroundColor Cyan
Write-Host "--------------------------------------------------------"
Write-Host "`nInstallation complete. Please restart the Windows Terminal to see your new profile." -ForegroundColor Green
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment