X-Git-Url: https://vilimpoc.org/repos/dotfiles/blobdiff_plain/649b04df2966260f38a18d5225a68bd4e0896b95..4658d6ddc8aaaa7e6b52fe3939151d3b35ddacab:/setup-windows-with-uac.ps1?ds=inline diff --git a/setup-windows-with-uac.ps1 b/setup-windows-with-uac.ps1 index c935e2d..4b7ea94 100644 --- a/setup-windows-with-uac.ps1 +++ b/setup-windows-with-uac.ps1 @@ -11,13 +11,13 @@ - OpenSSH Server (sshd) capability: automatic + started + inbound TCP 22 - rsync for Windows (nuket/rsync-windows) in C:\Tools\rsync, on the machine PATH: rsync.exe plus the ssh.exe it runs, out of the release zip for this - architecture (there is no ARM64 zip; ARM64 gets the x64 one, and the - ssh.exe is kept only if it actually starts) + architecture - x86, x64 and arm64 are all published, so both binaries are + native everywhere. The ssh.exe is kept only if it actually starts. - Visual Studio Community (C++ desktop workload, x86/x64 AND ARM64 build - tools, Spectre libs, WDK VSIX, Win11 SDK 26100, Clang/LLVM, and - on x64 - only - the v141 + Windows XP targeting toolset). VS 2022 on x64, VS 2026 - on ARM64; see $VsChannel. - - Windows Driver Kit 10.0.26100 + tools, Spectre libs, Win11 SDK 26100, and - on x64 only - the WDK VSIX, + Clang/LLVM, and the v141 + Windows XP targeting toolset). VS 2022 on x64, + VS 2026 on ARM64; see $VsChannel. + - Windows Driver Kit 10.0.26100 (x64 only) - Windows Performance Toolkit - xperf, wpr and Windows Performance Analyzer (wpa.exe) - on the machine PATH @@ -27,9 +27,14 @@ 18 (VS 2026) on ARM64, where that toolset cannot exist anyway. ARCHITECTURE. Runs on x64 and on ARM64 (Windows 11 on Arm). On ARM64 the - Visual Studio installer, MSVC and clang-cl are all native ARM64 and - cross-compile ARM64/x64/x86 targets; what changes is called out at each step, - and $HostArch below is what drives it. + Visual Studio installer and MSVC are native ARM64 and cross-compile + ARM64/x64/x86 targets. + + The two architectures deliberately provision DIFFERENT things. x64 is the full + workstation; ARM64 is a constrained VM set up as a single-compiler build box - + MSVC only, with clang-cl and the WDK dropped there. Neither is dropped for lack + of an ARM64 build; see the comments on $ClangComponents and the WDK step. + What changes is called out at each step, and $HostArch below is what drives it. #> $ErrorActionPreference = 'Stop' @@ -37,22 +42,30 @@ $ErrorActionPreference = 'Stop' # --------------------------------------------------------------------------- # Host architecture # -# RuntimeInformation.OSArchitecture rather than PROCESSOR_ARCHITECTURE: this -# script can be launched by a 32-bit or an emulated x64 PowerShell, either of -# which reports the emulated architecture in the environment variable while this -# API still reports the real one. Values seen here: X64, Arm64, X86. +# Read from the machine environment in the registry, because this script can be +# launched by a 32-bit or an emulated x64 PowerShell and BOTH of the obvious +# sources report the emulated architecture in that case. Measured on this box, +# from the x64 PowerShell an x64 shell resolves to: +# [RuntimeInformation]::OSArchitecture X64 <- wrong +# $env:PROCESSOR_ARCHITECTURE AMD64 <- wrong +# HKLM\...\Session Manager\Environment ARM64 <- right +# OSArchitecture is documented as the OS's architecture, and on .NET Core it is; +# under .NET Framework on Prism it is not, so it is kept only as a fallback. # # $IsArm64 gates: -# - which rsync-windows release zip is fetched (there is no ARM64 one) +# - which rsync-windows release zip is fetched (x86 / x64 / arm64, all native) # - which Visual Studio generation is driven ($VsChannel: 18 on Arm, 17 on x64) -# - the Visual Studio component groups (ARM64 build tools in; the v141/XP -# toolset out, because it has no ARM64-hosted compiler and Microsoft does not -# ship Windows XP targeting for Arm hosts. Clang/LLVM is installed on every -# architecture and is native on Arm, so it is NOT gated here) +# - the Visual Studio component groups: ARM64 build tools in; the v141/XP +# toolset out because it has no ARM64-hosted compiler and Microsoft does not +# ship Windows XP targeting for Arm hosts; Clang/LLVM and the WDK VSIX out by +# policy rather than by limitation - both are available and native on Arm +# - whether the Windows Driver Kit is installed at all # - what the VTune and WPT steps report # --------------------------------------------------------------------------- -$HostArch = [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() -$IsArm64 = ($HostArch -eq 'Arm64') +$rawArch = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -ErrorAction SilentlyContinue).PROCESSOR_ARCHITECTURE +if (-not $rawArch) { $rawArch = [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() } +$IsArm64 = ($rawArch -eq 'ARM64') +$HostArch = if ($IsArm64) { 'Arm64' } elseif ($rawArch -eq 'AMD64') { 'X64' } else { $rawArch } function Write-Step([string]$Msg) { Write-Host "`n==> $Msg" -ForegroundColor Cyan @@ -308,20 +321,23 @@ try { # --------------------------------------------------------------------------- Write-Step 'rsync for Windows' $RsyncRepo = 'nuket/rsync-windows' -# The release publishes exactly two assets - x64 and x86 - and no ARM64 one, so -# on ARM64 the x64 build is the right pick: it runs under Prism, and an emulated -# x64 rsync still moves data far faster than the ~17MB/s stdin cap that the whole -# reason for using this build is to avoid. (The transfer is I/O-bound on the -# socket, not on emulated CPU.) Selected off $HostArch rather than -# Is64BitOperatingSystem, which answers "true" on ARM64 and so cannot tell the -# two 64-bit cases apart. +# The release publishes x86, x64 and - since v3.5.0-gdeeda96f - arm64, so every +# architecture this script runs on gets a native build. ARM64 used to take the +# x64 zip under emulation, which was defensible (a transfer is bound by the +# socket, not by emulated CPU) but cost the release's ssh.exe: that x64 binary +# could not load the ARM64 libcrypto.dll in System32 and had to be deleted on +# every run. The arm64 asset ships an ARM64 rsync.exe AND an ARM64 ssh.exe, so +# both halves are now native and the fast client survives. +# +# Selected off $HostArch rather than Is64BitOperatingSystem, which answers "true" +# on ARM64 and so cannot tell the two 64-bit cases apart. $RsyncAsset = switch ($HostArch) { 'X64' { 'rsync-windows-x64.zip' } - 'Arm64' { 'rsync-windows-x64.zip' } + 'Arm64' { 'rsync-windows-arm64.zip' } default { 'rsync-windows-x86.zip' } } if ($IsArm64) { - Write-Host ' ARM64: no native asset is published, using the x64 build under emulation.' -ForegroundColor Yellow + Write-Host ' ARM64: using the native arm64 asset (rsync.exe and ssh.exe both ARM64).' -ForegroundColor Green } # The /releases/latest/download/ redirect rather than the API: unauthenticated # API calls are rate-limited to 60/hour per IP, which a provisioning run behind a @@ -347,15 +363,11 @@ try { if ($v -and ([version]($v -replace '[^0-9.]', '')) -lt [version]'3.8.2') { Write-Warning "$SysCrypto is LibreSSL $v; the release's ssh.exe is built against 3.8.2 (Windows OpenSSH Client 9.5). Update Windows, or expect ssh.exe not to start." } - if ($IsArm64) { - # On ARM64 the presence of libcrypto.dll proves less than it does on - # x64: System32 holds the ARM64 build of it, and the ssh.exe in the - # zip is x64. Whether an emulated x64 process can load that DLL comes - # down to whether it is a plain ARM64 binary or an ARM64X one - not - # something worth deciding by parsing the PE header, when running the - # binary answers it outright. Unpack it, then run it (below). - Write-Host ' ARM64: the x64 ssh.exe will be verified by running it, not by assuming.' -ForegroundColor Yellow - } + # No architecture special-case here any more: the asset chosen above + # matches the host, so the release's ssh.exe and System32's libcrypto.dll + # are the same architecture on every box. The run-it check below still + # happens on all of them - it is cheap, and it is what caught the ARM64 + # mismatch back when this took the x64 zip. } # Download and unpack beside the targets, not over them, so an interrupted @@ -409,11 +421,14 @@ try { # This matters more than it looks. rsync.exe prefers an ssh.exe sitting in its # own directory, so a present-but-unstartable one does not degrade to the # in-box client - it breaks rsync outright, and the error you get is a remote - # shell that died rather than anything naming ssh.exe. The two ways to land - # there are a missing/old System32 libcrypto.dll (x64 boxes) and an ARM64 box - # whose ARM64 libcrypto cannot be loaded by this x64 binary. Removing it is - # the repair in both cases: rsync then falls back to the ssh on the PATH, - # which on ARM64 is the native in-box client. + # shell that died rather than anything naming ssh.exe. The way to land there + # is a missing or too-old System32 libcrypto.dll. Removing it is the repair: + # rsync then falls back to the ssh on the PATH, which is the in-box client. + # + # This also used to fire on every ARM64 run, when the x64 asset was the only + # 64-bit one published and its ssh.exe could not load the ARM64 libcrypto + # (exit 0xC0000135, STATUS_DLL_NOT_FOUND). The arm64 asset fixed that at the + # source; the check stays because it is how that was found in the first place. # # EAP back to Continue for the call: ssh -V writes its version to STDERR, and # under $ErrorActionPreference = 'Stop' a native command's stderr becomes a @@ -421,13 +436,26 @@ try { # $global:LASTEXITCODE is cleared first because an exe that cannot start at # all throws without setting one, and the stale 0 from the previous native # command would otherwise read as success. + # + # DRAIN THE OUTPUT BEFORE READING $LASTEXITCODE. `... | Select-Object -First 1` + # was the original spelling here, and it is a trap: Select-Object stops the + # pipeline the instant it has its one object, and that is when ssh.exe has + # WRITTEN its banner - not when it has exited. PowerShell then tears the + # pipeline down, kills the still-running process, and reports -1. Measured on a + # healthy binary on an x64 box: 24 of 25 runs reported exit -1 through + # Select-Object, and 25 of 25 reported 0 when the output was collected first. + # + # So this check was deleting a perfectly good ssh.exe on almost every run, on + # every architecture, and the resulting fallback to the in-box client - the + # ~17MB/s one this whole step exists to avoid - looked like a property of the + # release rather than a bug in the test. Collect, THEN take the first line. $SshExe = Join-Path $RsyncDir 'ssh.exe' if ($WantSsh -and (Test-Path $SshExe)) { $prevEap = $ErrorActionPreference $ErrorActionPreference = 'Continue' $global:LASTEXITCODE = $null $sshVer = $null - try { $sshVer = (& $SshExe -V 2>&1 | Select-Object -First 1) } catch { } + try { $sshOut = (& $SshExe -V 2>&1); $sshVer = $sshOut | Select-Object -First 1 } catch { } finally { $ErrorActionPreference = $prevEap } if ($LASTEXITCODE -eq 0) { Write-Host " ssh.exe runs: $sshVer" @@ -501,29 +529,39 @@ $BaseComponents = @( # Windows 11 SDK — build number must match the WDK below 'Microsoft.VisualStudio.Component.Windows11SDK.26100' - - # WDK Visual Studio extension (VSIX). The silent wdksetup.exe /quiet does NOT - # install this (it only prompts interactively), so it must be added here. - 'Component.Microsoft.Windows.DriverKit' ) +# WDK Visual Studio extension (VSIX). The silent wdksetup.exe /quiet does NOT +# install this (it only prompts interactively), so it has to be asked for here. +# +# Follows the WDK itself: x64 only. On ARM64 the kit is not installed (see the +# WDK step for why), and this VSIX on its own is just the driver project +# templates and property pages with no headers, libs or tools behind them. +if (-not $IsArm64) { + $BaseComponents += 'Component.Microsoft.Windows.DriverKit' +} + # Clang/LLVM toolset (ClangCL, used in CMakePresets.json). Two parts: the Clang # compiler itself, plus the MSBuild integration providing the "ClangCL" toolset. # -# Installed on every architecture, ARM64 included, and native there - not an -# emulated x64 compiler. Two things establish that: the VSIX is +# x64 ONLY, and NOT because ARM64 cannot have it - it can, natively. The VSIX is # productArch=neutral with no chip/machineArch restriction, so the Arm installer -# offers it; and MSVC's VC\Tools\Llvm tree is partitioned by HOST architecture -# (bin = x86, x64\bin = x64, ARM64\bin = ARM64) with genuine ARM64 binaries -# already in ARM64\bin, which is where clang-cl.exe lands. Unlike the v141/XP -# group below, nothing technical is in the way. +# offers it, and MSVC's VC\Tools\Llvm tree is partitioned by HOST architecture +# (bin = x86, x64\bin = x64, ARM64\bin = ARM64) with genuine ARM64 binaries in +# ARM64\bin, which is where clang-cl.exe lands. It was installed and working here +# before this split. # -# This is the compiler diversity the box is after: MSVC and clang-cl over the -# same sources, both native. -$ClangComponents = @( - 'Microsoft.VisualStudio.Component.VC.Llvm.Clang' - 'Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset' -) +# It is dropped on ARM64 because that machine is a constrained VM provisioned as +# a single-compiler build box: MSVC and nothing else. Compiler diversity - MSVC, +# VS clang-cl and upstream LLVM over the same sources - now lives entirely on the +# x64 machine, which is the one with room for three toolchains. Empty here means +# Invoke-VsModify is never called for this group. +$ClangComponents = if ($IsArm64) { @() } else { + @( + 'Microsoft.VisualStudio.Component.VC.Llvm.Clang' + 'Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset' + ) +} # Windows XP targeting (v141_xp toolset, used in CMakePresets.json). The v141 # (VS2017) build tools provide the 14.16 compiler that the XP toolset wraps; @@ -619,7 +657,14 @@ Write-Host " OK: bootstrapper is a PE ($([math]::Round((Get-Item $VsBootstrap # offered a hard failure here would cost you the whole toolchain over a component # you can add later from the installer UI. Invoke-VsModify -Label 'base toolset + workload' -Ids $BaseComponents -Invoke-VsModify -Label 'Clang / LLVM' -Ids $ClangComponents -Optional +if ($IsArm64) { + Write-Step 'Visual Studio: Clang / LLVM' + Write-Host ' Skipped on ARM64 by choice, not by limitation: a native ARM64 clang-cl is' -ForegroundColor Yellow + Write-Host ' offered here and works. This box is provisioned with MSVC alone; the' -ForegroundColor Yellow + Write-Host ' multi-compiler builds belong on the x64 machine.' -ForegroundColor Yellow +} else { + Invoke-VsModify -Label 'Clang / LLVM' -Ids $ClangComponents -Optional +} if ($IsArm64) { Write-Step 'Visual Studio: Windows XP (v141 + WinXP)' Write-Host ' Skipped on ARM64: the v141 (14.16) toolset ships x86/x64-hosted compilers only,' -ForegroundColor Yellow @@ -680,13 +725,21 @@ if (-not $InstallPath) { $clangArm = Test-Path (Join-Path $llvmRoot 'ARM64\bin\clang-cl.exe') $clangX64 = Test-Path (Join-Path $llvmRoot 'x64\bin\clang-cl.exe') $clangX86 = Test-Path (Join-Path $llvmRoot 'bin\clang-cl.exe') - if ($clangArm -or $clangX64 -or $clangX86) { - Write-Host " clang-cl: $(@(if ($clangArm) {'ARM64'}; if ($clangX64) {'x64'}; if ($clangX86) {'x86'}) -join ', ')" -ForegroundColor Green - # On ARM64 the x64 build would still run, under emulation - so say plainly - # whether the NATIVE one is the one that landed. - if ($IsArm64 -and -not $clangArm) { - Write-Warning 'No ARM64-hosted clang-cl - the x64 one would run under emulation. Re-run the Clang/LLVM pass, or add "C++ Clang tools for Windows" in the installer.' + $clangAny = $clangArm -or $clangX64 -or $clangX86 + if ($IsArm64) { + # Not installed here by design, so its absence is the expected result and + # must not read as a fault. Its PRESENCE is the thing worth a line: a box + # provisioned before this split still carries it, and the component stays + # until it is explicitly removed - the installer never uninstalls what you + # simply stopped asking for. + if ($clangAny) { + Write-Host ' clang-cl: present but no longer provisioned on ARM64 - left over from an earlier run.' -ForegroundColor Yellow + Write-Host ' Remove it with: vs_installer.exe modify --installPath "" --remove Microsoft.VisualStudio.Component.VC.Llvm.Clang --remove Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset --quiet' -ForegroundColor Yellow + } else { + Write-Host ' clang-cl: n/a on ARM64 (MSVC only by design; use the x64 box for ClangCL).' -ForegroundColor DarkGray } + } elseif ($clangAny) { + Write-Host " clang-cl: $(@(if ($clangArm) {'ARM64'}; if ($clangX64) {'x64'}; if ($clangX86) {'x86'}) -join ', ')" -ForegroundColor Green } else { Write-Warning 'clang-cl not found - the ClangCL presets will fail. Add the "C++ Clang tools for Windows" component.' } @@ -715,6 +768,26 @@ if (-not $InstallPath) { # Build 26100 matches the Windows 11 SDK installed above. # Provides IddCx (iddcx.h / iddcx.lib) and UMDF 2.x for Indirect Display Drivers. # linkid=2335869 -> WDK 26100.6584 (per Microsoft "Other WDK Downloads"). +# +# x64 ONLY. Two reasons, and the second is the one that decided it: +# +# 1. The ARM64 box builds user-mode software; no driver is developed on it. +# +# 2. This exact WDK cannot install next to the SDK that VS 2026 brings. The +# WDK requires the MATCHING Windows SDK revision, and revisions are not +# side-by-side - Include\10.0.26100.0 is one directory whichever revision +# wrote it. VS 2026 installs SDK 26100.7705; linkid=2335869 is WDK +# 26100.6584, which is the kit paired with VS 2022. So wdksetup.exe aborts: +# exit 15605, WER signature "WDK / 10.1.26100.6584 / Install / 0x80070642" +# (0x642 = 1602, ERROR_INSTALL_USEREXIT - a silent install cancelling +# itself on a failed prerequisite check). It is not an ARM64 or emulation +# problem; the same pairing fails on x64. +# +# If a driver ever does need building here, the fix is the WDK that matches +# this generation - Microsoft's "Supported and other WDK downloads" table +# pairs VS 2026 with the 28000.x kit - not this link. +# +# On x64 with VS 2022 the SDK and this WDK are the matched pair, so it installs. # --------------------------------------------------------------------------- $WdkVersion = '10.0.26100' # Both hives. The WDK installer is a 32-bit program, so on x64 it writes under @@ -728,7 +801,13 @@ $WdkInstalledRoot = @( ) | ForEach-Object { (Get-ItemProperty $_ -ErrorAction SilentlyContinue).WdkBinRootVersioned } | Where-Object { $_ } | Select-Object -First 1 -if ($WdkInstalledRoot -and $WdkInstalledRoot -match [regex]::Escape($WdkVersion)) { +if ($IsArm64) { + Write-Step 'Windows Driver Kit' + Write-Host ' Skipped on ARM64: this box builds user-mode software only, and WDK 26100.6584' -ForegroundColor Yellow + Write-Host ' cannot install beside the 26100.7705 SDK that Visual Studio 2026 brings - the' -ForegroundColor Yellow + Write-Host ' kit needs the matching SDK revision and they are not side-by-side. See the' -ForegroundColor Yellow + Write-Host ' comment above this step for the exit code and what to use instead.' -ForegroundColor Yellow +} elseif ($WdkInstalledRoot -and $WdkInstalledRoot -match [regex]::Escape($WdkVersion)) { # Re-running wdksetup.exe for an already-present version returns exit code # 2008 (maintenance mode / nothing to do), which is not a real failure. Write-Step "WDK $WdkVersion already installed - skipping ($WdkInstalledRoot)"