1$ErrorActionPreference = 'Stop'
2$Server = __SERVER__
3
4function Install-Agent {
5 $Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
6 $Principal = New-Object Security.Principal.WindowsPrincipal($Identity)
7 if ($Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
8 throw 'Run this installer from your usual PowerShell window, without administrator privileges.'
9 }
10 $Base = Join-Path $env:LOCALAPPDATA 'AgentRelay'
11 $Stage = Join-Path $Base ('.install.' + [guid]::NewGuid().ToString('N'))
12 New-Item -ItemType Directory -Force $Base | Out-Null
13 & icacls.exe $Base /inheritance:r /grant:r ('*' + $Identity.User.Value + ':(OI)(CI)F') '*S-1-5-18:(OI)(CI)F' | Out-Null
14 if ($LASTEXITCODE -ne 0) { throw 'Unable to protect the agent folder. Check its permissions and retry.' }
15 try {
16 New-Item -ItemType Directory -Force $Stage | Out-Null
17 $Node = Join-Path $Base 'node.exe'
18 if (!(Test-Path $Node)) {
19 Write-Host 'Downloading the agent runtime…'
20 $Arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64') { 'arm64' } else { 'x64' }
21 $Checksums = (Invoke-WebRequest -UseBasicParsing -TimeoutSec 30 'https://nodejs.org/dist/latest-v24.x/SHASUMS256.txt').Content
22 $Match = [regex]::Match($Checksums, "(?m)^([a-f0-9]{64})\s+(node-(v24\.[0-9]+\.[0-9]+)-win-$Arch\.zip)\s*$")
23 if (!$Match.Success) { throw 'No runtime download is available for this machine.' }
24 $Archive = Join-Path $Stage $Match.Groups[2].Value
25 Invoke-WebRequest -UseBasicParsing -TimeoutSec 120 ("https://nodejs.org/dist/" + $Match.Groups[3].Value + '/' + $Match.Groups[2].Value) -OutFile $Archive
26 if ((Get-FileHash $Archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $Match.Groups[1].Value) {
27 throw 'The runtime checksum did not match. Run the installer again.'
28 }
29 Expand-Archive $Archive $Stage
30 Copy-Item (Join-Path $Stage ($Match.Groups[2].Value.Replace('.zip', '') + '\node.exe')) $Node
31 }
32 Invoke-WebRequest -UseBasicParsing -TimeoutSec 30 "$Server/agent/relay.mjs" -OutFile (Join-Path $Stage 'relay.mjs')
33 Invoke-WebRequest -UseBasicParsing -TimeoutSec 30 "$Server/agent/setup.mjs" -OutFile (Join-Path $Stage 'setup.mjs')
34 & $Node (Join-Path $Stage 'setup.mjs') install $Server $Base
35 if ($LASTEXITCODE -ne 0) { throw 'Installation stopped. Correct the problem above, then run the installer again.' }
36 } finally {
37 Remove-Item -Recurse -Force $Stage
38 }
39}
40
41Install-Agent