diff --git a/.gitignore b/.gitignore index adb36c8..d8cd016 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.exe \ No newline at end of file +*.exe +/bin/ \ No newline at end of file diff --git a/README.md b/README.md index 815524a..44238cb 100644 --- a/README.md +++ b/README.md @@ -8,28 +8,36 @@ Provides a list of installed distributions, the official Linux distro name, the ## wslctl -Allows WSL distros to be started on launch. The syntax follows that of systemctl: +Allows WSL distros to be started on Windows startup. The syntax follows that of systemctl: -``` -wslctl enable pengwin -wslctl disable pengwin -wslctl restart pengwin -``` +`wslctl enable pengwin` + +`wslctl disable pengwin` + +`wslctl restart pengwin` + +## wsl-dist-update + +Run package updates on all installed WSL distros. Tested on: Pengwin, Fedora Remix for WSL, Ubuntu, Debian, openSUSE Tumbleweed, ArchWSL, Oracle Linux, and the WSL. + +wsl-dist-update can optionally additionally update the WSL system distro by passing the `--system` option. + +To run wsl-dist-update as a service, copy wsl-dist-update.exe to a permanent location and run wsl-dist-update-sched.ps1, modifying the path to the .exe as needed. ## wsl-reset -A troubleshooting utility that resets WSL to various degrees. +A troubleshooting utility that resets the WSL 2 stack to various degrees. -`wsl-reset --reset` - shuts down WSL, resets the WSL service, and installs any WSL updates, if available +`wsl-reset --reset` - Shuts down WSL, resets the WSL service, and installs any WSL updates, if available. -`wsl-reset --hard-reset` - shuts down WSL, stops the WSL service, uninstalls WSL, and re-installs WSL +`wsl-reset --hard-reset` - Shuts down WSL, stops the WSL service, uninstalls WSL, and re-installs WSL. -`wsl-reset --destrutive-reset` - shuts down WSL, restarts the WSL service, **unregisters all WSL distros**, stops the WSL service, uninstalls WSL, and re-installs WSL +`wsl-reset --destrutive-reset` - Shuts down WSL, restarts the WSL service, **unregisters all WSL distros**, stops the WSL service, uninstalls WSL, and re-installs WSL. ## sysdistrowt Adds the WSL System Distro (CBL-Mariner) to the Windows Terminal and/or Windows Terminal Preview profiles, for easier debugging. -### Misc +## build-wslinternals - /prompts folder contains example AI prompts used to generate the first draft of these scripts, the final scripts got hand polished, but they are there to see. \ No newline at end of file +Builds wslinternals PowerShell scripts to .exe files using ps2exe. Requires PowerShell 5. \ No newline at end of file diff --git a/build-wslinternals.ps1 b/build-wslinternals.ps1 new file mode 100644 index 0000000..4c7b8de --- /dev/null +++ b/build-wslinternals.ps1 @@ -0,0 +1,18 @@ +# Install ps2exe module if not already installed +if (-not (Get-Module -Name ps2exe -ListAvailable)) { + Install-Module -Name ps2exe -Scope CurrentUser -Force +} + +# Create /bin/ subdirectory if it does not exist +if (-not (Test-Path -Path ".\bin\" -PathType Container)) { + New-Item -ItemType Directory -Path ".\bin\" +} + +# Get list of .ps1 files in current directory +$ps1Files = Get-ChildItem -Path . -Filter *.ps1 + +# Loop through each .ps1 file and convert to .exe using ps2exe +foreach ($ps1File in $ps1Files) { + $exeFile = ".\bin\" + $ps1File.Name.Replace(".ps1", ".exe") + ps2exe -inputFile $ps1File.FullName -outputFile $exeFile +} \ No newline at end of file diff --git a/prompts/list-wsl-prompt.txt b/prompts/list-wsl-prompt.txt deleted file mode 100644 index d14ffc3..0000000 --- a/prompts/list-wsl-prompt.txt +++ /dev/null @@ -1,21 +0,0 @@ -Write a PowerShell 7 Core script that lists installed WSL distributions in a table. - -The table should show: - -- Whether the distribution is the default distribution, by reading the DafaultDistribution key at HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss. If the distribution name matches the DefaultDistribution key, then the distribution is the default distribution, display an asterisk (*) next to the distribution name. If the distribution is not the default distribution, then do not display an asterisk next to the distribution name. -- The distribution name from the Windows Registry, listed under the heading "WSL Distro Name" -- The distribution PRETTY_NAME, by spawning a process in that respective distribution and reading the distribution's /etc/os-release file for PRETTY_NAME, listed under the heading "Linux Distro Name" -- The distribution's version, by spawning a process in that respective distribution and reading the distribution's /etc/os-release file for VERSION, listed under the heading "Distro Version" -- Whether the distribution has systemd enabled or not, by spawning a process in that respective distribution and reading /etc/wsl.conf for the systemd=true key, listed under the heading "systemd" -- The distribution's default username, by spawning a process in that respective distribution, running "id -un -- " followed by the default UID key in the respective WSL distribution, and parsing the output, under the heading "Default User" -- The distribution's state, by reading the State key in the Windows Registry, and listing "Installed" for a value of 0x1, "Installing" for a value of 0x3, or "Uninstalling", for a value of 0x4, under the heading "State" -- The distribution's WSL version as 1 or 2, by reading the Version key in the Windows Registry, listed under the heading "WSL Version" - -Additionallly: - -- Do not display the distro GUID in the table. -- Do not create a column for default distro, simply append an asterix next to the default distro's name. -- Do not use \\wsl$\ to access the /etc/os-release file or /etc/wsl.conf file. -- Get the /etc/os-release and /etc/wsl.conf files through \AppData\Local\Packages, get them by spawning a process with wsl.exe -d followed by the distribution name then cat each file and parse the output. -- If /etc/wsl.conf is not found, then the distribution does not have systemd enabled. -- Do not check for, display the default username, or default username header if the optional flag --skip-username is passed to the script. \ No newline at end of file diff --git a/prompts/sysdistrowt-prompt.txt b/prompts/sysdistrowt-prompt.txt deleted file mode 100644 index 1a0b489..0000000 --- a/prompts/sysdistrowt-prompt.txt +++ /dev/null @@ -1,23 +0,0 @@ -Write a PowerShell 7 Core script that: - -Checks for Windows Terminal in $env:LOCALAPPDATA "Packages" - -Checks for a settings.json for Windows Terminal in $env:LOCALAPPDATA "Packages" - -Checks for Windows Terminal Preview in $env:LOCALAPPDATA "Packages" - -Checks for a settings.json for Windows Terminal Preview in $env:LOCALAPPDATA "Packages" - -If neither Windows Terminal or Windows Terminal Preview are found, exit with a message that Windows Terminal is not installed. - -If Windows Terminal is detected, but no settings.json for Windows Terminal is found, then run and close wt.exe from $env:ProgramFiles Microsoft.WindowsTerminal - -If Windows Terminal Preview is detected, but no settings.json for Windows Terminal Preview is found, then run and close wt.exe from $env:ProgramFiles Microsoft.WindowsTerminal - -Do not use wildcards to detect files or run wt.exe, parse the directory and use the exact folder name - -Add an additional profile called "WSL System Distro" to Windows Terminal if it exists, that launches the WSL system distro with wsl.exe -u root --system - -Add an additional profile called "WSL System Distro" to Windows Terminal Preview if it exists, that launches the WSL system distro with wsl.exe -u root --system - -Checks if a profile created by the script already exists, and if so, removes the profile \ No newline at end of file diff --git a/prompts/wsl-reset-prompt.txt b/prompts/wsl-reset-prompt.txt deleted file mode 100644 index 7b02840..0000000 --- a/prompts/wsl-reset-prompt.txt +++ /dev/null @@ -1,11 +0,0 @@ -Create a PowerShell 7 Core script that: - -Checks if it is being run as administrator, and, if not, exists with a message that the script must be run as administrator. - -If no argument is specified, the script should display a message that the script must be run with either --reset, --hard-reset, --destructive-reset. - -If the --reset argument is specified, then run wsl.exe --shutdown, wsl.exe --update, and force restart the Windows Subsystem for Linux service in Windows. - -If the --hard-reset argument is specified, then run wsl.exe --shutdown, uninstall Windows Subsystem for Linux, and then run wsl.exe --install. - -If the --descrutive-reset argument is specified, then run wsl.exe --shutdown, run wsl.exe --unregister-all, uninstall Windows Subsystem for Linux, and then run and then run wsl.exe --install. diff --git a/prompts/wslctl-prompt.txt b/prompts/wslctl-prompt.txt deleted file mode 100644 index 256fa81..0000000 --- a/prompts/wslctl-prompt.txt +++ /dev/null @@ -1,12 +0,0 @@ -Write a PowerShell Core 7 script that: - -- checks if it is being run as administrator, and, if not, exists with a message that the script must be run as administrator -- will be run with the argument enable, disable, or restart followed by the name of an installed WSL distro -- if run with the argument enable, disable, or restart, but no WSL distro specified, exits with a message that a WSL distro must be specified -- if run with the argument enable followed by a WSL distro name, checks to see if the WSL distro exists, if it does not exist, it exits with a message the WSL distro not exist, if it does exist, it checks if starting the distro as a task has already been enabled, if it has already been enabled, it exits with a message the WSL distro has already been enabled, finally, if the scheduled task does not exist, it creates and installs a scheduled task in the scheduled task folder \Microsoft\Windows\WSL that starts the WSL distro on startup -- if run with argument disable followed by a WSL distro name, checks to see if a scheduled task has been created in the way enable created the task, if it does not exist, it exits with a message the WSL distro is not enabled, if it does exist, it disables the scheduled task that starts the WSL distro on start and removes the corresponding task folder under Microsoft\WSL -- if run with the argument restart followed by a WSL distro name, checks to see if a scheduled task has been created in the way enable created the task, if it does not exist, it exists with a message the WSL distro is not enabled, if it does exist, it disables the scheduled task that starts the WSL distro on start, re-enables the scheduled task that starts the WSL distro on start, and then runs shutdown -r now as root in the respective distro -- if the distro name specified by the user is Pengwin, then use WLinux as the distro name within the script -- check for the existence of an installed distro by parsing each GUID in HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss for the DistributionName key -- do not use TaskPath with Get-ScheduledTask when checking to see if a WSL distro is enabled, look for the simply task by name, for example: Get-ScheduledTask -TaskName "Start $distroname at startup" -- do not provide a list of commands used \ No newline at end of file diff --git a/wsl-dist-update-sched.ps1 b/wsl-dist-update-sched.ps1 new file mode 100644 index 0000000..61d7a96 --- /dev/null +++ b/wsl-dist-update-sched.ps1 @@ -0,0 +1,14 @@ +# Define variables +$taskName = "WSL Distro Automatic Update" +$taskDescription = "Runs wsl-dist-update.exe 10 minutes after Windows boots" +$executablePath = "wsl-dist-update.exe" +$arguments = "--system" + +# Create scheduled task +$action = New-ScheduledTaskAction -Execute $executablePath -Argument $arguments +$trigger = New-ScheduledTaskTrigger -AtStartup -Delay 10m +$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries +Register-ScheduledTask -TaskName $taskName -Description $taskDescription -Action $action -Trigger $trigger -Settings $settings -RunLevel Highest -Force + +# Run scheduled task in the background +Start-ScheduledTask -TaskName $taskName \ No newline at end of file diff --git a/wsl-dist-update.ps1 b/wsl-dist-update.ps1 new file mode 100644 index 0000000..0304f44 --- /dev/null +++ b/wsl-dist-update.ps1 @@ -0,0 +1,42 @@ +# Get list of installed WSL distros from registry +$distros = Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss" | ForEach-Object { $_.GetValue("DistributionName") } + +# Loop through each distro and get ID_LIKE variable from /etc/os-release using wsl.exe +$results = foreach ($distro in $distros) { + $osReleasePath = "\\wsl$\$distro\etc\os-release" + #$idLike = (wsl.exe -d $distro cat /etc/os-release | Select-String "^ID_LIKE=").ToString().Split("=")[1] + $id = (wsl.exe -d $distro cat /etc/os-release | Select-String "^ID=").ToString().Split("=")[1] + Write-Host "Updating $distro" + switch -Wildcard ($id) { + "*debian*" { + wsl.exe -d $distro -u root apt-get update > $null + wsl.exe -d $distro -u root apt-get upgrade -y > $null + } + "*ubuntu*" { + wsl.exe -d $distro -u root apt-get update > $null + wsl.exe -d $distro -u root apt-get upgrade -y > $null + } + "*fedora*" { + wsl.exe -d $distro -u root dnf update -y > $null + } + "*rhel*" { + wsl.exe -d $distro -u root dnf update -y > $null + } + "*suse*" { + wsl.exe -d $distro -u root zypper dup -y > $null + } + "*arch*" { + wsl.exe -d $distro -u root pacman -Syu --noconfirm > $null + } + } + [PSCustomObject]@{ + DistroName = $distro + ID_LIKE = $idLike + } +} + +# Update WSL System Distro if --system flag is passed +if ($args.Contains("--system")) { + Write-Host "Updating WSL System Distro" + wsl.exe -u root --system tdnf update -y > $null +} \ No newline at end of file