# JARVIS Agent Installer — Windows (PowerShell) # Registers the agent as a proper Windows Service (Win 8.1+, no open window required). # Requires pywin32. Runs the service as LocalSystem. # # Run as Administrator: # Set-ExecutionPolicy Bypass -Scope Process # .\install-windows.ps1 -JarvisUrl https://jarvis.orbishosting.com -Key YOUR_KEY # # One-liner (PowerShell as Admin): # irm https://jarvis.orbishosting.com/agent/install-windows.ps1 | iex param( [string]$JarvisUrl = "", [string]$Key = "", [string]$AgentName = "" ) # param() defaults don't apply when piped through iex — set here as fallback if (-not $JarvisUrl) { $JarvisUrl = "https://jarvis.orbishosting.com" } if (-not $Key) { $Key = "f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518" } if (-not $AgentName) { $AgentName = $env:COMPUTERNAME.ToLower() } $ErrorActionPreference = "Stop" $InstallDir = "C:\ProgramData\jarvis-agent" $AgentScript = "$InstallDir\jarvis-agent-windows.py" $ConfigFile = "$InstallDir\config.json" $ServiceName = "JARVISAgent" $OldTaskName = "JARVIS-Agent" # legacy scheduled-task name Write-Host "" Write-Host " ====================================" -ForegroundColor Cyan Write-Host " JARVIS Agent Installer v3.1 " -ForegroundColor Cyan Write-Host " Windows Service Edition " -ForegroundColor Cyan Write-Host " ====================================" -ForegroundColor Cyan Write-Host "" # ── Require admin ────────────────────────────────────────────────────────────── if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Error "Run PowerShell as Administrator and try again." } # ── Prompt if not provided ───────────────────────────────────────────────────── $JarvisUrl = $JarvisUrl.TrimEnd("/") # ── Find or install Python 3 (system-wide so LocalSystem service can reach it) ─ Write-Host "[1/6] Checking for Python 3..." -ForegroundColor Cyan $pythonPath = $null # System-wide paths — accessible by LocalSystem service account $systemPaths = @( "C:\Program Files\Python313\python.exe", "C:\Program Files\Python312\python.exe", "C:\Program Files\Python311\python.exe", "C:\Program Files\Python310\python.exe", "C:\Program Files\Python39\python.exe", "C:\Python313\python.exe", "C:\Python312\python.exe", "C:\Python311\python.exe", "C:\Python310\python.exe" ) function Install-PythonSystemWide { # Try winget first (Win 10 1709+ / Win 11) $wingetOk = $false try { $null = Get-Command winget -ErrorAction Stop Write-Host " Using winget (system-wide)..." -NoNewline winget install Python.Python.3.12 --silent --scope machine ` --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null if ($LASTEXITCODE -eq 0) { $wingetOk = $true; Write-Host " done." -ForegroundColor Green } } catch {} if (-not $wingetOk) { # Direct download — works on Win 8.1 without winget # Python 3.11 explicitly supports Win 8.1+ Write-Host " Downloading Python 3.11 (Win 8.1+ compatible)..." -NoNewline $pyInstaller = "$env:TEMP\python-installer.exe" $pyUrl = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe" try { [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 $wc = New-Object System.Net.WebClient $wc.DownloadFile($pyUrl, $pyInstaller) Write-Host " downloaded." -ForegroundColor Green } catch { Write-Error "Could not download Python. Install from https://python.org choosing 'Install for all users', then re-run." } Write-Host " Installing system-wide (silent)..." -NoNewline $proc = Start-Process -FilePath $pyInstaller ` -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0" ` -Wait -PassThru if ($proc.ExitCode -ne 0) { Write-Error "Python installer exited $($proc.ExitCode). Install manually from https://python.org then re-run." } Write-Host " done." -ForegroundColor Green Remove-Item $pyInstaller -ErrorAction SilentlyContinue } # Refresh PATH after install $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH","User") } # ── Search for system-wide Python first ─────────────────────────────────────── foreach ($p in $systemPaths) { if (Test-Path $p) { try { $ver = & $p --version 2>&1 if ("$ver" -match "Python 3") { $pythonPath = $p; break } } catch {} } } # ── Fall back to PATH — but flag if it's per-user ───────────────────────────── if (-not $pythonPath) { foreach ($cmd in @("python", "python3", "py")) { try { $ver = & $cmd --version 2>&1 if ("$ver" -match "Python 3") { $resolved = (Get-Command $cmd -ErrorAction SilentlyContinue) if ($resolved) { $pythonPath = $resolved.Source; break } } } catch {} } } # ── If Python is per-user (AppData), install system-wide so LocalSystem can use it ── $needsSystemPython = $false if ($pythonPath -and ($pythonPath -match "AppData")) { Write-Host " Found per-user Python: $pythonPath" -ForegroundColor Yellow Write-Host " LocalSystem service needs system-wide Python. Installing..." -ForegroundColor Yellow $needsSystemPython = $true } elseif (-not $pythonPath) { Write-Host " Python 3 not found. Installing system-wide..." -ForegroundColor Yellow $needsSystemPython = $true } if ($needsSystemPython) { Install-PythonSystemWide # Locate the newly installed system-wide Python $pythonPath = $null foreach ($p in $systemPaths) { if (Test-Path $p) { try { $ver = & $p --version 2>&1 if ("$ver" -match "Python 3") { $pythonPath = $p; break } } catch {} } } if (-not $pythonPath) { Write-Error "System-wide Python not found after install. Open a new Admin PowerShell and re-run." } } Write-Host " Python: $pythonPath" -ForegroundColor Green # ── Install pywin32 (required for Windows service support) ──────────────────── Write-Host "[2/6] Installing pywin32..." -ForegroundColor Cyan # pip install $pipResult = & $pythonPath -m pip install --upgrade pywin32 2>&1 if ($LASTEXITCODE -ne 0) { Write-Error "pip install pywin32 failed (exit $LASTEXITCODE).`n$pipResult`nTry manually: $pythonPath -m pip install pywin32" } # postinstall registers service runner DLLs — non-fatal if it fails try { $postResult = & $pythonPath -c "import pywin32_postinstall; pywin32_postinstall.install()" 2>&1 Write-Host " pywin32 installed." -ForegroundColor Green } catch { Write-Host " pywin32 installed (postinstall skipped — service should still work)." -ForegroundColor Yellow } # ── Create install directory and download agent ──────────────────────────────── Write-Host "[3/6] Downloading agent..." -ForegroundColor Cyan New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null try { [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } $wc = New-Object System.Net.WebClient $wc.Headers.Add("User-Agent", "JARVIS-Installer/3.1") $wc.DownloadFile("$JarvisUrl/agent/jarvis-agent-windows.py", $AgentScript) Write-Host " Downloaded to $AgentScript" -ForegroundColor Green } catch { Write-Error "Download failed: $_" } # ── Write config ─────────────────────────────────────────────────────────────── Write-Host "[4/6] Writing config..." -ForegroundColor Cyan $agentId = "${AgentName}_windows" $config = [ordered]@{ jarvis_url = $JarvisUrl host_header = "" ssl_verify = $true registration_key = $Key agent_type = "windows" hostname = $AgentName agent_id = $agentId poll_interval = 30 heartbeat_every = 10 update_check_hours = 24 watch_services = @("WinDefend", "Spooler") } | ConvertTo-Json -Depth 3 [System.IO.File]::WriteAllText($ConfigFile, $config, [System.Text.UTF8Encoding]::new($false)) Write-Host " Config: $ConfigFile" -ForegroundColor Green # ── Remove legacy scheduled task if present ──────────────────────────────────── try { $oldTask = Get-ScheduledTask -TaskName $OldTaskName -ErrorAction SilentlyContinue if ($oldTask) { Stop-ScheduledTask -TaskName $OldTaskName -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName $OldTaskName -Confirm:$false -ErrorAction SilentlyContinue Write-Host " Removed legacy scheduled task '$OldTaskName'." -ForegroundColor Yellow } } catch {} # ── Register Windows service ─────────────────────────────────────────────────── Write-Host "[5/6] Registering Windows service '$ServiceName'..." -ForegroundColor Cyan # Stop + remove any existing service first $existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue if ($existing) { if ($existing.Status -eq "Running") { Write-Host " Stopping existing service..." -NoNewline & $pythonPath $AgentScript stop 2>&1 | Out-Null Start-Sleep -Seconds 3 Write-Host " stopped." -ForegroundColor Yellow } Write-Host " Removing existing service..." -NoNewline & $pythonPath $AgentScript remove 2>&1 | Out-Null Start-Sleep -Seconds 2 Write-Host " removed." -ForegroundColor Yellow } # Install the service (--startup auto = start at boot) & $pythonPath $AgentScript --startup auto install if ($LASTEXITCODE -ne 0) { Write-Error "Service registration failed (exit $LASTEXITCODE). Check that pywin32 postinstall completed." } # Configure failure recovery: restart after 5s, 10s, 30s sc.exe failure $ServiceName reset= 86400 actions= restart/5000/restart/10000/restart/30000 | Out-Null Write-Host " Service registered with auto-restart on failure." -ForegroundColor Green # ── Start the service ────────────────────────────────────────────────────────── Write-Host "[6/6] Starting service..." -ForegroundColor Cyan & $pythonPath $AgentScript start Start-Sleep -Seconds 4 $svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue $status = if ($svc) { $svc.Status } else { "NotFound" } $color = if ($status -eq "Running") { "Green" } else { "Yellow" } Write-Host " Service status: $status" -ForegroundColor $color Write-Host "" Write-Host " ====================================" -ForegroundColor Green Write-Host " Installation complete! " -ForegroundColor Green Write-Host " ====================================" -ForegroundColor Green Write-Host "" Write-Host " Machine : $AgentName ($agentId)" -ForegroundColor White Write-Host " JARVIS : $JarvisUrl" -ForegroundColor White Write-Host " Python : $pythonPath" -ForegroundColor White Write-Host " Logs : $InstallDir\jarvis-agent.log" -ForegroundColor White Write-Host "" Write-Host " Manage the service:" -ForegroundColor Gray Write-Host " Get-Service JARVISAgent" -ForegroundColor Gray Write-Host " Start-Service JARVISAgent" -ForegroundColor Gray Write-Host " Stop-Service JARVISAgent" -ForegroundColor Gray Write-Host " Restart-Service JARVISAgent" -ForegroundColor Gray Write-Host " Get-Content '$InstallDir\jarvis-agent.log' -Tail 30 -Wait" -ForegroundColor Gray Write-Host "" Write-Host " To uninstall:" -ForegroundColor Gray Write-Host " Stop-Service JARVISAgent" -ForegroundColor Gray Write-Host " & '$pythonPath' '$AgentScript' remove" -ForegroundColor Gray Write-Host ""