#Requires -RunAsAdministrator <# .SYNOPSIS Installs the 3x-ui probe-only agent on Windows (64-bit). .DESCRIPTION Downloads x-ui-agent-windows-amd64.exe into C:\x-ui, writes agent.json with "probeOnly": true (Windows nodes run no proxy core: facts, metrics and latency probes only), registers the x-ui-agent Windows service (auto-start) and starts it. Re-running is safe: an existing service is stopped and removed first, and any of -Master/-Token/-Name left empty is inherited from the agent.json already on disk. .EXAMPLE .\install-agent.ps1 -Master "https://panel.example.com/rogue" -Token "" -Name "win-node-1" #> [CmdletBinding()] param( [string]$Master, [string]$Token, [string]$Name, [string]$InstallDir = "C:\x-ui", [string]$AgentUrl = $env:XUI_URL ) $ErrorActionPreference = "Stop" # Release download base, same shape as install-agent.sh's # RELEASE_BASE (the version segment is bumped by the release flow). $ReleaseBase = "https://git.881218.xyz/rogue/3x-ui-agent/releases/download/V2.2.1" if (-not $AgentUrl) { $AgentUrl = "$ReleaseBase/x-ui-agent-windows-amd64.exe" } $ServiceName = "x-ui-agent" $ExeName = "x-ui-agent-windows-amd64.exe" $ExePath = Join-Path $InstallDir $ExeName $ConfigPath = Join-Path $InstallDir "agent.json" # Inherit missing parameters from an existing agent.json (reruns). if (Test-Path $ConfigPath) { $existing = Get-Content $ConfigPath -Raw | ConvertFrom-Json if (-not $Master) { $Master = $existing.master_url } if (-not $Token) { $Token = $existing.token } if (-not $Name) { $Name = $existing.node_name } } if (-not $Master) { throw "missing -Master (and no existing agent.json to inherit from)" } if (-not $Token) { throw "missing -Token (and no existing agent.json to inherit from)" } if (-not $Name) { throw "missing -Name (and no existing agent.json to inherit from)" } New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null # Stop and remove any previous install so the exe file is not locked # by a running service when it is replaced below. Prefer the old # binary's own subcommands; fall back to sc.exe when it is gone. $svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue if ($svc) { if (Test-Path $ExePath) { & $ExePath stop | Out-Null & $ExePath uninstall | Out-Null } else { Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue & sc.exe delete $ServiceName | Out-Null } Start-Sleep -Seconds 1 } # Download the agent binary (via a temp file, then swap into place). [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $tmpExe = "$ExePath.new" Write-Host "Downloading $AgentUrl" Invoke-WebRequest -Uri $AgentUrl -OutFile $tmpExe -UseBasicParsing if (-not (Test-Path $tmpExe) -or (Get-Item $tmpExe).Length -eq 0) { throw "agent download produced an empty file: $AgentUrl" } Move-Item -Force $tmpExe $ExePath # Write agent.json. Windows agents are probe-only: probeOnly is # always set (the design contract, not an option). $config = [ordered]@{ master_url = $Master token = $Token node_name = $Name probeOnly = $true } $json = $config | ConvertTo-Json # Go's encoding/json rejects a UTF-8 BOM, which Set-Content -Encoding # UTF8 would add on Windows PowerShell 5.1: write BOM-less UTF-8. [System.IO.File]::WriteAllText($ConfigPath, $json, (New-Object System.Text.UTF8Encoding($false))) Write-Host "Wrote $ConfigPath (probeOnly)" # Register and start the service. & $ExePath install -config $ConfigPath if ($LASTEXITCODE -ne 0) { throw "service install failed (exit $LASTEXITCODE)" } & $ExePath start if ($LASTEXITCODE -ne 0) { throw "service start failed (exit $LASTEXITCODE)" } Write-Host "3x-ui agent installed and running as service '$ServiceName'." Write-Host "Update later by re-running this script; the master's one-click agent update is intentionally not consumed on Windows."