| File | Purpose |
| --- | --- |
| `setup-windows.bat` | Entry point. Runs the winget installs, then launches the elevated half and prints its log, then runs the non-elevated script. |
-| `setup-windows-no-uac.ps1` | The non-elevated, per-user half: WinMerge and BinSkim on the user `PATH`, and the global git config (identity, plus `core.sshCommand`). Can also be run directly from an ordinary prompt. |
+| `setup-windows-no-uac.ps1` | The non-elevated, per-user half: WinMerge and BinSkim on the user `PATH`, the global git config (identity, plus `core.sshCommand`), the native `ninja` pinned ahead of the one Visual Studio bundles, and an architecture audit of everything provisioned. Can also be run directly from an ordinary prompt. |
| `setup-windows-with-uac.ps1` | The elevated half, started via UAC by the batch file. Enables `ssh-agent`, installs the OpenSSH Client and Server capabilities and starts `sshd`, unpacks the `rsync-windows` release zip for this architecture (`rsync.exe` plus the `ssh.exe` it runs) into `C:\Tools\rsync` on the machine `PATH`, then installs Visual Studio Community with the required components, the WDK, and the Windows Performance Toolkit, and reports whether Intel VTune Profiler is present. Can also be run directly from an Administrator prompt. |
| `setup-windows-7-test-env.bat` | Prepares a **Windows 7 VM** as a test target driven from the host by `VBoxManage guestcontrol`. Copy it into the guest and run it there; it is idempotent, so re-run it after any snapshot restore. The per-user half needs no UAC (crash-dialog suppression, no screen blanking, a staging directory, the shared folder on `Z:`); the machine-wide half is skipped with a notice unless run elevated inside the guest. It then reports what the box can actually test: DWM composition, printers, audio capture devices. |
### Two gotchas the audit surfaces
-- **Visual Studio bundles an x64 `ninja.exe` even on ARM64**, and `VsDevCmd.bat`
- **prepends** the VS directories to `PATH`. So inside a Developer Command Prompt
- — exactly where C++ builds happen — the emulated ninja wins over the native one
- `winget install Ninja-build.Ninja` provides. It matters more than a one-off
- tool would, because ninja is re-invoked for every edge in the build graph. Pass
- `-DCMAKE_MAKE_PROGRAM=` the native one, or put its directory ahead of the VS
- one. VS's bundled `cmake.exe` *is* ARM64, so only ninja has this problem.
+- **Visual Studio bundles an x64 `ninja.exe` even on ARM64.** It matters more
+ than a one-off tool would, because ninja is re-invoked for every edge in the
+ build graph — it is the one place emulation is paid over and over rather than
+ once. `winget install Ninja-build.Ninja` gets the native `ninja-winarm64`
+ build, and the `NinjaPath` step pins its directory to the **front** of the user
+ `PATH`. VS's bundled `cmake.exe` *is* ARM64, so only ninja has this problem.
+
+ On which copy wins inside a Developer Command Prompt: the native one. VS adds
+ its ninja from `Common7\Tools\vsdevcmd\ext\cmake.bat`, which does
+ `set "PATH=%PATH%;...\CMake\bin;...\CMake\Ninja"` — an **append**, so the VS
+ directories land at the very end of the composed `PATH`, behind every machine
+ and user entry. A native ninja anywhere on the user `PATH` already beats it,
+ measured on an ARM64 box. The `NinjaPath` step is therefore insurance rather
+ than the load-bearing fix: winget *appends* its package directory to the user
+ `PATH`, so without it the margin rests on two append orders staying as they
+ are, one of them in a file Microsoft owns and revises.
- **Sysinternals ships every architecture in one zip**, and the ARM64 build is
not the default-named exe. `ProcessExplorer.zip` contains `procexp.exe` (x86),
`procexp64.exe` (x64) and `procexp64a.exe` (**ARM64**) — so run the `*64a.exe`