# run would otherwise read as success. $global: because a bare assignment
# would make a local copy that the native call then does not update.
$global:LASTEXITCODE = $null
- try { $version = (& $cand -V 2>&1 | Select-Object -First 1) } catch { }
+ # Collect ALL the output, THEN take its first line. Piped straight into
+ # `Select-Object -First 1`, which is how this used to read, PowerShell
+ # stops the pipeline the moment ssh.exe prints its banner - before it
+ # has exited - kills it, and the exit code comes back -1 instead of 0.
+ # Measured under Windows PowerShell 5.1 against a healthy
+ # C:\Tools\rsync\ssh.exe: 19 of 20 runs reported -1 that way, 0 of 20
+ # once collected first. So this check usually judged the fast client
+ # broken and handed git the in-box one it exists to avoid.
+ # setup-windows-with-uac.ps1 fixed the same trap in its own ssh.exe
+ # check (see DRAIN THE OUTPUT there); this copy was missed.
+ try { $sshOut = @(& $cand -V 2>&1); $version = $sshOut[0] } catch { }
finally { $ErrorActionPreference = $prevEap }
if ($LASTEXITCODE -eq 0) { $winSsh = $cand; break }
$why = if ($null -eq $LASTEXITCODE) { 'it would not start' } else { "exit $LASTEXITCODE" }
# here as accepted emulation, and are now simply not installed on ARM64. That
# is the whole shape of the change - the exceptions that were tolerable one at
# a time added up to a VM full of x64 binaries.
+ #
+ # rsync came off this list when the release started publishing an arm64
+ # asset. An x64 rsync.exe on an ARM64 box is now a leftover from a run before
+ # that, not an accepted exception, so it warns and gets a remedy below.
$KnownEmulated = @{
- 'rsync.exe' = 'no ARM64 asset published; transfer is socket-bound, not CPU-bound'
'iperf3.exe' = 'no ARM64 build published; network-bound anyway'
'py.exe' = 'python.org ships the launcher shim as x86; it execs the native python.exe'
'vswhere.exe' = 'Microsoft ships x86 only; runs once per script'
$Remedies = @{
'ninja.exe' = 'Visual Studio bundles an x64 ninja. Install the native one (winget install Ninja-build.Ninja) and re-run - the NinjaPath step puts its directory at the front of the user PATH.'
'cmake.exe' = 'Install the native build with: winget install Kitware.CMake (its MSI is machine-scope, so it needs an administrator).'
+ 'rsync.exe' = 'Left over from before the release published an arm64 asset. Re-run setup-windows-with-uac.ps1 as an administrator to replace it, and the ARM64 ssh.exe beside it, with the native build.'
}
$vs = $null
'BinSkim.exe' = @((Join-Path $BinSkimDir 'BinSkim.exe'))
'rsync.exe' = @((Join-Path $RsyncDir 'rsync.exe'))
'ssh.exe' = @((Join-Path $env:WINDIR 'System32\OpenSSH\ssh.exe'))
- 'nasm.exe' = @()
+ # NASM's installer falls back to a per-user directory when it cannot
+ # write to Program Files - see the NASM comment in setup-windows.bat. It
+ # registers nothing there, so winget cannot see it (and re-downloads and
+ # re-runs the installer on every run), and it puts nothing on the PATH.
+ # Without these candidates the audit reported "- not installed" for a
+ # nasm.exe that was on disk all along, and then still concluded that
+ # everything had resolved.
+ 'nasm.exe' = @(
+ (Join-Path $env:LOCALAPPDATA 'bin\NASM\nasm.exe')
+ (Join-Path $env:ProgramFiles 'NASM\nasm.exe')
+ (Join-Path ${env:ProgramFiles(x86)} 'NASM\nasm.exe')
+ )
'iperf3.exe' = @()
'OpenCppCoverage.exe' = @((Join-Path $env:ProgramFiles 'OpenCppCoverage\OpenCppCoverage.exe'), (Join-Path ${env:ProgramFiles(x86)} 'OpenCppCoverage\OpenCppCoverage.exe'))
'vswhere.exe' = @($vsWhereExe)