#!/usr/bin/env pwsh # Pensar Apex Installer for Windows # # Usage (PowerShell 7+): # irm https://pensarai.com/apex.ps1 | iex # # Usage (Windows PowerShell 5.1): # Windows PowerShell 5.1 does not follow HTTP 308 redirects. Use this command: # # & {[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12;$u='https://pensarai.com/apex.ps1';for($i=0;$i -lt 5;$i++){try{iex(irm $u);return}catch{$l=$_.Exception.Response.Headers['Location'];if($l){$u=$l}else{throw}}}} $ErrorActionPreference = 'Stop' # --- Redirect-safe HTTP helpers -------------------------------------------------- # Windows PowerShell 5.1 uses .NET Framework's HttpWebRequest which does not # follow HTTP 308 (Permanent Redirect) responses automatically. These helpers # catch 3xx responses, read the Location header, and retry — following up to # 5 redirects to handle redirect chains. function Invoke-SafeRestMethod { param([string]$Uri) $currentUri = $Uri for ($attempt = 0; $attempt -lt 5; $attempt++) { try { return Invoke-RestMethod -Uri $currentUri } catch { $response = $_.Exception.Response if ($response) { $statusCode = [int]$response.StatusCode if ($statusCode -ge 300 -and $statusCode -lt 400) { $redirectUrl = $response.Headers['Location'] if ($redirectUrl) { if (-not ([Uri]::IsWellFormedUriString($redirectUrl, [System.UriKind]::Absolute))) { $redirectUrl = [Uri]::new([Uri]$currentUri, $redirectUrl).AbsoluteUri } $currentUri = $redirectUrl continue } } } throw } } throw "Too many redirects following $Uri" } function Invoke-SafeWebDownload { param([string]$Uri, [string]$OutFile) $currentUri = $Uri for ($attempt = 0; $attempt -lt 5; $attempt++) { try { Invoke-WebRequest -Uri $currentUri -OutFile $OutFile -UseBasicParsing return } catch { $response = $_.Exception.Response if ($response) { $statusCode = [int]$response.StatusCode if ($statusCode -ge 300 -and $statusCode -lt 400) { $redirectUrl = $response.Headers['Location'] if ($redirectUrl) { if (-not ([Uri]::IsWellFormedUriString($redirectUrl, [System.UriKind]::Absolute))) { $redirectUrl = [Uri]::new([Uri]$currentUri, $redirectUrl).AbsoluteUri } $currentUri = $redirectUrl continue } } } throw } } throw "Too many redirects following $Uri" } # --------------------------------------------------------------------------------- # Configuration $repo = "pensarai/apex" $binaryName = "pensar" $installDir = "$env:LOCALAPPDATA\Pensar" Write-Host "" Write-Host " Pensar Apex Installer" -ForegroundColor Green Write-Host " =====================" -ForegroundColor Green Write-Host "" # Ensure TLS 1.2 (required for GitHub API on older Windows) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Get latest release Write-Host "→ Finding latest release..." -ForegroundColor Cyan try { $release = Invoke-SafeRestMethod -Uri "https://api.github.com/repos/$repo/releases/latest" $version = $release.tag_name Write-Host " Found version: $version" -ForegroundColor Gray } catch { Write-Host "✗ Failed to fetch latest release: $_" -ForegroundColor Red exit 1 } # Find Windows asset $asset = $release.assets | Where-Object { $_.name -like "*windows-x64.zip" } | Select-Object -First 1 if (-not $asset) { Write-Host "✗ No Windows build found for $version" -ForegroundColor Red exit 1 } # Create install directory Write-Host "→ Creating install directory..." -ForegroundColor Cyan if (-not (Test-Path $installDir)) { New-Item -ItemType Directory -Path $installDir -Force | Out-Null } # Download $zipPath = "$env:TEMP\pensar-windows-x64.zip" Write-Host "→ Downloading $($asset.name)..." -ForegroundColor Cyan try { Invoke-SafeWebDownload -Uri $asset.browser_download_url -OutFile $zipPath } catch { Write-Host "✗ Download failed: $_" -ForegroundColor Red exit 1 } # Extract Write-Host "→ Extracting..." -ForegroundColor Cyan try { Expand-Archive -Path $zipPath -DestinationPath $installDir -Force Remove-Item $zipPath -Force } catch { Write-Host "✗ Extraction failed: $_" -ForegroundColor Red exit 1 } # Add to PATH if not already there $userPath = [Environment]::GetEnvironmentVariable("Path", "User") if ($userPath -notlike "*$installDir*") { Write-Host "→ Adding to PATH..." -ForegroundColor Cyan [Environment]::SetEnvironmentVariable("Path", "$userPath;$installDir", "User") $env:Path = "$env:Path;$installDir" } # Verify installation Write-Host "" Write-Host "✓ Pensar installed successfully!" -ForegroundColor Green Write-Host "" Write-Host " ██████╗ ███████╗███╗ ██╗███████╗ █████╗ ██████╗ " -ForegroundColor Green Write-Host " ██╔══██╗██╔════╝████╗ ██║██╔════╝██╔══██╗██╔══██╗" -ForegroundColor Green Write-Host " ██████╔╝█████╗ ██╔██╗ ██║███████╗███████║██████╔╝" -ForegroundColor Green Write-Host " ██╔═══╝ ██╔══╝ ██║╚██╗██║╚════██║██╔══██║██╔══██╗" -ForegroundColor Green Write-Host " ██║ ███████╗██║ ╚████║███████║██║ ██║██║ ██║" -ForegroundColor Green Write-Host " ╚═╝ ╚══════╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝" -ForegroundColor Green Write-Host "" Write-Host " AI Pentest Agent" -ForegroundColor Gray Write-Host "" Write-Host " Location: $installDir\$binaryName.exe" -ForegroundColor Gray Write-Host " Version: $version" -ForegroundColor Gray Write-Host "" Write-Host " To get started, run a pentest:" -ForegroundColor White Write-Host "" Write-Host " pensar" -ForegroundColor Cyan Write-Host "" Write-Host " For more information visit " -NoNewline -ForegroundColor Gray Write-Host "https://pensarai.com" -ForegroundColor Cyan Write-Host " Documentation " -NoNewline -ForegroundColor Gray Write-Host "https://docs.pensar.dev/apex" -ForegroundColor Cyan Write-Host " Join our community " -NoNewline -ForegroundColor Gray Write-Host "https://discord.gg/pensar" -ForegroundColor Cyan Write-Host "" Write-Host "→ Open a new terminal to get started" -ForegroundColor Cyan Write-Host ""