Files
AIGame/AIServer/deploy/windows/Install-StartupTask.ps1

55 lines
3.5 KiB
PowerShell

[CmdletBinding(SupportsShouldProcess)]
param(
[ValidateRange(1,65535)][int]$Port = 15888,
[string]$TaskName = 'AIGame-AIServer',
[switch]$NoStart
)
$ErrorActionPreference = 'Stop'
$serverRoot = $PSScriptRoot
$executable = Join-Path $serverRoot 'aiserver.exe'
if (-not (Test-Path -LiteralPath $executable)) { throw 'Unzip the complete release before installing.' }
# Caddy may use this port on a NIC, but must not occupy wildcard/loopback addresses.
$listeners = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue)
foreach ($listener in $listeners) {
if ($listener.LocalAddress -notin @('0.0.0.0','::','127.0.0.1')) { continue }
$owner = Get-CimInstance Win32_Process -Filter ("ProcessId={0}" -f $listener.OwningProcess)
if ($listener.LocalAddress -eq '127.0.0.1' -and $owner.ExecutablePath -and
[IO.Path]::GetFullPath($owner.ExecutablePath) -eq [IO.Path]::GetFullPath($executable)) { continue }
throw "Port $Port at $($listener.LocalAddress) is occupied by $($owner.Name) (PID $($listener.OwningProcess)). Configure Caddy bind to the NIC IPv4, validate/reload Caddy, then retry."
}
$powershell = Join-Path $env:SystemRoot 'System32/WindowsPowerShell/v1.0/powershell.exe'
$runner = Join-Path $serverRoot 'Run-Server.ps1'
$arguments = '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "{0}" -Port {1}' -f $runner,$Port
$action = New-ScheduledTaskAction -Execute $powershell -Argument $arguments -WorkingDirectory $serverRoot
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId 'S-1-5-19' -LogonType ServiceAccount -RunLevel Limited
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) `
-RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -MultipleInstances IgnoreNew `
-StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
if ($PSCmdlet.ShouldProcess($TaskName, "Register AIServer startup task on loopback port $Port")) {
$data = Join-Path $serverRoot 'data'; $logs = Join-Path $serverRoot 'logs'
New-Item -ItemType Directory -Path $data,$logs -Force | Out-Null
& icacls.exe $serverRoot /grant '*S-1-5-19:(OI)(CI)RX' | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'Cannot grant executable read permission to Local Service.' }
foreach ($directory in @($data,$logs)) {
& icacls.exe $directory /grant '*S-1-5-19:(OI)(CI)M' | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Cannot grant write permission: $directory" }
}
Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger -Principal $principal `
-Settings $settings -Description 'AIGame HTTP, gameplay and WebSocket server' -Force | Out-Null
if ($NoStart) { Write-Output "Installed task $TaskName; not started (-NoStart)."; return }
Start-ScheduledTask -TaskName $TaskName
$healthy = $false
for ($attempt=0; $attempt -lt 25; $attempt++) {
try {
$health = Invoke-RestMethod -Uri "http://127.0.0.1:$Port/health" -TimeoutSec 1
if ($health.ok -and $health.service -eq 'aiserver' -and $health.gameProtocol -eq 1) { $healthy=$true; break }
} catch { }
Start-Sleep -Milliseconds 200
}
if (-not $healthy) {
throw "Task $TaskName was registered but AIServer is not healthy on 127.0.0.1:$Port. Check logs/ and Get-ScheduledTaskInfo -TaskName $TaskName. An HTTP 400 may mean this port is still handled by Caddy HTTPS."
}
Write-Output "AIServer healthy at http://127.0.0.1:$Port/health; startup task $TaskName installed."
}