# ============================================================================ # EasyBot Windows Agent — One-Line Installer # ============================================================================ # # Usage: # powershell -ExecutionPolicy Bypass -c "irm https://raw.githubusercontent.com/pyptechnologies/easybot-windows-agent/main/install.ps1 | iex" # # Then configure: # $env:EASYBOT_SERVER = "wss://your-server.com/ws/windows-agent" # $env:EASYBOT_TOKEN = "eb_wag_..." # easybot-windows-agent # # ============================================================================ $ErrorActionPreference = "Stop" $InstallDir = "$env:ProgramData\EasyBot\WindowsAgent" $ServiceName = "EasyBotWindowsAgent" $PythonMinVersion = [version]"3.11.0" Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " EasyBot Windows Agent Installer v1.0" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" # ── Check admin ────────────────────────────────────────────────────────────── $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host "[!] This installer requires administrator privileges." -ForegroundColor Yellow Write-Host " Please run PowerShell as Administrator and try again." -ForegroundColor Yellow exit 1 } # ── Check Python ───────────────────────────────────────────────────────────── Write-Host "[1/5] Checking Python..." -ForegroundColor White $pythonCmd = $null foreach ($cmd in @("python", "python3", "py -3")) { try { $ver = & $cmd.Split()[0] $cmd.Split()[1..99] --version 2>&1 if ($ver -match "Python (\d+\.\d+\.\d+)") { $pyVer = [version]$Matches[1] if ($pyVer -ge $PythonMinVersion) { $pythonCmd = $cmd Write-Host " Found Python $pyVer" -ForegroundColor Green break } } } catch {} } if (-not $pythonCmd) { Write-Host " Python >= 3.11 not found. Installing via winget..." -ForegroundColor Yellow try { winget install Python.Python.3.12 --accept-source-agreements --accept-package-agreements --silent # Refresh PATH $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") $pythonCmd = "python" Write-Host " Python installed successfully" -ForegroundColor Green } catch { Write-Host "[X] Failed to install Python. Please install Python 3.11+ manually." -ForegroundColor Red Write-Host " https://www.python.org/downloads/" -ForegroundColor Gray exit 1 } } # ── Create install directory ───────────────────────────────────────────────── Write-Host "[2/5] Creating install directory..." -ForegroundColor White New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null Write-Host " $InstallDir" -ForegroundColor Gray # ── Install Python package from Gitea ──────────────────────────────────────── Write-Host "[3/5] Installing easybot-windows-agent from repository..." -ForegroundColor White $repoZip = "$env:TEMP\easybot-windows-agent.zip" $repoExtract = "$env:TEMP\easybot-windows-agent" $repoUrl = "https://repo.pyp.ar/public-pull/easybot-windows-agent/archive/main.zip" # Download and extract if (Test-Path $repoExtract) { Remove-Item $repoExtract -Recurse -Force } Write-Host " Downloading from repository..." -ForegroundColor Gray Invoke-WebRequest -Uri $repoUrl -OutFile $repoZip -UseBasicParsing Expand-Archive -Path $repoZip -DestinationPath $repoExtract -Force # Find the extracted folder (Gitea names it easybot-windows-agent/) $pkgDir = Get-ChildItem -Path $repoExtract -Directory | Select-Object -First 1 # Temporarily allow errors (pip writes warnings to stderr which PowerShell treats as errors) $ErrorActionPreference = "Continue" # pip install from local directory Write-Host " Installing package..." -ForegroundColor Gray & $pythonCmd.Split()[0] $pythonCmd.Split()[1..99] -m pip install --force-reinstall --no-deps $pkgDir.FullName 2>&1 | ForEach-Object { if ($_ -match "Successfully installed") { Write-Host " $_" -ForegroundColor Green } } # Install dependencies Write-Host " Installing dependencies..." -ForegroundColor Gray & $pythonCmd.Split()[0] $pythonCmd.Split()[1..99] -m pip install "websockets>=12.0,<14" "uiautomation>=2.0" "pyautogui>=0.9" "pywinauto>=0.6" "Pillow>=10.0" 2>&1 | Out-Null $ErrorActionPreference = "Stop" # Cleanup Remove-Item $repoZip -Force -ErrorAction SilentlyContinue Remove-Item $repoExtract -Recurse -Force -ErrorAction SilentlyContinue Write-Host " Package installed successfully" -ForegroundColor Green # ── Configure environment ──────────────────────────────────────────────────── Write-Host "[4/5] Configuration..." -ForegroundColor White $configFile = "$InstallDir\config.env" if (Test-Path $configFile) { Write-Host " Existing config found at $configFile" -ForegroundColor Gray } else { # Use env vars if already set, otherwise prompt $server = if ($env:EASYBOT_SERVER) { $env:EASYBOT_SERVER } else { Read-Host " Enter EasyBot server URL (e.g., wss://app.example.com/ws/windows-agent)" } $token = if ($env:EASYBOT_TOKEN) { $env:EASYBOT_TOKEN } else { Read-Host " Enter authentication token (eb_wag_...)" } Write-Host " Server: $server" -ForegroundColor Gray Write-Host " Token: $($token.Substring(0, [Math]::Min(12, $token.Length)))..." -ForegroundColor Gray @" EASYBOT_SERVER=$server EASYBOT_TOKEN=$token LOG_LEVEL=INFO "@ | Set-Content -Path $configFile -Encoding UTF8 Write-Host " Config saved to $configFile" -ForegroundColor Green } # ── Install as Windows Service via nssm ────────────────────────────────────── Write-Host "[5/5] Installing as Windows Service..." -ForegroundColor White # Download nssm if not present $nssmPath = "$InstallDir\nssm.exe" if (-not (Test-Path $nssmPath)) { Write-Host " Downloading nssm..." -ForegroundColor Gray $nssmUrl = "https://repo.pyp.ar/public-pull/easybot-windows-agent/raw/branch/main/bin/nssm.exe" Invoke-WebRequest -Uri $nssmUrl -OutFile $nssmPath -UseBasicParsing } # Find the easybot-windows-agent script $agentScript = & $pythonCmd.Split()[0] $pythonCmd.Split()[1..99] -c "import shutil; print(shutil.which('easybot-windows-agent') or '')" 2>$null if (-not $agentScript) { # Fallback: use python -m $agentScript = "" } # Remove existing service if present (ignore errors if not installed) $ErrorActionPreference = "Continue" & $nssmPath stop $ServiceName 2>&1 | Out-Null & $nssmPath remove $ServiceName confirm 2>&1 | Out-Null $ErrorActionPreference = "Stop" # Parse config.env for environment variables $envVars = @() Get-Content $configFile | ForEach-Object { if ($_ -match "^([^#=]+)=(.*)$") { $envVars += "$($Matches[1])=$($Matches[2])" } } if ($agentScript) { & $nssmPath install $ServiceName $agentScript } else { $pythonExe = & $pythonCmd.Split()[0] $pythonCmd.Split()[1..99] -c "import sys; print(sys.executable)" & $nssmPath install $ServiceName $pythonExe "-m" "easybot_windows_agent.main" } & $nssmPath set $ServiceName DisplayName "EasyBot Windows Agent" & $nssmPath set $ServiceName Description "Remote Windows GUI automation agent for EasyBot" & $nssmPath set $ServiceName AppDirectory $InstallDir & $nssmPath set $ServiceName AppEnvironmentExtra ($envVars -join "`n") & $nssmPath set $ServiceName AppStdout "$InstallDir\agent.log" & $nssmPath set $ServiceName AppStderr "$InstallDir\agent.log" & $nssmPath set $ServiceName AppRotateFiles 1 & $nssmPath set $ServiceName AppRotateBytes 10485760 & $nssmPath set $ServiceName Start SERVICE_AUTO_START & $nssmPath set $ServiceName Type SERVICE_INTERACTIVE_PROCESS & $nssmPath set $ServiceName ObjectName "LocalSystem" & $nssmPath set $ServiceName AppExit Default Restart & $nssmPath set $ServiceName AppRestartDelay 5000 Write-Host " Service installed: $ServiceName" -ForegroundColor Green # Start the service & $nssmPath start $ServiceName | Out-Null Write-Host " Service started!" -ForegroundColor Green Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Installation Complete!" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host " Install dir: $InstallDir" -ForegroundColor Gray Write-Host " Config file: $configFile" -ForegroundColor Gray Write-Host " Log file: $InstallDir\agent.log" -ForegroundColor Gray Write-Host " Service: $ServiceName" -ForegroundColor Gray Write-Host "" Write-Host " Commands:" -ForegroundColor White Write-Host " nssm status $ServiceName # Check status" -ForegroundColor Gray Write-Host " nssm restart $ServiceName # Restart agent" -ForegroundColor Gray Write-Host " nssm stop $ServiceName # Stop agent" -ForegroundColor Gray Write-Host " nssm remove $ServiceName # Uninstall" -ForegroundColor Gray Write-Host ""