# AI Stack Windows service uninstaller # Run in elevated PowerShell: # powershell -NoProfile -ExecutionPolicy Bypass -File .\uninstall.ps1 param( [switch]$RemoveVenv, [switch]$RemoveData ) $ErrorActionPreference = "Stop" $BASE_DIR = $PSScriptRoot $LITELLM_XML = Join-Path $BASE_DIR "litellm\litellm-service.xml" $WEBUI_XML = Join-Path $BASE_DIR "open_webui\openwebui-service.xml" $LITELLM_VENV = Join-Path $BASE_DIR "litellm\venv" $WEBUI_VENV = Join-Path $BASE_DIR "open_webui\venv" $DATA_DIR = Join-Path $BASE_DIR ".data\open-webui" function Fail { param([string]$Message) Write-Host "[ERROR] $Message" -ForegroundColor Red throw $Message } function Step { param([string]$Message) Write-Host "[STEP] $Message" -ForegroundColor Cyan } function Diag { param([string]$Message) Write-Host "[DIAG] $Message" -ForegroundColor DarkGray } function Check-Admin { $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal($identity) if (-not $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { Fail "Please run PowerShell as Administrator." } } function Invoke-External { param( [Parameter(Mandatory = $true)] [string]$File, [string[]]$Arguments = @(), [Parameter(Mandatory = $true)] [string]$ActionLabel ) $display = if ($Arguments.Count -gt 0) { " " + ($Arguments -join " ") } else { "" } Step "$ActionLabel -> $File$display" try { & $File @Arguments if ($LASTEXITCODE -ne $null -and $LASTEXITCODE -ne 0) { Fail "$ActionLabel failed, exit code: $LASTEXITCODE" } } catch { Write-Host "[ERROR] file: $File" -ForegroundColor Red Write-Host "[ERROR] args: $($Arguments -join ' ')" -ForegroundColor Red Write-Host "[ERROR] detail: $($_.Exception.Message)" -ForegroundColor Red throw } } function Uninstall-All { Write-Host "" Write-Host "=== Uninstall AI Stack Windows Services ===" -ForegroundColor Yellow Write-Host "" Check-Admin $litellmWinSW = Join-Path $BASE_DIR "litellm\WinSW.exe" $webuiWinSW = Join-Path $BASE_DIR "open_webui\WinSW.exe" # Stop services in reverse order (Open WebUI depends on LiteLLM) Step "Stop Open WebUI service" $webuiSvc = Get-Service -Name "ai-stack-openwebui" -ErrorAction SilentlyContinue if ($webuiSvc -and $webuiSvc.Status -eq "Running") { Stop-Service ai-stack-openwebui -Force Start-Sleep -Seconds 2 } Step "Stop LiteLLM service" $litellmSvc = Get-Service -Name "ai-stack-litellm" -ErrorAction SilentlyContinue if ($litellmSvc -and $litellmSvc.Status -eq "Running") { Stop-Service ai-stack-litellm -Force Start-Sleep -Seconds 2 } # Uninstall services if (Test-Path $webuiWinSW) { Invoke-External -File $webuiWinSW -Arguments @("uninstall", $WEBUI_XML) -ActionLabel "Uninstall Open WebUI service" Start-Sleep -Seconds 1 } if (Test-Path $litellmWinSW) { Invoke-External -File $litellmWinSW -Arguments @("uninstall", $LITELLM_XML) -ActionLabel "Uninstall LiteLLM service" Start-Sleep -Seconds 1 } # Optional: remove venv if ($RemoveVenv) { Step "Remove virtual environments" if (Test-Path $LITELLM_VENV) { Remove-Item $LITELLM_VENV -Recurse -Force Diag "Removed: $LITELLM_VENV" } if (Test-Path $WEBUI_VENV) { Remove-Item $WEBUI_VENV -Recurse -Force Diag "Removed: $WEBUI_VENV" } } else { Diag "Keeping virtual environments by default (use -RemoveVenv to delete them)" } # Optional: remove data if ($RemoveData) { Step "Remove Open WebUI data" if (Test-Path $DATA_DIR) { Remove-Item $DATA_DIR -Recurse -Force Diag "Removed: $DATA_DIR" } } else { Diag "Keeping Open WebUI data by default (use -RemoveData to delete it)" } # Remove WinSW copies from service folders Step "Clean up WinSW from service folders" Remove-Item $litellmWinSW -Force -ErrorAction SilentlyContinue Remove-Item $webuiWinSW -Force -ErrorAction SilentlyContinue Write-Host "" Write-Host "[OK] Uninstall completed" -ForegroundColor Green Write-Host "" Write-Host "Usage for next install:" -ForegroundColor Cyan Write-Host " powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1" Write-Host "" Write-Host "To remove venv/data too:" -ForegroundColor Cyan Write-Host " powershell -NoProfile -ExecutionPolicy Bypass -File .\uninstall.ps1 -RemoveVenv -RemoveData" Write-Host "" } try { Uninstall-All } catch { Write-Host "" Write-Host "Uninstall failed" -ForegroundColor Red Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red throw }