From 422ce8c735062050411d37ea8958eb3f71a42eea Mon Sep 17 00:00:00 2001 From: Max Vilimpoc Date: Sat, 29 Aug 2026 19:17:40 +0200 Subject: [PATCH] dotfiles: stop the UAC launch line mangling its own arguments Adding -TraceUser to the elevated launch gave it a second quoted argument, and the "".."" doubling used to get quotes through cmd only survives ONE. With two, the quote-state parsing merges the tail into the -File value, so the elevated PowerShell was handed -File "C:\...\setup-windows-with-uac.ps1 -TraceUser LATISLAB\Claude " and refused it -- "failed because the file does not have a '.ps1' extension" -- exiting -196608 (0xFFFD0000) before Start-Transcript could run. The batch file then reported no elevated log and guessed at a cancelled UAC prompt, which is the one thing that had not happened. Both values now travel in the environment and the quotes the child needs are built as [char]34 inside PowerShell, so the command line in the batch file carries no quote characters of its own beyond the outer pair. Exercised through cmd against a probe script in a directory with a space in its name: -File binds, -TraceUser arrives as LATISLAB\Claude, and the child's exit code still propagates. Against the real script with -Verb RunAs dropped, it now gets as far as the #Requires elevation check, which is where a non-elevated run should stop. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YMh8i2QzkHNdE3MkKfcaT6 --- setup-windows.bat | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/setup-windows.bat b/setup-windows.bat index 1d32ada..250d4cb 100644 --- a/setup-windows.bat +++ b/setup-windows.bat @@ -61,10 +61,20 @@ set "DOTNET_EXE=%ProgramFiles%\dotnet\dotnet.exe" @rem administrator's credentials runs the elevated half AS that administrator, so @rem it cannot see whose box this is; the account named here is the one it grants @rem non-elevated ETW collection rights to (xperf / wpr without a UAC prompt). +@rem +@rem The two values go through the environment, and the quotes the child needs +@rem around them are built in PowerShell as [char]34, so the command line below +@rem contains no embedded quote characters at all. Writing them inline as "".."" +@rem works for ONE argument and quietly breaks at two: the quote-state parsing +@rem swallows everything after the first into the -File value, and the elevated +@rem PowerShell dies with "failed because the file does not have a '.ps1' +@rem extension" and exit code -196608 (0xFFFD0000) before it can log a thing. set "UAC_LOG=%~dp0setup-windows-uac.log" if exist "%UAC_LOG%" del "%UAC_LOG%" +set "UAC_SCRIPT=%~dp0setup-windows-with-uac.ps1" +set "UAC_TRACE_USER=%USERDOMAIN%\%USERNAME%" -powershell -NoProfile -Command "$p = Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','""%~dp0setup-windows-with-uac.ps1""','-TraceUser','""%USERDOMAIN%\%USERNAME%""' -Wait -PassThru; exit $p.ExitCode" +powershell -NoProfile -Command "$q = [char]34; $p = Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File',($q + $env:UAC_SCRIPT + $q),'-TraceUser',($q + $env:UAC_TRACE_USER + $q) -Wait -PassThru; exit $p.ExitCode" set "UAC_RC=%ERRORLEVEL%" @rem --- Surface the elevated session's output (its window has already closed) --- -- 2.48.2