@echo off setlocal enabledelayedexpansion REM ============================================================================ REM reset.bat REM REM QA helper: returns a Windows host to a pre-WSL state so the OA-Launcher REM cold-install path can be retested end-to-end without needing a fresh VM. REM REM WHAT IT DOES (in order): REM 1. wsl --shutdown REM 2. Unregisters EVERY WSL distribution on the host. This deletes each REM distro's ext4.vhdx, which means everything inside (the docker.io REM package we apt-install, all images, containers, volumes, networks) REM is wiped along with the distro. REM 3. Removes the WSL Microsoft Store package. REM 4. Disables the VirtualMachinePlatform and Microsoft-Windows-Subsystem- REM Linux Windows features. REM 5. Deletes %LOCALAPPDATA%\OA (launcher state, app cache, step cache). REM 6. Deletes Docker Desktop config remnants if present: %APPDATA%\Docker, REM %LOCALAPPDATA%\Docker. (OA-Launcher itself doesn't use Docker Desktop REM — it runs docker.io inside Ubuntu via `wsl -d Ubuntu -- docker ...` — REM so this only cleans up cruft from prior unrelated DD installs.) REM 7. Deletes %USERPROFILE%\.wslconfig. REM REM A REBOOT IS REQUIRED after running, because step 4 only takes effect on REM next boot. Without the reboot, `wsl --install` will not re-trigger the REM full cold-install pipeline; it'll see the features as still in transition. REM REM This is destructive. Any WSL distro on the host will be unregistered, REM including ones unrelated to OA-Launcher. Read before running. REM REM Prompts: UAC at self-elevation, and a Yes/No reboot dialog at the end REM (TaskDialog with WinForms MessageBox fallback). Choosing Yes schedules REM `shutdown /r /t 10` (run `shutdown /a` to abort). Everything in between REM runs non-interactively. Single self-contained .bat — no sibling files. REM To capture output, redirect: REM reset.bat > reset.log 2>&1 REM ============================================================================ REM --- Self-elevate --- net session >nul 2>&1 if %errorLevel% neq 0 ( echo This script needs administrator privileges. Re-launching elevated... powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs" exit /b ) echo. echo ============================================================== echo OA-Launcher: reset Windows host to pre-WSL test state echo ============================================================== echo. echo Performing: echo 1. wsl --shutdown echo 2. wsl --unregister for every distribution on this host echo (wipes Ubuntu + every docker image/container/volume inside) echo 3. Remove WSL Microsoft Store package echo 4. Disable VirtualMachinePlatform + Microsoft-Windows-Subsystem-Linux echo 5. Delete %LOCALAPPDATA%\OA echo 6. Delete %APPDATA%\Docker and %LOCALAPPDATA%\Docker (DD remnants, if any) echo 7. Delete %USERPROFILE%\.wslconfig echo. echo REBOOT REQUIRED after this script completes. echo. echo. echo --- [1/7] Shutting down WSL -------------------------------------- wsl --shutdown 2>nul echo Done. echo. echo --- [2/7] Unregistering WSL distributions ------------------------ echo (Each distro's ext4.vhdx is deleted, which wipes docker.io and all echo images/containers/volumes inside that distro along with it.) REM Use PowerShell so we don't have to deal with cmd.exe's UTF-16 / for-loop REM quirks parsing `wsl -l -q` output across WSL versions. powershell -NoProfile -Command ^ "$env:WSL_UTF8='1'; " ^ "$distros = & wsl.exe -l -q 2>$null; " ^ "if ($LASTEXITCODE -eq 0 -and $distros) { " ^ " foreach ($d in $distros) { " ^ " $name = ($d -replace '\0','').Trim(); " ^ " if ($name) { " ^ " Write-Host \" Unregistering: $name\"; " ^ " & wsl.exe --unregister $name | Out-Null " ^ " } " ^ " } " ^ "} else { " ^ " Write-Host ' (no distributions registered)' " ^ "}" echo Done. echo. echo --- [3/7] Removing WSL Microsoft Store package ------------------- powershell -NoProfile -Command ^ "Get-AppxPackage -AllUsers *WindowsSubsystemForLinux* -ErrorAction SilentlyContinue | " ^ "ForEach-Object { " ^ " Write-Host \" Removing: $($_.PackageFullName)\"; " ^ " Remove-AppxPackage -Package $_.PackageFullName -ErrorAction SilentlyContinue " ^ "}" echo Done. echo. echo --- [4/7] Disabling Windows features ----------------------------- echo (DISM output below; ignore "feature is not present" if WSL was never installed.) dism /online /disable-feature /featurename:VirtualMachinePlatform /norestart dism /online /disable-feature /featurename:Microsoft-Windows-Subsystem-Linux /norestart echo Done. echo. echo --- [5/7] Deleting %LOCALAPPDATA%\OA ---------------------- REM Kill OA processes first — `rd /s /q` silently leaves the folder partially REM populated when any file inside is open (e.g. launcher's step cache, log file, REM device-id). Without this guard, the directory survives reset+reboot. for %%P in (OA-Launcher.exe OA-Launcher.Windows.exe OA-App.exe) do ( taskkill /F /IM "%%P" >nul 2>&1 ) if exist "%LOCALAPPDATA%\OA" ( rd /s /q "%LOCALAPPDATA%\OA" 2>nul REM Retry 1: PowerShell Remove-Item tolerates some lock conditions rd does not REM (junction loops, ACL quirks, long paths). if exist "%LOCALAPPDATA%\OA" ( echo First delete left files; retrying via PowerShell... powershell -NoProfile -Command "Remove-Item -LiteralPath '%LOCALAPPDATA%\OA' -Recurse -Force -ErrorAction SilentlyContinue" ) REM Retry 2: take ownership and reset ACLs, then delete. Covers cases where REM a previous run left files owned by a different user / SYSTEM. if exist "%LOCALAPPDATA%\OA" ( echo Still present; taking ownership and resetting ACLs... takeown /f "%LOCALAPPDATA%\OA" /r /d y >nul 2>&1 icacls "%LOCALAPPDATA%\OA" /reset /t /c /q >nul 2>&1 rd /s /q "%LOCALAPPDATA%\OA" 2>nul ) if exist "%LOCALAPPDATA%\OA" ( echo WARNING: could not fully remove %LOCALAPPDATA%\OA echo a process still holds files open. Identify it with: echo handle.exe %LOCALAPPDATA%\OA ^(sysinternals^) ) else ( echo Removed %LOCALAPPDATA%\OA ) ) else ( echo No state at %LOCALAPPDATA%\OA (already clean) ) echo. echo --- [6/7] Deleting Docker Desktop config remnants (if any) ------- if exist "%APPDATA%\Docker" ( rd /s /q "%APPDATA%\Docker" 2>nul if exist "%APPDATA%\Docker" ( echo WARNING: could not fully remove %APPDATA%\Docker ) else ( echo Removed %APPDATA%\Docker ) ) else ( echo No %APPDATA%\Docker (already clean) ) if exist "%LOCALAPPDATA%\Docker" ( rd /s /q "%LOCALAPPDATA%\Docker" 2>nul if exist "%LOCALAPPDATA%\Docker" ( echo WARNING: could not fully remove %LOCALAPPDATA%\Docker ) else ( echo Removed %LOCALAPPDATA%\Docker ) ) else ( echo No %LOCALAPPDATA%\Docker (already clean) ) echo. echo --- [7/7] Deleting %USERPROFILE%\.wslconfig ---------------- if exist "%USERPROFILE%\.wslconfig" ( del /q "%USERPROFILE%\.wslconfig" echo Removed %USERPROFILE%\.wslconfig ) else ( echo No %USERPROFILE%\.wslconfig (already clean) ) echo. echo ============================================================== echo Reset complete. echo ============================================================== echo. REM --- Prompt to reboot --- REM Inline PowerShell — keeps reset.bat self-contained for QA distribution. REM Tries comctl32 TaskDialog (Vista+) for the modern Win10/11 look (bold REM heading, info icon, flat Yes/No buttons), falls back to WinForms REM MessageBox on any failure so the prompt is never silent. REM REM Quote-escaping note: the PowerShell source uses ONLY single-quoted REM strings, with [char]34 for any literal " character that needs to reach REM the C# DllImport attribute. Earlier versions used \" or "" inside cmd's REM quoted argument, which produced inconsistent results across hosts and REM caused Add-Type to fail compilation, dropping the user on a closing REM elevated console with a red error and no dialog. REM REM Exit codes from the script: 0 = Yes (reboot now), 1 = No. powershell -NoProfile -Command ^ "$q = [char]34; " ^ "$src = '[System.Runtime.InteropServices.DllImport(' + $q + 'comctl32.dll' + $q + ', CharSet=System.Runtime.InteropServices.CharSet.Unicode)] public static extern int TaskDialog(System.IntPtr hWndParent, System.IntPtr hInstance, string pszWindowTitle, string pszMainInstruction, string pszContent, int dwCommonButtons, System.IntPtr pszIcon, out int pnButton);'; " ^ "$title = 'OA-Launcher reset'; " ^ "$heading = 'Reboot now to finish reset?'; " ^ "$body = 'A restart is required to fully remove the WSL and VirtualMachinePlatform Windows features. Choose No to skip and reboot manually before re-testing.'; " ^ "try { " ^ " Add-Type -Namespace OA -Name TD -MemberDefinition $src -ErrorAction Stop; " ^ " $btn = 0; " ^ " [void][OA.TD]::TaskDialog([IntPtr]::Zero, [IntPtr]::Zero, $title, $heading, $body, 6, [IntPtr]65533, [ref]$btn); " ^ " if ($btn -eq 6) { exit 0 } else { exit 1 } " ^ "} catch { " ^ " Add-Type -AssemblyName System.Windows.Forms; " ^ " $r = [System.Windows.Forms.MessageBox]::Show($heading + [char]10 + [char]10 + $body, $title, [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Question); " ^ " if ($r -eq [System.Windows.Forms.DialogResult]::Yes) { exit 0 } else { exit 1 } " ^ "}" if %errorLevel% equ 0 ( echo Rebooting in 10 seconds. Run "shutdown /a" from another shell to abort. shutdown /r /t 10 /c "OA-Launcher reset complete; rebooting to finish feature removal." ) else ( echo Skipping reboot. Reboot manually before re-testing the cold-install path. echo. pause ) echo. endlocal