Files
steve ed6ccef31b deploy: P2-17 install.ps1 (Windows installer)
Pwsh installer that detects arch, downloads
$Server/agent/binary?os=windows&arch=amd64 to
C:\Program Files\restic-manager\, runs the agent in -enroll-server
[+ -enroll-token] mode (token flow OR announce-and-approve), then
calls 'restic-manager-agent install' to register the SCM service.
Surfaces existing scheduled tasks named *restic* without disabling.

CLAUDE.md restage block updated to also stage install.ps1 alongside
install.sh.
2026-05-04 11:15:18 +01:00

134 lines
4.7 KiB
PowerShell

# install.ps1 — Windows installer for the restic-manager agent (P2-17).
#
# Usage (Run as administrator):
# $env:RM_SERVER = "https://restic.lab.example"
# $env:RM_TOKEN = "<one-time-token>" # omit for announce-and-approve
# iwr "$env:RM_SERVER/install/install.ps1" -UseBasicParsing | iex
#
# What it does:
# 1. checks for admin elevation
# 2. downloads the matching agent binary from the server
# 3. lays down C:\Program Files\restic-manager\ and
# C:\ProgramData\restic-manager\ (config + state)
# 4. registers the agent as a Windows service via the agent's own
# `install` subcommand (which uses the SCM API)
# 5. enrolls (token flow if RM_TOKEN set, otherwise announce flow)
# by spawning the agent with the right CLI flags and waits
# until config is written
# 6. surfaces (but does NOT disable) any existing scheduled tasks
# whose name contains "restic" so the operator can decide
#
# Idempotent — safe to re-run.
[CmdletBinding()]
param(
[string]$Server = $env:RM_SERVER,
[string]$Token = $env:RM_TOKEN,
[string]$InstallDir = 'C:\Program Files\restic-manager',
[string]$DataDir = 'C:\ProgramData\restic-manager'
)
$ErrorActionPreference = 'Stop'
function Test-Admin {
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$pri = New-Object System.Security.Principal.WindowsPrincipal($id)
return $pri.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Detect-Arch {
switch ($env:PROCESSOR_ARCHITECTURE) {
'AMD64' { return 'amd64' }
'ARM64' { return 'arm64' }
default { throw "unsupported PROCESSOR_ARCHITECTURE: $($env:PROCESSOR_ARCHITECTURE)" }
}
}
function Detect-ResticTasks {
Write-Host ''
Write-Host '— Existing restic-named scheduled tasks (review manually) —'
try {
$tasks = Get-ScheduledTask -ErrorAction SilentlyContinue |
Where-Object { $_.TaskName -match 'restic' -or $_.TaskPath -match 'restic' }
if ($tasks) {
foreach ($t in $tasks) {
Write-Host " * $($t.TaskPath)$($t.TaskName) state=$($t.State)"
Write-Host " Disable with: Disable-ScheduledTask -TaskName '$($t.TaskName)' -TaskPath '$($t.TaskPath)'"
}
} else {
Write-Host ' (none found)'
}
} catch {
Write-Host ' (Get-ScheduledTask failed; review the Task Scheduler UI manually)'
}
Write-Host ''
}
# --- preflight -------------------------------------------------------
if (-not (Test-Admin)) {
throw 'install.ps1: must be run from an elevated PowerShell (Run as administrator).'
}
if (-not $Server) {
throw 'install.ps1: -Server (or $env:RM_SERVER) is required, e.g. https://restic.lab.example'
}
$arch = Detect-Arch
Write-Host "install.ps1: server=$Server arch=$arch"
# --- directories -----------------------------------------------------
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
New-Item -ItemType Directory -Force -Path $DataDir | Out-Null
# --- download agent --------------------------------------------------
$agentExe = Join-Path $InstallDir 'restic-manager-agent.exe'
$tmpExe = "$agentExe.tmp"
$dlURL = "$Server/agent/binary?os=windows&arch=$arch"
Write-Host "install.ps1: downloading $dlURL"
Invoke-WebRequest -UseBasicParsing -Uri $dlURL -OutFile $tmpExe
# Atomic-ish replace: stop service if running so the .exe isn't busy.
try { Stop-Service -Name 'restic-manager-agent' -ErrorAction SilentlyContinue } catch {}
Move-Item -Force -Path $tmpExe -Destination $agentExe
# --- enroll / announce -----------------------------------------------
$cfgPath = Join-Path $DataDir 'agent.yaml'
$args = @('-config', $cfgPath, '-enroll-server', $Server)
if ($Token) {
$args += @('-enroll-token', $Token)
Write-Host 'install.ps1: enrolling with one-time token'
} else {
Write-Host 'install.ps1: no RM_TOKEN — running announce-and-approve flow.'
Write-Host ' The fingerprint will print below. Compare it with the dashboard before clicking Accept.'
}
& $agentExe @args
if ($LASTEXITCODE -ne 0) {
throw "install.ps1: agent enrolment failed (exit $LASTEXITCODE)"
}
# --- install + start service ----------------------------------------
# The 'install' subcommand registers the service via the SCM. If
# already registered, it errors loudly — re-run with -Force only if
# you've manually verified.
try {
& $agentExe install
} catch {
Write-Host "install.ps1: service may already be registered ($_); continuing."
}
try {
Start-Service -Name 'restic-manager-agent'
} catch {
Write-Host "install.ps1: Start-Service failed ($_); check Event Viewer."
}
Detect-ResticTasks
Write-Host ''
Write-Host 'install.ps1: done.'
Write-Host " config : $cfgPath"
Write-Host " binary : $agentExe"
Write-Host " service: restic-manager-agent (Get-Service to inspect)"