<# .SYNOPSIS Install the FlatRender Node Agent as a Windows service (native sc.exe — no NSSM). .DESCRIPTION Registers flatrender-node-agent.exe as an auto-start service that survives reboots and auto-restarts on crash. Configuration is read from `agent.env` placed next to the exe (see agent.env.example), so no per-service environment plumbing is needed. Run from an ELEVATED PowerShell prompt (Administrator). .PARAMETER ExePath Path to flatrender-node-agent.exe. Defaults to the exe beside this script. .PARAMETER ServiceName Windows service name. Default: FlatRenderNodeAgent. .EXAMPLE .\install-service.ps1 .\install-service.ps1 -ExePath C:\flatrender\flatrender-node-agent.exe #> param( [string]$ExePath = (Join-Path $PSScriptRoot "flatrender-node-agent.exe"), [string]$ServiceName = "FlatRenderNodeAgent", [string]$DisplayName = "FlatRender Node Agent" ) $ErrorActionPreference = "Stop" # ── Elevation check ─────────────────────────────────────────────────────────── $principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Error "This script must be run as Administrator. Right-click PowerShell → Run as administrator." exit 1 } # ── Validate exe + config ───────────────────────────────────────────────────── if (-not (Test-Path $ExePath)) { Write-Error "Executable not found: $ExePath`nBuild it first (see README) and copy it here." exit 1 } $ExePath = (Resolve-Path $ExePath).Path $envFile = Join-Path (Split-Path $ExePath) "agent.env" if (-not (Test-Path $envFile)) { Write-Warning "No agent.env found next to the exe at: $envFile" Write-Warning "Copy agent.env.example → agent.env and fill in NODE_ID / NODE_HMAC_SECRET before the service will work." } # ── Remove any existing instance ────────────────────────────────────────────── $existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue if ($existing) { Write-Host "Service '$ServiceName' already exists — stopping and removing it first..." if ($existing.Status -ne 'Stopped') { Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue } & sc.exe delete $ServiceName | Out-Null Start-Sleep -Seconds 2 } # ── Create the service ──────────────────────────────────────────────────────── # binPath must quote the exe path (spaces). start=auto → launches at boot. Write-Host "Creating service '$ServiceName'..." & sc.exe create $ServiceName binPath= "`"$ExePath`"" start= auto DisplayName= "$DisplayName" | Out-Null & sc.exe description $ServiceName "FlatRender render-node agent: claims and renders After Effects jobs." | Out-Null # ── Crash recovery: restart after 5s, three times, reset window 1 day ───────── & sc.exe failure $ServiceName reset= 86400 actions= restart/5000/restart/5000/restart/5000 | Out-Null # ── Start it ────────────────────────────────────────────────────────────────── Write-Host "Starting service..." Start-Service -Name $ServiceName Start-Sleep -Seconds 2 $svc = Get-Service -Name $ServiceName Write-Host "" Write-Host "✓ Installed and $($svc.Status)." -ForegroundColor Green Write-Host " Service : $ServiceName" Write-Host " Exe : $ExePath" Write-Host " Config : $envFile" Write-Host "" Write-Host " Health : curl http://localhost:7777/health" Write-Host " Logs : Get-WinEvent -ProviderName 'Service Control Manager' | Select-Object -First 5" Write-Host " Stop : Stop-Service $ServiceName" Write-Host " Remove : .\uninstall-service.ps1"