]> vilimpoc.org git repositories - dotfiles/blob - README.md
dotfiles: add iperf3 and nasm to the per-user winget installs
[dotfiles] / README.md
1 # dotfiles
2
3 Windows development-box provisioning scripts.
4
5 `setup-windows.bat` takes a fresh Windows install to a working C++ / native
6 development environment: editors and shells, Python, the Visual Studio 2022
7 toolchain (including the Clang and Windows XP targeting toolsets), the Windows
8 Driver Kit, and a handful of analysis tools (Sysinternals, OpenCppCoverage,
9 BinSkim, the Windows Performance Toolkit). It also sets the box up to be driven
10 remotely: OpenSSH Server plus an rsync build for Windows, which is what makes a
11 throwaway VM reachable from a Linux host.
12
13 ## Files
14
15 | File | Purpose |
16 | --- | --- |
17 | `setup-windows.bat` | Entry point. Runs the winget installs, then launches the elevated half and prints its log, then runs the non-elevated script. |
18 | `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. |
19 | `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 2022 Community with the required components, the WDK, and the Windows Performance Toolkit, and reports whether Intel VTune Profiler is present. It also puts one ordinary account into `Performance Log Users`, so it can run user-mode ETW sessions unelevated. Can also be run directly from an Administrator prompt — pass `-TraceUser DOMAIN\user` to name that account, and `-EtwRightsOnly` to do that step alone. |
20 | `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. |
21
22 ## Usage
23
24 1. **Edit `setup-windows-no-uac.ps1` first.** The global git identity near the
25    top of the file is empty:
26
27    ```powershell
28    $GitUserName  = ''   # e.g. 'Ada Lovelace'
29    $GitUserEmail = ''   # e.g. 'ada@example.com'
30    ```
31
32    Fill in your own name and email, or leave them empty to keep your identity
33    per-repository - the script skips `user.name` / `user.email` rather than
34    writing a placeholder, and says so. Everything else in that script is set
35    either way.
36
37 2. Run it from a normal (non-elevated) prompt:
38
39    ```bat
40    setup-windows.bat
41    ```
42
43    It will raise a single UAC prompt for the elevated half. Accept it — declining
44    leaves Visual Studio and the WDK uninstalled, and the script says so.
45
46 3. Restart your shell afterwards so the updated user `PATH` is picked up, and
47    reboot if a step reported that a restart was required.
48
49 ## Notes
50
51 - The elevated half writes a transcript to `setup-windows-uac.log` next to the
52   script; the batch file prints it when the elevated window closes. The log is
53   gitignored, as it contains local paths.
54 - **git uses a Win32-OpenSSH client.** `setup-windows-no-uac.ps1` sets
55   `core.sshCommand`. Git for Windows otherwise prefers its own bundled MSYS2
56   `ssh.exe`, which cannot reach the Windows `ssh-agent` service that the elevated
57   half enables - Win32-OpenSSH publishes the agent on a named pipe the MSYS2
58   build does not speak. Without this, keys loaded with `ssh-add` from PowerShell
59   are invisible to `git`, and a push falls back to hunting for a key file and
60   prompting for its passphrase. The value uses forward slashes on purpose: git
61   parses `core.sshCommand` with shell quoting rules, in which a backslash is an
62   escape character.
63 - **Which `ssh.exe` git gets.** `C:\Tools\rsync\ssh.exe` — the fast build the
64   elevated half unpacks — if it is there, `%WINDIR%/System32/OpenSSH/ssh.exe`
65   otherwise. It is the same client with the same `~/.ssh`, agent and
66   `known_hosts`; the difference is the stdin pump, and without it anything git
67   *pushes* is capped at ~17 MB/s. Candidates are tried by **running** them
68   (`ssh -V`), not by `Test-Path`: the fast build needs a `libcrypto.dll` that an
69   image without the OpenSSH Client capability does not have, and a client that
70   will not start should be found here rather than on the next `git push`.
71   This is also why `setup-windows.bat` now runs the elevated half **first** — the
72   fast `ssh.exe` has to exist before the git config step can prefer it. The
73   non-elevated half still runs even when the elevated one failed; it just falls
74   back. Re-run `setup-windows-no-uac.ps1` on its own at any time to re-pick.
75 - All three scripts are idempotent — re-running skips anything already installed.
76   BinSkim in particular checks NuGet for the newest stable version *before*
77   downloading: the package is a self-contained .NET build well over 100 MB, and
78   re-provisioning an up-to-date box should not pay for it. The installed version
79   is tracked in `nupkg-version.txt` beside the tool.
80 - `setup-windows-no-uac.ps1` runs its steps independently: one failing warns and
81   the rest still run, and it exits 1 if any did. The `.bat` reports that and
82   carries on to the elevated half, which is the part worth the UAC prompt. Use
83   `-Skip` to re-run a subset, e.g. `.\setup-windows-no-uac.ps1 -Skip BinSkim`.
84   Run it **non-elevated**: it writes per-user state (the `HKCU` `PATH`, the
85   `.gitconfig` under `%USERPROFILE%`), so an elevated run would configure the
86   administrator's profile instead. It warns if you do.
87 - **Remote access.** OpenSSH Server is installed from the Windows on-demand
88   capability (10/1809+), set to start automatically, and given an inbound TCP 22
89   firewall rule on *all* profiles — a VM's host-only or bridged adapter is
90   routinely classified Public, which is the usual reason a running `sshd` is
91   unreachable. Windows ships no `rsync`, so a build of it
92   ([nuket/rsync-windows](https://github.com/nuket/rsync-windows)) is installed to
93   `C:\Tools\rsync` and added to the **machine** `PATH`. That last detail matters:
94   the remote end of an `rsync` runs non-interactively, with no login shell, and
95   Win32-OpenSSH builds that environment from the registry `PATH` rather than from
96   a profile. Key auth needs `~/.ssh/authorized_keys` ACL'd to just you and
97   `SYSTEM`; accounts in the Administrators group use
98   `C:\ProgramData\ssh\administrators_authorized_keys` instead.
99 - **rsync brings its own `ssh.exe`.** That release ships as one zip per
100   architecture — `rsync-windows-x64.zip` / `rsync-windows-x86.zip`, each holding
101   `rsync.exe`, an `ssh.exe`, `COPYING.txt` and `NOTICE-ssh.txt` — and the
102   elevated half picks the zip for the OS bitness, verifies it against the
103   published `.sha256`, and unpacks the pair together. Together is the point:
104   `rsync.exe` prefers an `ssh.exe` sitting in its own directory, and the release
105   builds one because the client Windows ships reads its stdin 3 KB at a time,
106   which holds a transfer *from* the box at ~17 MB/s however fast the link is.
107   Nothing else about it differs — same `~/.ssh`, same `ssh-agent`, same
108   `known_hosts` — and a bare `ssh` still resolves to the in-box client, which
109   sits ahead of `C:\Tools\rsync` on the `PATH`. It links against the
110   `libcrypto.dll` the **OpenSSH Client** capability puts in `System32` (Windows'
111   own LibreSSL, which uses AES-NI) and ships no copy of its own, so the elevated
112   half installs that capability first and falls back to `rsync.exe` alone,
113   warning, on an image that will not offer it.
114 - The `rsync` download follows the `releases/latest/download/` redirect rather
115   than the GitHub API: unauthenticated API calls are rate-limited to 60/hour per
116   IP, which a provisioning run behind a shared NAT can genuinely exhaust. To hold
117   a box on a known build, pin the tag in `$RsyncUrl`
118   (`.../releases/download/<tag>/<asset>`) instead.
119 - Visual Studio is installed in three labelled passes (base workload, Clang/LLVM,
120   XP toolset) so a failure identifies which component group is responsible.
121 - **Windows Performance Analyzer is not part of Visual Studio.** VS has its own
122   Performance Profiler, which is a different, `.diagsession`-based tool and
123   cannot open an `.etl`. WPA ships with `xperf` and `wpr` in the Windows
124   Performance Toolkit, which exists in exactly two places: as an optional
125   *feature* of the Windows SDK (`OptionId.WindowsPerformanceToolkit`) and inside
126   the Windows ADK, which bundles the same toolkit. Whether the SDK install that
127   Visual Studio performs selects that feature varies by version, so the elevated
128   half **detects first** — `%ProgramFiles(x86)%\Windows Kits\10\Windows
129   Performance Toolkit`, its 64-bit twin, and the ADK location — and only falls
130   back to `winget install Microsoft.WindowsADK` when nothing is there. It then
131   re-asserts that directory on the machine `PATH` (the toolkit's own installer
132   usually does this, and the Start Menu gets *Windows Kits > Windows Performance
133   Toolkit* shortcuts for WPA and WPR). To install just the toolkit instead of the
134   whole ADK, run the standalone SDK setup with
135   `winsdksetup.exe /features OptionId.WindowsPerformanceToolkit /q`. A newer WPA
136   also exists in the Microsoft Store (`winget install --id 9N0W1B2BXGNZ --source
137   msstore`); it is not installed here because the Store source needs an
138   interactive, signed-in session, which the unattended elevated half does not
139   have.
140 - **Intel VTune Profiler is reported, not installed.** The elevated half prints
141   whether it is on the box, its version, and the path to `vtune.exe`; if it is
142   missing it prints the download page instead (and says so if the CPU is not
143   Intel). Automating the install is not worth it here: the offline installer is a
144   ~750 MB download from a URL carrying a per-release GUID with no "latest"
145   redirect behind it, so every new build would mean editing a hard-coded link,
146   and it is only worth having on Intel silicon since hardware event-based
147   sampling reads Intel PMU counters. It does install unattended if you want it
148   scripted elsewhere:
149
150   ```powershell
151   intel-vtune-<version>_offline.exe -a --silent --cli --eula accept
152   ```
153
154   **Running it needs no elevation, but hardware sampling does.** A standard user
155   gets the User-Mode Sampling analyses — `vtune -collect hotspots` and threading
156   — and they work: measured here, collection and finalization, exit 0. Hardware
157   event-based sampling (`uarch-exploration`, `memory-access`, `hotspots -knob
158   sampling-mode=hw`) wants administrator, and VTune says so in a warning at the
159   top of every unelevated run. Note the failure it actually gives is *"cannot
160   recognize the processor"*, which reads like a hardware problem and is not one:
161   the drivers (`sepdrv5`, `sepdal`, `vtss`) are installed and running, and VTune
162   identifies the PMU through them. Unlike ETW there is no group to join for this
163   — the Linux driver can be handed to a `vtune` group, but on Windows the
164   documented answer is to run as administrator.
165
166 - **User-mode ETW tracing without a UAC prompt — and the kernel logger's hard
167   limit.** Out of the box a standard user cannot start *any* event tracing
168   session, not even a user-mode one naming a single provider:
169
170   ```text
171   xperf -start T -on Microsoft-Windows-Kernel-Process -f trace.etl
172       -> Access is denied. (0x5)
173   ```
174
175   Session control is checked against the security descriptor ETW keeps per
176   provider GUID under `HKLM\SYSTEM\CurrentControlSet\Control\WMI\Security`, whose
177   default grants those rights to SYSTEM, Administrators, the service accounts and
178   `BUILTIN\Performance Log Users` — and to nobody else. So the elevated half puts
179   the account named by `-TraceUser` into that group, and the command above then
180   works unelevated; enabling another account later is just
181   `net localgroup "Performance Log Users" <user> /add`. Membership is read into
182   the access token **at logon**, so sign out and back in first — any new logon
183   does it, and an `ssh` login into the box is the quick way to check without
184   dropping the desktop.
185
186   **Kernel traces are not available this way, and cannot be made to be.**
187   `xperf -on base` and `wpr -start` drive the *NT Kernel Logger*, which is
188   reserved for Administrators and LocalSystem — Microsoft documents Performance
189   Log Users access as explicitly not extending to it. That was measured rather
190   than assumed, and the negative result is recorded here so nobody repeats the
191   experiment: with the account in the group, `SeSystemProfilePrivilege` ("Profile
192   system performance") granted to that group, and an explicit ACE giving the
193   group `TRACELOG_ACCESS_KERNEL_LOGGER` on `SystemTraceControlGuid` — all three
194   in place, across a reboot — `xperf -on base` still answered `NT Kernel Logger:
195   Access is denied. (0x5)`. It is not a check an ACE overrides. The privilege
196   grant and the ACE were dropped again rather than left on the box earning
197   nothing: CPU sampling and whole-system traces are elevated work, with `xperf`,
198   `wpr` or VTune from an Administrator prompt.
199
200   Analysis was never affected — `wpa.exe` opens an existing `.etl` as a plain
201   user. This is only about collection.
202
203   The step runs **first** in the elevated half, and `-EtwRightsOnly` runs it and
204   nothing else, which matters because a full run is dominated by the three Visual
205   Studio passes that take minutes even with nothing to do:
206
207   ```powershell
208   Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass',
209       '-File','<repo>\setup-windows-with-uac.ps1','-TraceUser','DOMAIN\user','-EtwRightsOnly'
210   ```
211
212   If you ran an earlier revision of this script, it left both of the grants above
213   on the box. Undo the privilege in `secpol.msc` > Local Policies > User Rights
214   Assignment > "Profile system performance" by removing Performance Log Users.
215   The ACEs sit in the `{9e814aad-3204-11d2-9a82-006008a86939}` value under
216   `HKLM\SYSTEM\CurrentControlSet\Control\WMI\Security`: strip the `LU` entries
217   from that descriptor rather than deleting the value, which also carries entries
218   for SYSTEM, Administrators and two service accounts.
219 - The scripts were extracted from a native Windows project, so the component
220   selection is tuned for that: Spectre-mitigated runtimes, the v141/XP toolset,
221   and driver-kit headers. Trim the component lists in the `.ps1` if you don't
222   need them — each group is a plain array near the top.