]> vilimpoc.org git repositories - dotfiles/blobdiff - setup-windows-with-uac.ps1
dotfiles: stop the ssh.exe check from deleting the ssh.exe it verifies
[dotfiles] / setup-windows-with-uac.ps1
index 52384d4548e317250c822b2fcbfaa67b0d4bdd23..4b7ea948dccce4a7c6b51b0b256499c10fd77716 100644 (file)
@@ -11,8 +11,8 @@
     - OpenSSH Server (sshd) capability: automatic + started + inbound TCP 22\r
     - rsync for Windows (nuket/rsync-windows) in C:\Tools\rsync, on the machine\r
       PATH: rsync.exe plus the ssh.exe it runs, out of the release zip for this\r
-      architecture (there is no ARM64 zip; ARM64 gets the x64 one, and the\r
-      ssh.exe is kept only if it actually starts)\r
+      architecture - x86, x64 and arm64 are all published, so both binaries are\r
+      native everywhere. The ssh.exe is kept only if it actually starts.\r
     - Visual Studio Community (C++ desktop workload, x86/x64 AND ARM64 build\r
       tools, Spectre libs, Win11 SDK 26100, and - on x64 only - the WDK VSIX,\r
       Clang/LLVM, and the v141 + Windows XP targeting toolset). VS 2022 on x64,\r
@@ -53,7 +53,7 @@ $ErrorActionPreference = 'Stop'
 # under .NET Framework on Prism it is not, so it is kept only as a fallback.\r
 #\r
 # $IsArm64 gates:\r
-#   - which rsync-windows release zip is fetched (there is no ARM64 one)\r
+#   - which rsync-windows release zip is fetched (x86 / x64 / arm64, all native)\r
 #   - which Visual Studio generation is driven ($VsChannel: 18 on Arm, 17 on x64)\r
 #   - the Visual Studio component groups: ARM64 build tools in; the v141/XP\r
 #     toolset out because it has no ARM64-hosted compiler and Microsoft does not\r
