<# .SYNOPSIS One-script BPShowServer installer for Windows. .DESCRIPTION Downloads the latest BPShowServerSetup.exe bundle (or uses a local copy), runs it with the Burn bootstrapper, verifies the service is running, and confirms bpssctl is on the PATH. Remote install (run from an elevated PowerShell): iex (iwr 'https://get.bpshowserver.io/install.ps1').Content Local install: .\install.ps1 .\install.ps1 -LocalBundle .\BPShowServerSetup.exe .\install.ps1 -Silent # no UI, automated .\install.ps1 -Uninstall # remove BPShowServer .PARAMETER LocalBundle Path to a local BPShowServerSetup.exe. Skips the download step. .PARAMETER BundleUrl Override the download URL for the bundle. Default points to the official release endpoint. .PARAMETER Silent Run the installer without any UI (/quiet). Default for unattended installs. .PARAMETER Uninstall Uninstall BPShowServer instead of installing. .PARAMETER ClusterJoin Join this newly-installed node to an existing cluster leader as a member, right after the service comes up. Format: "host:port", e.g. "10.0.10.4:7443". Requires -ClusterInvite and -IUnderstandConfigWillBeReplaced. Destructive: replaces this node's local show/config with the leader's desired state (docs/04-clustering-and-ha.md §2). Calls "bpssctl cluster join" under the hood. .PARAMETER ClusterInvite One-time invite code from the target leader's Cluster page (or "bpshow cluster invite create"). Required with -ClusterJoin. .PARAMETER IUnderstandConfigWillBeReplaced Required explicit acknowledgment alongside -ClusterJoin — every join surface demands it so operators cannot wipe a show by accident. Example: .\install.ps1 -Silent -ClusterJoin 10.0.10.4:7443 -ClusterInvite ABC123 -IUnderstandConfigWillBeReplaced #> param( [string] $LocalBundle = "", [string] $BundleUrl = "https://get.bpshowserver.io/releases/latest/BPShowServerSetup.exe", [switch] $Silent, [switch] $Uninstall, [string] $ClusterJoin = "", [string] $ClusterInvite = "", [switch] $IUnderstandConfigWillBeReplaced ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" $ServiceName = "bpshowserver" $ServerPort = 7474 # ── Elevation check ─────────────────────────────────────────────────────────── $currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() $isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host "Re-launching as Administrator..." -ForegroundColor Yellow $psArgs = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" if ($LocalBundle) { $psArgs += " -LocalBundle `"$LocalBundle`"" } if ($Silent) { $psArgs += " -Silent" } if ($Uninstall) { $psArgs += " -Uninstall" } if ($ClusterJoin) { $psArgs += " -ClusterJoin `"$ClusterJoin`"" } if ($ClusterInvite) { $psArgs += " -ClusterInvite `"$ClusterInvite`"" } if ($IUnderstandConfigWillBeReplaced) { $psArgs += " -IUnderstandConfigWillBeReplaced" } Start-Process powershell -Verb RunAs -ArgumentList $psArgs -Wait exit } # ── Uninstall mode ──────────────────────────────────────────────────────────── if ($Uninstall) { Write-Host "Uninstalling BPShowServer..." -ForegroundColor Cyan # Stop service if running $svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq 'Running') { Write-Host " Stopping service $ServiceName..." Stop-Service -Name $ServiceName -Force } # Find the bundle's cached uninstall entry $uninstallKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" $bundleEntry = Get-ChildItem $uninstallKey -ErrorAction SilentlyContinue | Get-ItemProperty | Where-Object { $_.DisplayName -like "BPShowServer Setup*" } | Select-Object -First 1 if ($bundleEntry) { Write-Host " Running bundle uninstall..." $uninstallCmd = $bundleEntry.QuietUninstallString if ($uninstallCmd) { Start-Process -FilePath "cmd.exe" -ArgumentList "/c $uninstallCmd /quiet" -Wait -NoNewWindow } } else { # Fall back to MSI uninstall if bundle entry not found $msiEntry = Get-ChildItem $uninstallKey -ErrorAction SilentlyContinue | Get-ItemProperty | Where-Object { $_.DisplayName -eq "BPShowServer" } | Select-Object -First 1 if ($msiEntry) { Write-Host " Running MSI uninstall..." Start-Process msiexec -ArgumentList "/x $($msiEntry.PSChildName) /quiet /norestart" -Wait } else { Write-Warning "BPShowServer installation not found in registry." } } Write-Host "BPShowServer uninstalled." -ForegroundColor Green exit } # ── Download or use local bundle ───────────────────────────────────────────── if ($LocalBundle -and (Test-Path $LocalBundle)) { $bundlePath = Resolve-Path $LocalBundle Write-Host "Using local bundle: $bundlePath" -ForegroundColor Cyan } else { $tempDir = Join-Path $env:TEMP "bpshowserver-install" $bundlePath = Join-Path $tempDir "BPShowServerSetup.exe" New-Item -ItemType Directory -Force -Path $tempDir | Out-Null Write-Host "Downloading BPShowServer installer..." -ForegroundColor Cyan Write-Host " From: $BundleUrl" Write-Host " To : $bundlePath" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $wc = New-Object Net.WebClient $wc.DownloadFile($BundleUrl, $bundlePath) Write-Host " Download complete." -ForegroundColor Green } # ── Run installer ──────────────────────────────────────────────────────────── $installArgs = if ($Silent) { "/quiet /norestart" } else { "/norestart" } Write-Host "`nRunning installer..." -ForegroundColor Cyan Write-Host " $bundlePath $installArgs" $proc = Start-Process -FilePath $bundlePath -ArgumentList $installArgs -Wait -PassThru if ($proc.ExitCode -notin @(0, 3010)) { throw "Installer exited with code $($proc.ExitCode). Installation failed." } if ($proc.ExitCode -eq 3010) { Write-Host " A reboot is recommended to complete installation." -ForegroundColor Yellow } # ── Verify service ──────────────────────────────────────────────────────────── Write-Host "`nVerifying BPShowServer service..." -ForegroundColor Cyan $maxWait = 15 $waited = 0 do { Start-Sleep -Seconds 2 $waited += 2 $svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue } while ((-not $svc -or $svc.Status -ne 'Running') -and $waited -lt $maxWait) if ($svc -and $svc.Status -eq 'Running') { Write-Host " Service '$ServiceName' is Running." -ForegroundColor Green } else { Write-Warning "Service '$ServiceName' did not start within ${maxWait}s. Check Event Viewer." } # ── Verify CLI on PATH ──────────────────────────────────────────────────────── Write-Host "`nVerifying bpssctl CLI..." -ForegroundColor Cyan # Refresh PATH in the current process (the MSI modifies the system PATH) $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User") $bpssctl = Get-Command bpssctl -ErrorAction SilentlyContinue if ($bpssctl) { Write-Host " bpssctl found at: $($bpssctl.Source)" -ForegroundColor Green try { $status = & bpssctl status 2>&1 Write-Host " bpssctl status: $status" -ForegroundColor Green } catch { Write-Host " bpssctl is installed (service may still be starting)." -ForegroundColor Yellow } } else { Write-Warning "bpssctl not found on PATH. Open a new shell to pick up the updated PATH." } # ── Optional: join a cluster (docs/04-clustering-and-ha.md §2) ────────────────── if ($ClusterJoin) { if (-not $ClusterInvite -or -not $IUnderstandConfigWillBeReplaced) { Write-Warning "-ClusterJoin requires both -ClusterInvite and -IUnderstandConfigWillBeReplaced. Skipping cluster join." } elseif (-not (Get-Command bpssctl -ErrorAction SilentlyContinue)) { Write-Warning "bpssctl not found on PATH; skipping cluster join. Run it manually once the shell picks up the new PATH:" Write-Warning " bpssctl cluster join $ClusterJoin --invite --i-understand-config-will-be-replaced" } else { Write-Host "`nJoining cluster at $ClusterJoin..." -ForegroundColor Cyan & bpssctl cluster join $ClusterJoin --invite $ClusterInvite --i-understand-config-will-be-replaced if ($LASTEXITCODE -ne 0) { Write-Warning "Cluster join failed (see above). The service is still installed and running standalone." } else { Write-Host " Cluster join complete." -ForegroundColor Green } } } # ── Done ────────────────────────────────────────────────────────────────────── Write-Host "" Write-Host "BPShowServer installed successfully!" -ForegroundColor Green Write-Host "" Write-Host " Web UI : http://localhost:$ServerPort" Write-Host " Service : sc query $ServiceName" Write-Host " CLI : bpssctl status" Write-Host " Logs : Get-EventLog -LogName Application -Source $ServiceName -Newest 20" Write-Host ""