igneum/relay/clients/install-agent.ps1

60 lines
4 KiB
PowerShell

# Registers the relay agent as the logon task IgneumRelayService (the manifest IgneumRelayService.xml beside this file:
# runs at this user's logon in the interactive session, hidden, restarted on failure every minute up to 999 times, no
# time limit, one instance), by the agent's full installed path, then starts it. Per user and with no administrator by
# default (LeastPrivilege: a standard user may register a task for themselves, so a signed job can run this on a PC with
# nobody at the keyboard); -Highest registers it elevated, which needs an administrator shell once. Re-running replaces
# the task. Every IgneumRelayAgent* task (the one-shot reboot arms of X25) and the RunOnce key go first: on PC 2 a stale
# one pointed at a path that was not there and popped "Windows cannot find 'igneum-agent'" at every boot (7 October 2026).
# A failure here is a line on stdout and an exit code, never a dialog.
# powershell -ExecutionPolicy Bypass -File install-agent.ps1 [-Highest] [-Remove]
param([switch]$Highest, [switch]$Remove)
$ErrorActionPreference = 'Continue'
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path
$TaskName = 'IgneumRelayService'
function Stale-Tasks {
# every task whose name starts with IgneumRelayAgent, from the CSV listing (the one-shot arms, and any hand-made copy)
$out = @()
try {
$rows = & schtasks.exe /Query /FO CSV /NH 2>$null | ForEach-Object { "$_" }
foreach ($r in $rows) { $n = ($r -split '","')[0].Trim('"'); if ($n -like '\IgneumRelayAgent*') { $out += $n } }
} catch { }
return $out
}
foreach ($t in (Stale-Tasks)) {
& schtasks.exe /End /TN $t 2>&1 | Out-Null
& schtasks.exe /Delete /F /TN $t 2>&1 | Out-Null
Write-Host ('removed the stale task ' + $t)
}
try {
$k = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce'
if ((Test-Path $k) -and ((Get-ItemProperty -Path $k -ErrorAction SilentlyContinue).PSObject.Properties.Name -contains 'IgneumRelayAgent')) { Remove-ItemProperty -Path $k -Name 'IgneumRelayAgent' -ErrorAction SilentlyContinue; Write-Host 'removed the RunOnce key IgneumRelayAgent' }
} catch { }
if ($Remove) {
& schtasks.exe /End /TN $TaskName 2>&1 | Out-Null
& schtasks.exe /Delete /F /TN $TaskName 2>&1 | Out-Null
Write-Host ('removed the ' + $TaskName + ' task (an agent window started by hand is not touched)')
exit 0
}
foreach ($f in @('IgneumRelayService.xml', 'igneum-agent-service.ps1', 'igneum-agent.ps1', 'machine-secret.txt')) {
if (-not (Test-Path (Join-Path $Here $f))) { Write-Host ('missing ' + $f + ' beside this script (unzip the whole client zip from make-clients.sh --machine <name>)'); exit 2 }
}
$level = 'LeastPrivilege'
if ($Highest) { $level = 'HighestAvailable' }
$user = $env:USERDOMAIN + '\' + $env:USERNAME
$xml = Get-Content (Join-Path $Here 'IgneumRelayService.xml') -Raw
$xml = $xml.Replace('__USER__', $user).Replace('__AGENT_DIR__', $Here).Replace('__RUNLEVEL__', $level)
$tmp = Join-Path $env:TEMP ('IgneumRelayService-' + [guid]::NewGuid().ToString('n') + '.xml')
[IO.File]::WriteAllText($tmp, $xml, (New-Object Text.UnicodeEncoding $false, $true))
$code = 1
try {
$out = & schtasks.exe /Create /F /TN $TaskName /XML $tmp 2>&1 | ForEach-Object { "$_" }
$code = $LASTEXITCODE
if ($code -ne 0) { Write-Host ('schtasks /Create failed (' + $code + '): ' + ($out -join ' ')); exit 3 }
Write-Host ('registered ' + $TaskName + ' for ' + $user + ' at ' + $level + ' from ' + $Here)
} finally { Remove-Item -Path $tmp -Force -ErrorAction SilentlyContinue }
& schtasks.exe /Run /TN $TaskName 2>&1 | ForEach-Object { "$_" } | Write-Host
Start-Sleep -Seconds 3
& schtasks.exe /Query /TN $TaskName /V /FO LIST 2>&1 | ForEach-Object { "$_" } | Where-Object { $_ -match '^(TaskName|Status|Logon Mode|Last Run Time|Last Result|Task To Run|Run As User|Schedule Type):' } | Write-Host
Write-Host 'the agent now runs under the task; close any igneum-agent.bat window (the task copy exits while that one holds the mutex, and comes back 15 s after it closes)'
Write-Host ('its log: ' + (Join-Path $env:LOCALAPPDATA 'igneum-relay\logs\agent-service.log'))
exit 0