diff --git a/farmq-install-en.ps1 b/farmq-install-en.ps1 index 79583fa..8a69f4d 100644 --- a/farmq-install-en.ps1 +++ b/farmq-install-en.ps1 @@ -111,43 +111,63 @@ function Install-Tailscale { Write-Info "Installing Tailscale for Windows..." - # Always use the 'latest' installer from the official stable channel. + # Use the official MSI from the 'latest' stable channel and install it with + # msiexec /quiet. The previous approach (tailscale-setup-latest.exe /S) is the + # NSIS GUI installer; its silent switch does NOT reliably register the + # 'Tailscale' service or drop tailscale.exe before the script continues, which + # caused "service not found" / "executable not found" right after install. + # The MSI installs the service synchronously and is the supported unattended path. # NOTE: GitHub's "latest release" tag and pkgs.tailscale.com/stable can be out - # of sync (e.g. GitHub reports 1.98.3 while stable already serves 1.98.4), so - # building a versioned URL such as tailscale-setup-.exe results in a - # 404. The 'latest' alias always exists, so we use it directly. - $downloadUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-latest.exe" - $tempPath = "$env:TEMP\tailscale-setup-latest.exe" - + # of sync, so we use the version-less 'latest' alias which always exists. + $downloadUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-latest-amd64.msi" + $tempPath = "$env:TEMP\tailscale-setup-latest.msi" + $logPath = "$env:TEMP\tailscale-install.log" + try { Write-Status "Downloading Tailscale from: $downloadUrl" Invoke-WebRequest -Uri $downloadUrl -OutFile $tempPath -UseBasicParsing - + Write-Status "Installing Tailscale... (please wait)" - Start-Process -FilePath $tempPath -ArgumentList "/S" -Wait - + $proc = Start-Process -FilePath "msiexec.exe" ` + -ArgumentList "/i", "`"$tempPath`"", "/quiet", "/norestart", "/l*v", "`"$logPath`"" ` + -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" + } + # Refresh PATH environment variable $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - - # Verify installation - Start-Sleep -Seconds 3 - $tailscaleInstalled = Get-Command "tailscale" -ErrorAction SilentlyContinue - if (-not $tailscaleInstalled) { - # Try direct path - $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" - if (Test-Path $tailscaleExe) { - # Add Tailscale to PATH - $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine") - if ($currentPath -notlike "*Tailscale*") { - [Environment]::SetEnvironmentVariable("Path", "$currentPath;C:\Program Files\Tailscale", "Machine") - $env:Path = "$env:Path;C:\Program Files\Tailscale" - } + + # 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*") { + [Environment]::SetEnvironmentVariable("Path", "$currentPath;C:\Program Files\Tailscale", "Machine") + } + if ($env:Path -notlike "*Tailscale*") { + $env:Path = "$env:Path;C:\Program Files\Tailscale" } } - + + # Wait for tailscale.exe to actually appear (install can lag a few seconds) + Write-Status "Waiting for Tailscale to be ready..." + $ready = $false + for ($i = 0; $i -lt 15; $i++) { + if ((Get-Command "tailscale" -ErrorAction SilentlyContinue) -or (Test-Path $tailscaleExe)) { + $ready = $true + break + } + Start-Sleep -Seconds 2 + } + if (-not $ready) { + throw "Tailscale executable did not appear after installation. See log: $logPath" + } + Remove-Item $tempPath -Force -ErrorAction SilentlyContinue Write-Success "Tailscale installation completed" - + } catch { Write-Error "Tailscale installation failed: $($_.Exception.Message)" @@ -162,8 +182,15 @@ function Start-TailscaleService { Write-Status "Starting Tailscale service..." try { - # Start Tailscale service - $service = Get-Service -Name "Tailscale" -ErrorAction SilentlyContinue + # The MSI registers a service named "Tailscale"; it may take a few seconds + # to appear, so poll for it before giving up. + $service = $null + for ($i = 0; $i -lt 15; $i++) { + $service = Get-Service -Name "Tailscale" -ErrorAction SilentlyContinue + if ($service) { break } + Start-Sleep -Seconds 2 + } + if ($service) { if ($service.Status -ne "Running") { Start-Service -Name "Tailscale" @@ -171,7 +198,19 @@ function Start-TailscaleService { } Write-Success "Tailscale service is running." } else { + # Fall back to launching tailscaled directly if the service is missing Write-Warning "Tailscale service not found. Attempting manual start..." + $tailscaled = "C:\Program Files\Tailscale\tailscaled.exe" + if (Test-Path $tailscaled) { + Start-Process -FilePath $tailscaled -ArgumentList "install" -Wait -ErrorAction SilentlyContinue + Start-Sleep -Seconds 3 + $service = Get-Service -Name "Tailscale" -ErrorAction SilentlyContinue + if ($service -and $service.Status -ne "Running") { + Start-Service -Name "Tailscale" -ErrorAction SilentlyContinue + Start-Sleep -Seconds 3 + } + if ($service) { Write-Success "Tailscale service is running." } + } } } catch { diff --git a/farmq-install.ps1 b/farmq-install.ps1 index 7f5b232..4143190 100644 --- a/farmq-install.ps1 +++ b/farmq-install.ps1 @@ -117,43 +117,62 @@ function Install-Tailscale { Write-Info "Windows용 Tailscale 설치 중..." - # 공식 stable 채널의 'latest' 설치 파일을 항상 사용한다. - # 주의: GitHub "최신 릴리스" 태그와 pkgs.tailscale.com/stable 채널 버전이 - # 어긋날 수 있다(예: GitHub=1.98.3 인데 stable=1.98.4). 그래서 - # tailscale-setup-<버전>.exe 식으로 URL을 조립하면 404가 난다. - # 'latest' 별칭은 항상 존재하므로 이걸 직접 사용한다. - $downloadUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-latest.exe" - $tempPath = "$env:TEMP\tailscale-setup-latest.exe" - + # 공식 stable 채널의 'latest' MSI를 msiexec /quiet 로 설치한다. + # 이전 방식(tailscale-setup-latest.exe /S)은 NSIS GUI 인스톨러로, 사일런트 + # 스위치가 'Tailscale' 서비스나 tailscale.exe 를 스크립트 진행 전에 확실히 + # 설치하지 못해 설치 직후 "service not found" / "executable not found" 오류가 + # 발생했다. MSI는 서비스를 동기적으로 설치하는 공식 무인 설치 경로다. + # 주의: GitHub "최신 릴리스" 태그와 stable 채널 버전이 어긋날 수 있으므로 + # 버전 없는 'latest' 별칭을 사용한다(항상 존재함). + $downloadUrl = "https://pkgs.tailscale.com/stable/tailscale-setup-latest-amd64.msi" + $tempPath = "$env:TEMP\tailscale-setup-latest.msi" + $logPath = "$env:TEMP\tailscale-install.log" + try { Write-Status "Tailscale 다운로드 중: $downloadUrl" Invoke-WebRequest -Uri $downloadUrl -OutFile $tempPath -UseBasicParsing - + Write-Status "Tailscale 설치 중... (잠시 기다려주세요)" - Start-Process -FilePath $tempPath -ArgumentList "/S" -Wait - + $proc = Start-Process -FilePath "msiexec.exe" ` + -ArgumentList "/i", "`"$tempPath`"", "/quiet", "/norestart", "/l*v", "`"$logPath`"" ` + -Wait -PassThru + # 0 = 성공, 3010 = 성공(재부팅 필요) + if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) { + throw "msiexec 종료 코드 $($proc.ExitCode). 로그: $logPath" + } + # PATH 환경변수 새로고침 $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - - # 설치 확인 - Start-Sleep -Seconds 3 - $tailscaleInstalled = Get-Command "tailscale" -ErrorAction SilentlyContinue - if (-not $tailscaleInstalled) { - # 직접 경로 시도 - $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" - if (Test-Path $tailscaleExe) { - # PATH에 Tailscale 경로 추가 - $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine") - if ($currentPath -notlike "*Tailscale*") { - [Environment]::SetEnvironmentVariable("Path", "$currentPath;C:\Program Files\Tailscale", "Machine") - $env:Path = "$env:Path;C:\Program Files\Tailscale" - } + + # 이번 세션 PATH에 설치 경로 보장 + $tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe" + if (Test-Path $tailscaleExe) { + $currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine") + if ($currentPath -notlike "*Tailscale*") { + [Environment]::SetEnvironmentVariable("Path", "$currentPath;C:\Program Files\Tailscale", "Machine") + } + if ($env:Path -notlike "*Tailscale*") { + $env:Path = "$env:Path;C:\Program Files\Tailscale" } } - + + # tailscale.exe 가 실제로 나타날 때까지 대기 (설치가 몇 초 지연될 수 있음) + Write-Status "Tailscale 준비 대기 중..." + $ready = $false + for ($i = 0; $i -lt 15; $i++) { + if ((Get-Command "tailscale" -ErrorAction SilentlyContinue) -or (Test-Path $tailscaleExe)) { + $ready = $true + break + } + Start-Sleep -Seconds 2 + } + if (-not $ready) { + throw "설치 후 Tailscale 실행 파일을 찾을 수 없습니다. 로그: $logPath" + } + Remove-Item $tempPath -Force -ErrorAction SilentlyContinue Write-Success "Tailscale 설치 완료" - + } catch { Write-Error "Tailscale 설치 실패: $($_.Exception.Message)"