@@ -321,20 +321,23 @@ try {
 # ---------------------------------------------------------------------------\r
 Write-Step 'rsync for Windows'\r
 $RsyncRepo  = 'nuket/rsync-windows'\r
-# The release publishes exactly two assets - x64 and x86 - and no ARM64 one, so\r
-# on ARM64 the x64 build is the right pick: it runs under Prism, and an emulated\r
-# x64 rsync still moves data far faster than the ~17MB/s stdin cap that the whole\r
-# reason for using this build is to avoid. (The transfer is I/O-bound on the\r
-# socket, not on emulated CPU.) Selected off $HostArch rather than\r
-# Is64BitOperatingSystem, which answers "true" on ARM64 and so cannot tell the\r
-# two 64-bit cases apart.\r
+# The release publishes x86, x64 and - since v3.5.0-gdeeda96f - arm64, so every\r
+# architecture this script runs on gets a native build. ARM64 used to take the\r
+# x64 zip under emulation, which was defensible (a transfer is bound by the\r
+# socket, not by emulated CPU) but cost the release's ssh.exe: that x64 binary\r
+# could not load the ARM64 libcrypto.dll in System32 and had to be deleted on\r
+# every run. The arm64 asset ships an ARM64 rsync.exe AND an ARM64 ssh.exe, so\r
+# both halves are now native and the fast client survives.\r
+#\r
+# Selected off $HostArch rather than Is64BitOperatingSystem, which answers "true"\r
+# on ARM64 and so cannot tell the two 64-bit cases apart.\r
 $RsyncAsset = switch ($HostArch) {\r
     'X64'   { 'rsync-windows-x64.zip' }\r
-    'Arm64' { 'rsync-windows-x64.zip' }\r
+    'Arm64' { 'rsync-windows-arm64.zip' }\r
     default { 'rsync-windows-x86.zip' }\r
 }\r
 if ($IsArm64) {\r
-    Write-Host '    ARM64: no native asset is published, using the x64 build under emulation.' -ForegroundColor Yellow\r
+    Write-Host '    ARM64: using the native arm64 asset (rsync.exe and ssh.exe both ARM64).' -ForegroundColor Green\r
 }\r
 # The /releases/latest/download/ redirect rather than the API: unauthenticated\r
 # API calls are rate-limited to 60/hour per IP, which a provisioning run behind a\r
@@ -360,15 +363,11 @@ try {
         if ($v -and ([version]($v -replace '[^0-9.]', '')) -lt [version]'3.8.2') {\r
             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."\r
         }\r
-        if ($IsArm64) {\r
-            # On ARM64 the presence of libcrypto.dll proves less than it does on\r
-            # x64: System32 holds the ARM64 build of it, and the ssh.exe in the\r
-            # zip is x64. Whether an emulated x64 process can load that DLL comes\r
-            # down to whether it is a plain ARM64 binary or an ARM64X one - not\r
-            # something worth deciding by parsing the PE header, when running the\r
-            # binary answers it outright. Unpack it, then run it (below).\r
-            Write-Host '    ARM64: the x64 ssh.exe will be verified by running it, not by assuming.' -ForegroundColor Yellow\r
-        }\r
+        # No architecture special-case here any more: the asset chosen above\r
+        # matches the host, so the release's ssh.exe and System32's libcrypto.dll\r
+        # are the same architecture on every box. The run-it check below still\r
+        # happens on all of them - it is cheap, and it is what caught the ARM64\r
+        # mismatch back when this took the x64 zip.\r
     }\r
 \r
     # Download and unpack beside the targets, not over them, so an interrupted\r
@@ -422,11 +421,14 @@ try {
     # This matters more than it looks. rsync.exe prefers an ssh.exe sitting in its\r
     # own directory, so a present-but-unstartable one does not degrade to the\r
     # in-box client - it breaks rsync outright, and the error you get is a remote\r
-    # shell that died rather than anything naming ssh.exe. The two ways to land\r
-    # there are a missing/old System32 libcrypto.dll (x64 boxes) and an ARM64 box\r
-    # whose ARM64 libcrypto cannot be loaded by this x64 binary. Removing it is\r
-    # the repair in both cases: rsync then falls back to the ssh on the PATH,\r
-    # which on ARM64 is the native in-box client.\r
+    # shell that died rather than anything naming ssh.exe. The way to land there\r
+    # is a missing or too-old System32 libcrypto.dll. Removing it is the repair:\r
+    # rsync then falls back to the ssh on the PATH, which is the in-box client.\r
+    #\r
+    # This also used to fire on every ARM64 run, when the x64 asset was the only\r
+    # 64-bit one published and its ssh.exe could not load the ARM64 libcrypto\r
+    # (exit 0xC0000135, STATUS_DLL_NOT_FOUND). The arm64 asset fixed that at the\r
+    # source; the check stays because it is how that was found in the first place.\r
     #\r
     # EAP back to Continue for the call: ssh -V writes its version to STDERR, and\r
     # under $ErrorActionPreference = 'Stop' a native command's stderr becomes a\r
@@ -434,13 +436,26 @@ try {
     # $global:LASTEXITCODE is cleared first because an exe that cannot start at\r
     # all throws without setting one, and the stale 0 from the previous native\r
     # command would otherwise read as success.\r
+    #\r
+    # DRAIN THE OUTPUT BEFORE READING $LASTEXITCODE. `... | Select-Object -First 1`\r
+    # was the original spelling here, and it is a trap: Select-Object stops the\r
+    # pipeline the instant it has its one object, and that is when ssh.exe has\r
+    # WRITTEN its banner - not when it has exited. PowerShell then tears the\r
+    # pipeline down, kills the still-running process, and reports -1. Measured on a\r
+    # healthy binary on an x64 box: 24 of 25 runs reported exit -1 through\r
+    # Select-Object, and 25 of 25 reported 0 when the output was collected first.\r
+    #\r
+    # So this check was deleting a perfectly good ssh.exe on almost every run, on\r
+    # every architecture, and the resulting fallback to the in-box client - the\r
+    # ~17MB/s one this whole step exists to avoid - looked like a property of the\r
+    # release rather than a bug in the test. Collect, THEN take the first line.\r
     $SshExe = Join-Path $RsyncDir 'ssh.exe'\r
     if ($WantSsh -and (Test-Path $SshExe)) {\r
         $prevEap = $ErrorActionPreference\r
         $ErrorActionPreference = 'Continue'\r
         $global:LASTEXITCODE = $null\r
         $sshVer = $null\r
-        try { $sshVer = (& $SshExe -V 2>&1 | Select-Object -First 1) } catch { }\r
+        try { $sshOut = (& $SshExe -V 2>&1); $sshVer = $sshOut | Select-Object -First 1 } catch { }\r
         finally { $ErrorActionPreference = $prevEap }\r
         if ($LASTEXITCODE -eq 0) {\r
             Write-Host "    ssh.exe runs: $sshVer"\r