From 99fd031d5a4eeafd8234ea0f5755f738370a1b50 Mon Sep 17 00:00:00 2001 From: PharmQ Admin Date: Sun, 31 May 2026 01:17:07 +0000 Subject: [PATCH] fix(windows): skip install if Tailscale already present (avoid MSI 1603) A prior .exe(NSIS) install leaves Tailscale on disk but not on PATH; the MSI then fails with error 1603 trying to install over it. Now detect the existing binary at C:\Program Files\Tailscale\tailscale.exe and skip installation, and treat a nonzero msiexec exit as success when the binary is already present. Co-Authored-By: Claude Opus 4.8 (1M context) --- farmq-install-en.ps1 | 30 ++++++++++++++++++++++-------- farmq-install.ps1 | 29 +++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/farmq-install-en.ps1 b/farmq-install-en.ps1 index 8a69f4d..cf424ed 100644 --- a/farmq-install-en.ps1 +++ b/farmq-install-en.ps1 @@ -100,15 +100,23 @@ function Test-Requirements { function Install-Tailscale { Write-Status "Checking Tailscale installation..." - # Check existing installation + # Check existing installation (PATH or the default install directory). + # IMPORTANT: a prior run may have installed Tailscale via the .exe (NSIS) even + # though it wasn't on PATH. Re-installing over it with the MSI fails with + # error 1603. So if the binary already exists, skip installation entirely and + # just make sure it's on PATH for this session. + $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" $tailscalePath = Get-Command "tailscale" -ErrorAction SilentlyContinue - if ($tailscalePath) { - $version = & tailscale version 2>$null | Select-Object -First 1 - Write-Info "Tailscale is already installed." - Write-Info "Current version: $version" + if ($tailscalePath -or (Test-Path $tailscaleExe)) { + Write-Info "Tailscale is already installed. Skipping installation." + if (-not $tailscalePath -and ($env:Path -notlike "*Tailscale*")) { + $env:Path = "$env:Path;C:\Program Files\Tailscale" + } + $version = & $tailscaleExe version 2>$null | Select-Object -First 1 + if ($version) { Write-Info "Current version: $version" } return } - + Write-Info "Installing Tailscale for Windows..." # Use the official MSI from the 'latest' stable channel and install it with @@ -133,14 +141,20 @@ function Install-Tailscale { -Wait -PassThru # 0 = success, 3010 = success but reboot required if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) { - throw "msiexec returned exit code $($proc.ExitCode). See log: $logPath" + # 1603 etc. often means a conflicting/partial install already exists. + # If the binary is nonetheless present, treat it as installed and move on; + # otherwise surface the failure with the log path. + if (Test-Path $tailscaleExe) { + Write-Warning "msiexec exit code $($proc.ExitCode), but Tailscale is already present. Continuing." + } else { + throw "msiexec returned exit code $($proc.ExitCode). See log: $logPath" + } } # Refresh PATH environment variable $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") # Make sure the install dir is on PATH for this session - $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" if (Test-Path $tailscaleExe) { $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine") if ($currentPath -notlike "*Tailscale*") { diff --git a/farmq-install.ps1 b/farmq-install.ps1 index de4b351..c108876 100644 --- a/farmq-install.ps1 +++ b/farmq-install.ps1 @@ -106,15 +106,22 @@ function Test-Requirements { function Install-Tailscale { Write-Status "Tailscale 클라이언트 확인 중..." - # 기존 설치 확인 + # 기존 설치 확인 (PATH 또는 기본 설치 경로). + # 중요: 이전 실행에서 .exe(NSIS)로 이미 설치됐는데 PATH엔 안 잡혀 있을 수 + # 있다. 그 위에 MSI로 덮어쓰면 오류 1603으로 실패한다. 그래서 바이너리가 + # 이미 있으면 설치를 통째로 건너뛰고 이번 세션 PATH에만 추가한다. + $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" $tailscalePath = Get-Command "tailscale" -ErrorAction SilentlyContinue - if ($tailscalePath) { - $version = & tailscale version 2>$null | Select-Object -First 1 - Write-Info "Tailscale이 이미 설치되어 있습니다." - Write-Info "현재 버전: $version" + if ($tailscalePath -or (Test-Path $tailscaleExe)) { + Write-Info "Tailscale이 이미 설치되어 있습니다. 설치를 건너뜁니다." + if (-not $tailscalePath -and ($env:Path -notlike "*Tailscale*")) { + $env:Path = "$env:Path;C:\Program Files\Tailscale" + } + $version = & $tailscaleExe version 2>$null | Select-Object -First 1 + if ($version) { Write-Info "현재 버전: $version" } return } - + Write-Info "Windows용 Tailscale 설치 중..." # 공식 stable 채널의 'latest' MSI를 msiexec /quiet 로 설치한다. @@ -138,14 +145,20 @@ function Install-Tailscale { -Wait -PassThru # 0 = 성공, 3010 = 성공(재부팅 필요) if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) { - throw "msiexec 종료 코드 $($proc.ExitCode). 로그: $logPath" + # 1603 등은 충돌하는/불완전한 기존 설치가 있을 때 자주 난다. + # 그래도 바이너리가 있으면 설치된 것으로 보고 계속 진행하고, + # 없으면 로그 경로와 함께 실패를 알린다. + if (Test-Path $tailscaleExe) { + Write-Warning "msiexec 종료 코드 $($proc.ExitCode) 이지만 Tailscale이 이미 존재합니다. 계속 진행합니다." + } else { + throw "msiexec 종료 코드 $($proc.ExitCode). 로그: $logPath" + } } # PATH 환경변수 새로고침 $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") # 이번 세션 PATH에 설치 경로 보장 - $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" if (Test-Path $tailscaleExe) { $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine") if ($currentPath -notlike "*Tailscale*") {