Some of the latest work requires the use of many Windows-exclusive engines and tools, so for now, we cannot do without the Windows environment (no time to slack off), but there is a need for development, so I plan to try WSL and install a portable, Windows-friendly Ubuntu instance.
Install WSL Ubuntu#
Go directly to the Microsoft Store to get the WSL Ubuntu instance.
This may involve some Clash users who cannot open the Store; just set UWP Loopback in the Clash settings and check Store - Save.
The installation package can be found at C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu22.04LTS_2204.5.10018.0_x64__79rhkp1fndgsc
, and its size is constant.
The actual system content is stored at: %LocalAppData%\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc
Therefore, it is necessary to migrate it to another drive letter.
Extract Installation Package#
Open PowerShell as an administrator and install Windows Subsystem for Linux support.
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
After installation, press Y to restart.
Then you can set the WSL mode,
wsl --set-default-version 1
The difference between WSL1 and WSL2 is that WSL2 achieves complete isolation of the system, similar to a virtual machine, while WSL1 directly presents Linux files in the NTFS system. If WSL2 is set, an error may occur during installation:
WslRegisterDistribution failed with error: 0x800701bc
This is because there is no corresponding WSL2 kernel, and you need to download the update package from the WSL website.
Go to the installation package location, package it, and copy it to the portable hard drive (here it is F:).
Double-click the executable program to install.
Here I encountered some issues; the installation interface got stuck on installing ... for a long time. A GitHub issue proposed a solution: I got the same issue, but found a workaround: you just have to use ctrl+c and then it will continue and ask you for a username and password.
Then it installed successfully. Since we chose WSL1 mode, we can see the Linux system files in the rootfs folder F:\Ubuntu\rootfs
.
At this point, you can open the executable program (Ubuntu2204) that you just executed for installation to test.
Clean Up Content#
Uninstall Ubuntu from the Start menu to free up the installation package on the C drive.
Disconnect the main unit from the portable hard drive.
Go to the registry location:
Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss{*****}
The last position is a random GUID
, and opening it will show two key contents:
BasePath : F:\Ubunut DistributionName: Ubuntu-22.04
path
is used to indicate the directory of the WSL Linux instance (rootfs
), and name
is used to inform the name of this instance (wsl –list
).
The remaining items are used to activate the login user and set the WSL mode values. In short, with this information, you can directly start WSL from the command line:
wsl -d Ubuntu-22.04
We export this registry to the Ubuntu directory:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss{8f49723d-d252-404e-b36a-e376ee44c835}]
"State"=dword:00000001
"DistributionName"="Ubuntu-22.04"
"Version"=dword:00000002
"BasePath"="F:\Ubuntu"
"Flags"=dword:00000007
"DefaultUid"=dword:000003e8
When we need to open this instance on another host, we only need to change the base path to the current portable hard drive's drive letter on the other host (F: -> E:), and then double-click this registry to install it into the other host.
If there are multiple WSL instances, be careful not to have duplicate names.
This can be achieved through a batch file.
@echo off
setlocal EnableDelayedExpansion
set batfilenam=%~nx0
set batdir=%~dp0
set batdir=%batdir:~0,-1%
set batdir2=%batdir:=\%
set ThisWslDistributionName=%~1
set UnixUser=%~2
REM =========== BAT PARAMETER CHECKING ==============
if not defined ThisWslDistributionName (
echo. Need a DistributionName as parameter.
echo. The DistributionName is a new name to be registered into Lxss service.
echo. This .bat is compatible with Win10.21H2 or above.
echo. Examples:
echo. %batfilenam% Ubuntu-22.04
echo. %batfilenam% Ubuntu-22.04 bob
exit /b 4
)
if not "" == "%~3" (
call :Echos Error: Only one or two parameter should be given.
exit /b 4
)
call :HasSpaceChar %ThisWslDistributionName%
if %ERRORLEVEL%==1 (
call :Echos Error: DistributionName must NOT have space char in it.
exit /b 4
)
if defined UnixUser (
call :HasSpaceChar %UnixUser%
if %ERRORLEVEL%==1 (
call :Echos Error: UnixUser must NOT have space char in it.
exit /b 4
)
set _u_param=-u %UnixUser%
) else (
set _u_param=
)
REM =========== ENV CHECKING ==============
set wsl1_checkdir=%batdir%\rootfs\root
set wsl1_seen=
if exist "%wsl1_checkdir%" set wsl1_seen=1
set wsl2_checkfile=%batdir%\ext4.vhdx
set wsl2_seen=
if exist "%wsl2_checkfile%" set wsl2_seen=1
if "%wsl1_seen%%wsl2_seen%" == "" (
call :Echos Error: No WSL file-system found in "%batdir%" .
call :Echos You should either have
call :Echos "%wsl1_checkdir%" ^(for WSL1^)
call :Echos or
call :Echos "%wsl2_checkfile%" ^(for WSL2^)
exit /b 4
)
REM =========== PREPARE .REG FILE ==============
REM We need to generate a GUID for current DistributionName,
REM We can ensure it being unique by calcuating %ThisWslDistributionName%.
echo %ThisWslDistributionName%> "%batdir%\wslname.tmp"
call :GetFileMD5 "%batdir%\wslname.tmp" md5
if not defined md5 (
call :Echos Error: Cannot generate a GUID for ThisWslDistributionName.
exit /b 4
)
set md5guid=%md5:~0,8%-%md5:~8,4%-%md5:~12,4%-%md5:~16,4%-%md5:~20,12%
rem For "Ubuntu-22.04", md5guid is
rem 2b0c8e79-b4a5-1bfc-49cd-4f344cbfe444
set md5finalchar=%md5:~31,1%
if not defined md5finalchar (
call :Echos Error: When generating MD5 for ThisWslDistributionName, certttil.exe returns expected result.
call :Echos md5=%md5%
exit /b 4
)
set badoutput=%md5:~32,1%
if defined badoutput (
call :Echos Error: When generating MD5 for ThisWslDistributionName, certttil.exe returns expected result.
call :Echos md5=%md5%
exit /b 4
)
set regfile=%batdir%\WSL-green.reg
echo Windows Registry Editor Version 5.00 >> "%regfile%"
echo.>> "%regfile%"
echo [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss{%md5guid%}]>> "%regfile%"
if defined wsl1_seen (
echo "Flags"=dword:00000007 >> "%regfile%"
set wslverhint=WSL1
) else if defined wsl2_seen (
echo "Flags"=dword:0000000f >> "%regfile%"
set wslverhint=WSL2
) else (
echo "wsl version not found" >> "%regfile%"
)
echo "BasePath"="%batdir2%" >> "%regfile%"
echo "DistributionName"="%ThisWslDistributionName%" >> "%regfile%"
type "%batdir%\WSL-green.reg.0" >> "%regfile%"
REM =========== IMPORTING REGISTRY ==============
call :Echos Registering WSL instance using:
call :Echos . WSL version = %wslverhint%
call :Echos . GUID = {%md5guid%}
call :Echos . DistributionName = %ThisWslDistributionName%
call :EchoAndExec reg import "%regfile%"
if not %ERRORLEVEL%==0 (
call :Echos Import registry file fail: %regfile%
pause
exit /b 4
)
title WSL - %ThisWslDistributionName%
call :EchoAndExec wsl -d %ThisWslDistributionName% %_u_param% --cd ~
if not %ERRORLEVEL%==0 (
echo.
echo "wsl -d" execution fail. Please check your bat file or Windows environment.
echo.
pause
exit /b 4
)
exit /b 0
REM =============================
REM ====== Functions Below ======
REM =============================
:Echos
REM This function preserves %ERRORLEVEL% for the caller,
REM and, LastError does NOT pollute the caller.
setlocal & set LastError=%ERRORLEVEL%
echo [%batfilenam%] %*
exit /b %LastError%
:EchoAndExec
echo [%batfilenam%] EXEC: %*
call %*
exit /b %ERRORLEVEL%
:HasSpaceChar
REM Check if the input params has space-char in it.
REM
REM call :HasSpaceChar param1 param2
REM call :HasSpaceChar "param1 param2"
REM -- ERRORLEVEL above will be 1, means yes.
REM
REM call :HasSpaceChar ans param1-param2
REM -- ERRORLEVEL above will be 0, means no.
REM
REM If no input param, consider it "have" spacechar.
setlocal & set input=%*
if not defined input exit /b 1
set input=%input:"=#%
set count=0
for %%i in (%input%) do (
set /A count=count+1
)
if %count% == 1 (
exit /b 0
) else (
exit /b 1
)
:GetFileMD5
REM Thanks to: https://github.com/npocmaka/batch.scripts/blob/master/fileUtils/md5.bat
REM Usage:
REM call :GetFileMD5
set "md5="
for /f "skip=1 tokens=* delims=" %%# in ('certutil -hashfile "%~f1" MD5') do (
if not defined md5 (
for %%Z in (%%#) do set "md5=!md5!%%Z"
)
)
endlocal && (set "%~2=%md5%")
Subsequently, you only need to double-click the bat file to achieve plug-and-play.