]>
| Commit | Line | Data |
|---|---|---|
| 3c096107 MV |
1 | @echo off\r |
| 2 | \r | |
| 3 | @rem ---------------------------------------------------------------------------\r | |
| 452f525c | 4 | @rem setup-windows.bat - provision a fresh Windows box for native development\r |
| 649b04df MV |
5 | @rem\r |
| 6 | @rem Runs on x64 and on ARM64 (Windows 11 on Arm). See the ARM64 block below for\r | |
| 7 | @rem what changes on Arm silicon.\r | |
| 8 | @rem ---------------------------------------------------------------------------\r | |
| 9 | \r | |
| 10 | @rem ---------------------------------------------------------------------------\r | |
| 11 | @rem Host architecture\r | |
| 12 | @rem\r | |
| 13 | @rem PROCESSOR_ARCHITECTURE alone is not enough: a 32-bit cmd.exe under emulation\r | |
| 14 | @rem reports x86 and stashes the real one in PROCESSOR_ARCHITEW6432. Check both,\r | |
| 15 | @rem so this is right however the script was launched.\r | |
| 16 | @rem\r | |
| 17 | @rem The value drives two things below, and nothing else - winget resolves the\r | |
| 18 | @rem installer architecture on its own (native first, then whatever the box can\r | |
| 19 | @rem emulate), so the ordinary installs need no help:\r | |
| 20 | @rem - VirtualBox is skipped on ARM64 (see below)\r | |
| 21 | @rem - the summary tells you which tools you got as emulated x64\r | |
| 3c096107 | 22 | @rem ---------------------------------------------------------------------------\r |
| 649b04df MV |
23 | set "HOST_ARCH=%PROCESSOR_ARCHITECTURE%"\r |
| 24 | if defined PROCESSOR_ARCHITEW6432 set "HOST_ARCH=%PROCESSOR_ARCHITEW6432%"\r | |
| 25 | set "IS_ARM64=0"\r | |
| 26 | if /i "%HOST_ARCH%"=="ARM64" set "IS_ARM64=1"\r | |
| 27 | echo [setup-windows] Host architecture: %HOST_ARCH%\r | |
| 3c096107 | 28 | \r |
| cd774a19 MV |
29 | @rem ---------------------------------------------------------------------------\r |
| 30 | @rem Can this account elevate? Worked out ONCE, here, because it gates two very\r | |
| 31 | @rem different things: the elevated half far below, and a handful of the "per-user"\r | |
| 32 | @rem winget installs just after this, which are per-user in name only.\r | |
| 33 | @rem\r | |
| 34 | @rem ALREADY - already elevated. IsInRole(Administrator) is false for an admin\r | |
| 35 | @rem running unelevated under UAC, so this means actually elevated,\r | |
| 36 | @rem not merely capable of it.\r | |
| 37 | @rem PROMPT - not elevated, UAC on, so elevation can be requested.\r | |
| 38 | @rem NOLUA - UAC is off machine-wide (EnableLUA = 0) AND this is not an\r | |
| 39 | @rem administrator. Elevation is impossible, not merely declined:\r | |
| 40 | @rem Windows has no prompt to offer. Note that with UAC off,\r | |
| 41 | @rem `Start-Process -Verb RunAs` does not fail - it is silently\r | |
| 42 | @rem ignored, runs the child with the caller's own token, and reports\r | |
| 43 | @rem success, which is why this needs detecting rather than trying.\r | |
| 44 | @rem ---------------------------------------------------------------------------\r | |
| 45 | set "ELEV=PROMPT"\r | |
| 46 | for /f "usebackq tokens=*" %%A in (`powershell -NoProfile -ExecutionPolicy Bypass -Command "$id=[Security.Principal.WindowsIdentity]::GetCurrent(); if (([Security.Principal.WindowsPrincipal]$id).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { 'ALREADY' } elseif ((Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -ErrorAction SilentlyContinue).EnableLUA -eq 0) { 'NOLUA' } else { 'PROMPT' }"`) do set "ELEV=%%A"\r | |
| 47 | echo [setup-windows] Elevation: %ELEV%\r | |
| 48 | if "%ELEV%"=="NOLUA" (\r | |
| 49 | echo [setup-windows] This account cannot elevate ^(UAC off, not an administrator^). Packages that\r | |
| 50 | echo [setup-windows] need a machine-wide install will be SKIPPED rather than left to fail; details\r | |
| 51 | echo [setup-windows] at each one, and a summary before the elevated half.\r | |
| 52 | )\r | |
| 53 | \r | |
| 2e281421 | 54 | @rem --- Non-admin (per-user) winget installs ---\r |
| 649b04df MV |
55 | @rem\r |
| 56 | @rem No --architecture anywhere on purpose. winget already picks the best\r | |
| 57 | @rem installer the manifest offers for this machine - arm64, else x64, else x86 -\r | |
| 58 | @rem and pinning it would turn "no native build, use the emulated one" into a\r | |
| 59 | @rem hard failure.\r | |
| 60 | @rem\r | |
| 61 | @rem These all publish real ARM64 installers, so on an ARM64 box every one of\r | |
| 62 | @rem them lands as a native ARM64 binary with no emulation involved.\r | |
| 63 | @rem\r | |
| 64 | @rem The Sysinternals packages are a multi-architecture ZIP rather than an\r | |
| 65 | @rem installer, so the ARM64 build is IN there but is not the default-named exe:\r | |
| 66 | @rem the zip holds procexp.exe (x86), procexp64.exe (x64) and procexp64a.exe\r | |
| 67 | @rem (ARM64). On ARM64, run the *64a.exe variants - plain procexp.exe is the x86\r | |
| 68 | @rem one and will run emulated.\r | |
| 3c096107 | 69 | winget install Anthropic.ClaudeCode\r |
| 0aec6243 | 70 | winget install Brave.Brave\r |
| 3c096107 MV |
71 | winget install Git.Git\r |
| 72 | winget install Microsoft.PowerShell Microsoft.Sysinternals.ProcessExplorer Microsoft.Sysinternals.ProcessMonitor Microsoft.Sysinternals.SDelete Microsoft.VisualStudioCode Microsoft.WindowsTerminal\r | |
| 73 | winget install Python.Python.3.13\r | |
| fbe899b6 MV |
74 | \r |
| 75 | @rem WinMerge is the one package here where winget's own preference order picks\r | |
| 76 | @rem the WRONG architecture, and it is worth knowing why: upstream publishes the\r | |
| 77 | @rem ARM64 build as a MACHINE-scope installer (WinMerge-<ver>-ARM64-Setup.exe) and\r | |
| 78 | @rem the x64 build as a PER-USER one (WinMerge-<ver>-x64-PerUser-Setup.exe). Run\r | |
| 79 | @rem unelevated, winget's scope preference beats its architecture preference and\r | |
| 80 | @rem you silently get the emulated x64 build.\r | |
| 81 | @rem\r | |
| 82 | @rem So ask for arm64 explicitly, and fall back to the default when that cannot be\r | |
| 83 | @rem installed - which is exactly the standard-user case, where the machine-scope\r | |
| 84 | @rem installer has nowhere to go. The fallback is the x64 build under emulation:\r | |
| 85 | @rem a diff tool is not a hot path, and a working WinMerge beats none. The\r | |
| 86 | @rem architecture audit at the end of setup-windows-no-uac.ps1 reports which one\r | |
| 87 | @rem you ended up with.\r | |
| 88 | if "%IS_ARM64%"=="1" (\r | |
| 89 | winget install WinMerge.WinMerge --architecture arm64 || winget install WinMerge.WinMerge\r | |
| 90 | ) else (\r | |
| 91 | winget install WinMerge.WinMerge\r | |
| 92 | )\r | |
| 3c096107 | 93 | \r |
| 649b04df MV |
94 | @rem --- Build drivers, standalone and native ---\r |
| 95 | @rem\r | |
| 96 | @rem CMake and Ninja BOTH ship with Visual Studio, so this is not about making\r | |
| 97 | @rem them exist - it is about which binary you get and where it is on the PATH:\r | |
| 98 | @rem\r | |
| 99 | @rem - VS's cmake.exe is already ARM64, but it only lands on the PATH inside a\r | |
| 100 | @rem Developer Command Prompt. The build line further down assumes a plain\r | |
| 101 | @rem `cmake`, so install the standalone one to make that true in any shell.\r | |
| 102 | @rem - VS's bundled ninja.exe is x64 EVEN ON ARM64 (verified on this box), so it\r | |
| 103 | @rem runs under emulation. Ninja is re-invoked for every edge in the build\r | |
| 104 | @rem graph, which makes it the one tool here where emulation is actually paid\r | |
| 105 | @rem over and over, and ninja-winarm64.zip is a native build. Worth having.\r | |
| 106 | @rem\r | |
| 3e0aa9fc MV |
107 | @rem Which ninja wins inside a VS Developer Command Prompt: the native one. VS\r |
| 108 | @rem adds its copy from Common7\Tools\vsdevcmd\ext\cmake.bat with\r | |
| 109 | @rem set "PATH=%PATH%;...\CMake\bin;...\CMake\Ninja"\r | |
| 110 | @rem which APPENDS, so the VS directories sit at the very end of the composed\r | |
| 111 | @rem PATH, behind every machine and user entry. setup-windows-no-uac.ps1 then\r | |
| 112 | @rem pins the native ninja's directory to the FRONT of the user PATH so the\r | |
| 113 | @rem margin does not depend on two append orders staying as they are.\r | |
| cd774a19 MV |
114 | @rem\r |
| 115 | @rem Ninja here, CMake in the machine-wide group below: Ninja is a portable zip\r | |
| 116 | @rem winget unpacks into the user profile, CMake is an MSI that installs for the\r | |
| 117 | @rem whole machine.\r | |
| 649b04df MV |
118 | winget install Ninja-build.Ninja\r |
| 119 | \r | |
| 120 | @rem --- Second, independent Clang: compiler diversity ---\r | |
| 121 | @rem\r | |
| 122 | @rem The elevated half installs Visual Studio's Clang component (clang-cl, native\r | |
| 123 | @rem ARM64). This is a DIFFERENT LLVM: the upstream release, on its own schedule\r | |
| 124 | @rem and usually several major versions ahead of the one VS bundles, installed to\r | |
| 125 | @rem C:\Program Files\LLVM rather than inside the VS tree. Two Clang majors plus\r | |
| 126 | @rem MSVC over the same sources is the point - it is what catches the bugs a\r | |
| 127 | @rem single toolchain agrees with itself about.\r | |
| 128 | @rem\r | |
| 129 | @rem Native on ARM64: the manifest resolves to LLVM-<ver>-woa64.exe ("Windows on\r | |
| 130 | @rem Arm 64"), not the x64 build.\r | |
| 131 | @rem\r | |
| 132 | @rem PATH ORDER MATTERS if you use it. Should this installer put its bin on the\r | |
| 133 | @rem PATH, a bare `clang-cl` resolves to the upstream one while CMake's\r | |
| 134 | @rem `-T ClangCL` toolset keeps using the VS copy - so the two can be selected\r | |
| 135 | @rem independently, but only if you know which one you are asking for. Prefer\r | |
| 136 | @rem -DCMAKE_CXX_COMPILER with a full path when you care.\r | |
| 137 | winget install LLVM.LLVM\r | |
| 138 | \r | |
| cd774a19 MV |
139 | @rem x64-only manifest: winget falls back to the x64 installer on ARM64 and it runs\r |
| 140 | @rem under Prism emulation. Harmless for what it does here - iperf3 is a network\r | |
| 141 | @rem benchmark bounded by the link, not by CPU.\r | |
| 649b04df | 142 | winget install ar51an.iPerf3\r |
| 649b04df MV |
143 | \r |
| 144 | @rem NASM assembles x86/x86-64 only - there is no ARM64 target in it and no ARM64\r | |
| 145 | @rem build of it. Installed on ARM64 anyway (as emulated x64) because this box\r | |
| 146 | @rem still cross-compiles x86/x64 binaries, where NASM is the assembler that\r | |
| 147 | @rem builds them. If you only ever target ARM64, nothing here uses it: the ARM64\r | |
| 148 | @rem assembler is armasm64.exe, which ships with MSVC.\r | |
| 149 | winget install NASM.NASM\r | |
| 150 | \r | |
| 151 | @rem VirtualBox has no ARM64 Windows host build, and the x64 one cannot be made to\r | |
| 152 | @rem work by emulation: a hypervisor is kernel-mode, and its x64 driver will not\r | |
| 153 | @rem load on an ARM64 kernel. Installing it on ARM64 gets you a broken product and\r | |
| 154 | @rem a failed driver install, so skip it and say so.\r | |
| 155 | @rem\r | |
| 156 | @rem This is also what makes setup-windows-7-test-env.bat unreachable from an\r | |
| 157 | @rem ARM64 host: it prepares a Windows 7 *x86* guest, and neither VirtualBox nor\r | |
| 158 | @rem Hyper-V on ARM64 can run one.\r | |
| 159 | if "%IS_ARM64%"=="1" (\r | |
| 160 | echo [setup-windows] Skipping Oracle.VirtualBox: no ARM64 Windows host build ^(x64 hypervisor drivers cannot load on an ARM64 kernel^).\r | |
| 161 | echo [setup-windows] The Windows 7 x86 test-VM workflow ^(setup-windows-7-test-env.bat^) is therefore unavailable on this box.\r | |
| 162 | ) else (\r | |
| 163 | winget install Oracle.VirtualBox\r | |
| 164 | )\r | |
| 165 | \r | |
| cd774a19 MV |
166 | @rem ---------------------------------------------------------------------------\r |
| 167 | @rem Machine-wide installers, despite sitting in the "per-user" section\r | |
| 168 | @rem\r | |
| 169 | @rem These four are not per-user at all. On an account that cannot elevate they\r | |
| 170 | @rem fail on every run, with installer exit codes that say nothing useful:\r | |
| 171 | @rem Microsoft.DotNet.SDK.10 exit 5 (ERROR_ACCESS_DENIED)\r | |
| 172 | @rem Kitware.CMake exit 1603 (generic MSI failure)\r | |
| 173 | @rem Google.AndroidGPUInspector exit 1603\r | |
| 174 | @rem OpenCppCoverage exit 1 (its installer self-elevates)\r | |
| 175 | @rem\r | |
| 176 | @rem Grouped and skipped outright where elevation is impossible. Attempting a\r | |
| 177 | @rem guaranteed failure four times per run - and paying the download for it -\r | |
| 178 | @rem teaches nobody anything, and the four opaque error codes bury the one line\r | |
| 179 | @rem that matters. On an account that can elevate they run exactly as before.\r | |
| 180 | @rem\r | |
| 181 | @rem NOTE none of these is a build-blocker: the .NET SDK is only here for the WiX\r | |
| 182 | @rem MSI tooling, CMake also ships inside Visual Studio, AGI profiles Android\r | |
| 183 | @rem devices, and OpenCppCoverage cannot instrument ARM64 binaries anyway.\r | |
| 184 | @rem ---------------------------------------------------------------------------\r | |
| 185 | if "%ELEV%"=="NOLUA" (\r | |
| 186 | echo.\r | |
| 187 | echo [setup-windows] Skipping the machine-wide installers - this account cannot elevate:\r | |
| 188 | echo [setup-windows] Microsoft.DotNet.SDK.10, Kitware.CMake, Google.AndroidGPUInspector, OpenCppCoverage.\r | |
| 189 | echo [setup-windows] None blocks a build. Re-run from an administrator account to get them.\r | |
| 190 | echo.\r | |
| 191 | goto :after_admin_pkgs\r | |
| 192 | )\r | |
| 193 | \r | |
| 194 | winget install Microsoft.DotNet.SDK.10\r | |
| 195 | winget install Kitware.CMake\r | |
| 196 | winget install Google.AndroidGPUInspector\r | |
| 197 | \r | |
| 3c096107 | 198 | @rem OpenCppCoverage: native (PE) line coverage for the C++ binaries. run-coverage-occ.py drives the\r |
| 452f525c | 199 | @rem pytest suite under it to produce an HTML report (the binaries under test build with PDBs,\r |
| 3c096107 | 200 | @rem which it reads). The installer elevates via UAC.\r |
| 649b04df MV |
201 | @rem\r |
| 202 | @rem x86/x64 only, and unlike the other emulated tools that is a real limit rather\r | |
| 203 | @rem than a slowdown: it collects coverage by debugging the process under test and\r | |
| 204 | @rem stepping x86/x64 instructions, so it can cover the x86/x64 binaries this box\r | |
| 205 | @rem cross-compiles but NOT an ARM64 one. For ARM64 coverage, build the ARM64\r | |
| 206 | @rem binaries with /fsanitize-coverage or use the x64 build for the coverage run.\r | |
| 3c096107 | 207 | winget install OpenCppCoverage.OpenCppCoverage\r |
| cd774a19 MV |
208 | \r |
| 209 | :after_admin_pkgs\r | |
| 649b04df | 210 | if "%IS_ARM64%"=="1" echo [setup-windows] NOTE: OpenCppCoverage is x86/x64-only - it cannot instrument ARM64 binaries. Run coverage against the x64 build.\r |
| 3c096107 | 211 | \r |
| aa6eb783 MV |
212 | @rem --- WiX 5.0.2, pinned on purpose ---\r |
| 213 | @rem WiX packages our proprietary software into MSIs, and the version is pinned to keep that\r | |
| 214 | @rem free of a fee. 5.0.2 is the last release distributed under the Microsoft Reciprocal\r | |
| 215 | @rem License alone. From 6.0 onward the package also carries OSMFEULA.txt, an Open Source\r | |
| 216 | @rem Maintenance Fee agreement: a monthly fee owed by anyone who uses the PREBUILT BINARIES\r | |
| 217 | @rem as part of revenue-generating activity and has annual gross revenue >= US$10,000.\r | |
| 218 | @rem\r | |
| 219 | @rem It is a fee for the binaries, not a restriction on what we ship - MS-RL is file-scoped\r | |
| 220 | @rem and never reached the MSIs WiX builds, under any version - but 5.0.2 owes nothing.\r | |
| 221 | @rem The 6.x/7.x SOURCE is still MS-RL too, so self-compiling is another way out; a pin is\r | |
| 222 | @rem the cheaper one. This replaces `winget install WiXToolset.WiXCLI`, which has no version\r | |
| 223 | @rem selector and so installs the latest (7.0.0 today, EULA and all).\r | |
| 224 | @rem\r | |
| 225 | @rem PIN THE MSBUILD SIDE TOO. A .wixproj referencing WixToolset.Sdk without a version\r | |
| 226 | @rem resolves to the latest - 7.x, same EULA - and nothing here constrains it. Pin it in the\r | |
| 227 | @rem project: <Project Sdk="WixToolset.Sdk/5.0.2">.\r | |
| 228 | @rem\r | |
| 229 | @rem dotnet.exe is called by full path: winget put the SDK on the machine PATH a few lines\r | |
| 230 | @rem ago, but this cmd session inherited its environment before that and cannot see it.\r | |
| 231 | @rem install-then-update is for re-runs - install fails once the tool is there, and update\r | |
| 232 | @rem then holds it at exactly 5.0.2 - which keeps this script idempotent like the rest.\r | |
| 649b04df MV |
233 | @rem\r |
| 234 | @rem %ProgramFiles%\dotnet is the NATIVE SDK's root on every architecture, ARM64\r | |
| 235 | @rem included - what winget just installed. An x64 SDK installed alongside it on\r | |
| 236 | @rem an ARM64 box goes to %ProgramFiles%\dotnet\x64 instead, so fall back there\r | |
| 237 | @rem for a machine that only ever got the x64 one. Prefer the native root: the\r | |
| 238 | @rem ARM64 SDK runs the wix tool natively, and building an MSI is not something\r | |
| 239 | @rem worth doing through emulation.\r | |
| aa6eb783 | 240 | set "DOTNET_EXE=%ProgramFiles%\dotnet\dotnet.exe"\r |
| 649b04df MV |
241 | if not exist "%DOTNET_EXE%" set "DOTNET_EXE=%ProgramFiles%\dotnet\x64\dotnet.exe"\r |
| 242 | if not exist "%DOTNET_EXE%" echo [setup-windows] WARNING: dotnet.exe not found; skipping the WiX 5.0.2 pin.\r | |
| 243 | if not exist "%DOTNET_EXE%" goto :after_wix\r | |
| 244 | \r | |
| aa6eb783 MV |
245 | "%DOTNET_EXE%" tool install --global wix --version 5.0.2 || "%DOTNET_EXE%" tool update --global wix --version 5.0.2\r |
| 246 | \r | |
| 247 | @rem Report what the pin actually produced. By full path again, and because the shim lands in\r | |
| 248 | @rem a directory this session's PATH predates: expect "5.0.2+<commit>", not 7.x.\r | |
| 249 | "%USERPROFILE%\.dotnet\tools\wix.exe" --version\r | |
| 250 | \r | |
| 649b04df MV |
251 | :after_wix\r |
| 252 | \r | |
| 3c096107 MV |
253 | @rem ---------------------------------------------------------------------------\r |
| 254 | @rem No package manager needed for the Windows build\r | |
| 255 | @rem\r | |
| 256 | @rem Just:\r | |
| 257 | @rem cd windows && cmake -B build -G "Visual Studio 17 2022" -A x64 && cmake --build build --config Release\r | |
| 649b04df MV |
258 | @rem\r |
| 259 | @rem -A selects the TARGET, independently of the host. On an ARM64 box the same\r | |
| 260 | @rem generator cross-compiles all three, and MSVC's ARM64-hosted toolchain is used\r | |
| 261 | @rem for each - nothing is emulated:\r | |
| 262 | @rem -A ARM64 native ARM64 binaries\r | |
| 263 | @rem -A x64 x64 binaries (run here under emulation)\r | |
| 264 | @rem -A Win32 x86 binaries\r | |
| 265 | @rem Use the generator matching the Visual Studio the elevated half installed -\r | |
| 266 | @rem "Visual Studio 17 2022" on x64, "Visual Studio 18 2026" on ARM64 - or just\r | |
| 267 | @rem let CMake pick the newest it finds.\r | |
| 3c096107 MV |
268 | @rem ---------------------------------------------------------------------------\r |
| 269 | \r | |
| 649b04df | 270 | @rem --- Elevated installs (Visual Studio, WDK, system tools) ---\r |
| 3c096107 MV |
271 | @rem The elevated script runs in its own window and logs to setup-windows-uac.log.\r |
| 272 | @rem -PassThru + $p.ExitCode propagates its real exit code back through to ERRORLEVEL.\r | |
| 273 | set "UAC_LOG=%~dp0setup-windows-uac.log"\r | |
| 274 | if exist "%UAC_LOG%" del "%UAC_LOG%"\r | |
| 275 | \r | |
| cd774a19 MV |
276 | @rem %ELEV% was worked out at the top of this script - see the comment there for\r |
| 277 | @rem why `Start-Process -Verb RunAs` cannot be trusted to report this itself.\r | |
| 278 | if "%ELEV%"=="NOLUA" goto :elev_impossible\r | |
| 279 | if "%ELEV%"=="ALREADY" goto :elev_direct\r | |
| 280 | \r | |
| 281 | @rem Not elevated, UAC is on: request it. Expect a prompt.\r | |
| 282 | echo [setup-windows] Requesting elevation ^(expect a UAC prompt^)...\r | |
| 95307dbb | 283 | powershell -NoProfile -Command "$p = Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','""%~dp0setup-windows-with-uac.ps1""' -Wait -PassThru; exit $p.ExitCode"\r |
| 3c096107 | 284 | set "UAC_RC=%ERRORLEVEL%"\r |
| cd774a19 MV |
285 | goto :elev_done\r |
| 286 | \r | |
| 287 | :elev_direct\r | |
| 288 | echo [setup-windows] Already running elevated; running the elevated half directly.\r | |
| 289 | powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0setup-windows-with-uac.ps1"\r | |
| 290 | set "UAC_RC=%ERRORLEVEL%"\r | |
| 291 | goto :elev_done\r | |
| 292 | \r | |
| 293 | :elev_impossible\r | |
| 294 | echo.\r | |
| 295 | echo [setup-windows] SKIPPING the elevated half: this account cannot elevate.\r | |
| 296 | echo [setup-windows] UAC is disabled machine-wide ^(EnableLUA = 0^) and you are not an administrator,\r | |
| 297 | echo [setup-windows] so Windows offers no way to elevate - there is no prompt to accept. With UAC off,\r | |
| 298 | echo [setup-windows] 'Start-Process -Verb RunAs' is silently ignored and reports success, which is why\r | |
| 299 | echo [setup-windows] this used to look like a cancelled prompt.\r | |
| 300 | echo [setup-windows]\r | |
| 301 | echo [setup-windows] Not installed: Visual Studio components ^(including clang-cl^), the WDK,\r | |
| 302 | echo [setup-windows] rsync, and the OpenSSH server. Everything per-user above is unaffected.\r | |
| 303 | echo [setup-windows]\r | |
| 304 | echo [setup-windows] To finish the box, either sign in to an administrator account and re-run this\r | |
| 305 | echo [setup-windows] script, or have an administrator run setup-windows-with-uac.ps1 there. Then\r | |
| 306 | echo [setup-windows] re-run setup-windows-no-uac.ps1 as yourself, so the per-user PATH and .gitconfig\r | |
| 307 | echo [setup-windows] land in YOUR profile rather than the administrator's.\r | |
| 308 | echo.\r | |
| 309 | set "UAC_RC=SKIPPED"\r | |
| 310 | \r | |
| 311 | :elev_done\r | |
| 3c096107 MV |
312 | \r |
| 313 | @rem --- Surface the elevated session's output (its window has already closed) ---\r | |
| cd774a19 MV |
314 | @rem\r |
| 315 | @rem A missing log is NOT self-explanatory, so do not guess at one cause. The\r | |
| 316 | @rem elevated script writes its transcript as almost its first act, so no log\r | |
| 317 | @rem means it never got as far as running: either the prompt was declined, or it\r | |
| 318 | @rem started unelevated and stopped on its own #Requires line. Which of those it\r | |
| 319 | @rem was is already known from %ELEV%, so report that instead of speculating.\r | |
| 320 | if "%UAC_RC%"=="SKIPPED" goto :after_uac_log\r | |
| 3c096107 MV |
321 | if exist "%UAC_LOG%" (\r |
| 322 | echo.\r | |
| 323 | echo ===== elevated setup log ^(%UAC_LOG%^) =====\r | |
| 324 | type "%UAC_LOG%"\r | |
| 325 | echo ===== end of elevated setup log =====\r | |
| 326 | ) else (\r | |
| 327 | echo [setup-windows] WARNING: no elevated log found at "%UAC_LOG%".\r | |
| cd774a19 MV |
328 | if "%ELEV%"=="PROMPT" echo [setup-windows] The elevated window never started - the UAC prompt was most likely declined.\r |
| 329 | if "%ELEV%"=="ALREADY" echo [setup-windows] The elevated half exited before writing its transcript; see its output above.\r | |
| 3c096107 | 330 | )\r |
| cd774a19 | 331 | :after_uac_log\r |
| 3c096107 | 332 | \r |
| 2bbc9b41 MV |
333 | @rem --- Non-elevated PowerShell half ---\r |
| 334 | @rem WinMerge on the user PATH, BinSkim, and the global git config (identity +\r | |
| 335 | @rem core.sshCommand -> a Win32-OpenSSH client, so git shares the Windows\r | |
| 336 | @rem ssh-agent). EDIT THE GIT IDENTITY at the top of setup-windows-no-uac.ps1\r | |
| 337 | @rem before the first run.\r | |
| 338 | @rem\r | |
| 339 | @rem Deliberately NOT elevated: every step writes per-user state (the HKCU PATH,\r | |
| 340 | @rem the .gitconfig under %USERPROFILE%), which the elevated half would write to\r | |
| 341 | @rem the administrator profile instead.\r | |
| 342 | @rem\r | |
| 343 | @rem AFTER the elevated half on purpose: core.sshCommand prefers the ssh.exe that\r | |
| 344 | @rem half unpacks beside rsync.exe - a push through the in-box client is capped\r | |
| 345 | @rem at ~17MB/s - and it can only prefer it once it is on disk. Run either way,\r | |
| 346 | @rem including when the elevated half failed above: nothing here depends on it,\r | |
| 347 | @rem and the fallback is the in-box client that Windows already has.\r | |
| 348 | @rem\r | |
| 349 | @rem Non-fatal: these are conveniences, and the elevated half is the part worth\r | |
| 350 | @rem the UAC prompt. A failure warns and provisioning continues.\r | |
| 351 | powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0setup-windows-no-uac.ps1"\r | |
| 352 | if not "%ERRORLEVEL%"=="0" echo [setup-windows] WARNING: setup-windows-no-uac.ps1 reported a failure ^(see above^); continuing.\r | |
| 353 | \r | |
| cd774a19 MV |
354 | @rem Skipping the elevated half is a reported, understood outcome on a box where\r |
| 355 | @rem elevation is impossible - not a failure to exit non-zero over. The per-user\r | |
| 356 | @rem provisioning above did run, and re-running from an administrator account is\r | |
| 357 | @rem the documented next step.\r | |
| 358 | if "%UAC_RC%"=="SKIPPED" goto :uac_reported\r | |
| 3c096107 MV |
359 | if not "%UAC_RC%"=="0" (\r |
| 360 | echo.\r | |
| 361 | echo [setup-windows] ELEVATED SETUP FAILED ^(exit code %UAC_RC%^). See log above.\r | |
| 362 | exit /b %UAC_RC%\r | |
| 363 | )\r | |
| 364 | echo.\r | |
| 365 | echo [setup-windows] Elevated setup completed successfully.\r | |
| cd774a19 MV |
366 | goto :uac_reported\r |
| 367 | \r | |
| 368 | :uac_reported\r | |
| 369 | if "%UAC_RC%"=="SKIPPED" echo.\r | |
| 370 | if "%UAC_RC%"=="SKIPPED" echo [setup-windows] Per-user setup complete; the elevated half was skipped ^(see above^).\r | |
| 3c096107 MV |
371 | \r |
| 372 | @rem Removed: this doesn't work as well as I hoped, maybe try again later\r | |
| 373 | @rem -- Install Headroom ---\r | |
| 374 | @rem py -m pip install "headroom-ai[all]"\r | |
| 375 | @rem npm install headroom-ai\r | |
| 376 | \r | |
| 649b04df MV |
377 | @rem Pillow publishes win_arm64 wheels alongside win_amd64, so `py` - the ARM64\r |
| 378 | @rem Python winget just installed - gets a native wheel and never falls back to\r | |
| 379 | @rem building from source. Any package WITHOUT an ARM64 wheel does fall back, and\r | |
| 380 | @rem that source build needs the MSVC toolchain the elevated half installs.\r | |
| 381 | py -m pip install Pillow\r | |
| 382 | \r | |
| 383 | if "%IS_ARM64%"=="1" (\r | |
| 384 | echo.\r | |
| 385 | echo [setup-windows] ARM64 notes:\r | |
| 386 | echo [setup-windows] native ARM64: Git, Python, .NET SDK, PowerShell, VS Code, Windows Terminal,\r | |
| 387 | echo [setup-windows] WinMerge, Brave, Sysinternals ^(the *64a.exe variants^),\r | |
| 388 | echo [setup-windows] Claude Code, CMake, Ninja, and the SDK/WPT tools.\r | |
| 389 | echo [setup-windows] compilers : MSVC and clang-cl from Visual Studio 2026, plus upstream\r | |
| 390 | echo [setup-windows] LLVM - all three native ARM64, two different Clang majors.\r | |
| 391 | echo [setup-windows] emulated x64: iperf3, NASM, OpenCppCoverage, BinSkim, rsync.exe, AGI.\r | |
| 392 | echo [setup-windows] unavailable : VirtualBox, the Windows 7 x86 test VM, Intel VTune,\r | |
| 393 | echo [setup-windows] and the v141 / Windows XP targeting toolset.\r | |
| 394 | )\r | |
| cd774a19 MV |
395 | @rem The list above is what this script PROVIDES on ARM64, not necessarily what\r |
| 396 | @rem landed on this run - so point at the audit, which reports the actual state.\r | |
| 397 | if "%ELEV%"=="NOLUA" (\r | |
| 398 | echo [setup-windows] NOT on this box: everything needing elevation was skipped, including\r | |
| 399 | echo [setup-windows] Visual Studio's clang-cl, the .NET SDK and CMake. The\r | |
| 400 | echo [setup-windows] architecture audit above lists what is really installed.\r | |
| 401 | )\r |