Skip to content

Commit 453b203

Browse files
author
Your Name
committed
Add uninstall.ps1 script with file lock handling and update website
1 parent 07596b8 commit 453b203

2 files changed

Lines changed: 292 additions & 1 deletion

File tree

index.html

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1912,7 +1912,23 @@ <h4>
19121912
<path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
19131913
</svg>
19141914
</span>
1915-
Windows (PowerShell)
1915+
Windows (PowerShell) - Recommended
1916+
</h4>
1917+
<p>Download and run the uninstall script (handles file locks automatically)</p>
1918+
<div class="command">
1919+
iwr -useb https://persistence-ai.github.io/Landing/uninstall.ps1 | iex
1920+
<button class="command-copy" onclick="copyToClipboard('iwr -useb https://persistence-ai.github.io/Landing/uninstall.ps1 | iex', this, 'windows')">Copy</button>
1921+
</div>
1922+
</div>
1923+
1924+
<div class="install-method" style="margin-top: 1rem;">
1925+
<h4>
1926+
<span class="icon">
1927+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
1928+
<path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
1929+
</svg>
1930+
</span>
1931+
Windows (PowerShell) - Manual
19161932
</h4>
19171933
<p>Completely remove PersistenceAI including binaries, cache, and config files</p>
19181934
<div class="command">

uninstall.ps1

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# PersistenceAI Uninstaller (PowerShell)
2+
# This script can be downloaded and executed via:
3+
# iwr -useb https://persistence-ai.github.io/Landing/uninstall.ps1 | iex
4+
# curl -fsSL https://persistence-ai.github.io/Landing/uninstall.ps1 | powershell -ExecutionPolicy Bypass -Command -
5+
6+
$ErrorActionPreference = "Continue"
7+
8+
# ============================================================================
9+
# Output Functions (Matching install.ps1 style)
10+
# ============================================================================
11+
12+
function Write-Info {
13+
param([string]$msg)
14+
Write-Host " " -NoNewline
15+
Write-Host "[i]" -ForegroundColor Cyan -NoNewline
16+
Write-Host " $msg" -ForegroundColor Gray
17+
}
18+
19+
function Write-Success {
20+
param([string]$msg)
21+
Write-Host " " -NoNewline
22+
Write-Host "[+]" -ForegroundColor Green -NoNewline
23+
Write-Host " $msg" -ForegroundColor Gray
24+
}
25+
26+
function Write-Error {
27+
param([string]$msg)
28+
Write-Host " " -NoNewline
29+
Write-Host "[x]" -ForegroundColor Red -NoNewline
30+
Write-Host " $msg" -ForegroundColor Gray
31+
}
32+
33+
function Write-Warning {
34+
param([string]$msg)
35+
Write-Host " " -NoNewline
36+
Write-Host "[!]" -ForegroundColor Yellow -NoNewline
37+
Write-Host " $msg" -ForegroundColor Gray
38+
}
39+
40+
function Write-Step {
41+
param([string]$msg)
42+
Write-Host " " -NoNewline
43+
Write-Host "[>]" -ForegroundColor Cyan -NoNewline
44+
Write-Host " $msg" -ForegroundColor White
45+
}
46+
47+
# ============================================================================
48+
# Banner
49+
# ============================================================================
50+
51+
Write-Host ""
52+
Write-Host " " -NoNewline; Write-Host "========================================" -ForegroundColor Magenta
53+
Write-Host " " -NoNewline; Write-Host "|" -ForegroundColor Magenta -NoNewline
54+
Write-Host " " -NoNewline; Write-Host "PersistenceAI" -ForegroundColor Magenta -NoNewline; Write-Host " Uninstaller" -ForegroundColor White -NoNewline; Write-Host " " -NoNewline; Write-Host "|" -ForegroundColor Magenta
55+
Write-Host " " -NoNewline; Write-Host "========================================" -ForegroundColor Magenta
56+
Write-Host ""
57+
58+
# ============================================================================
59+
# Windows API for MoveFileEx (Delete on Reboot)
60+
# ============================================================================
61+
62+
Add-Type -TypeDefinition @"
63+
using System;
64+
using System.Runtime.InteropServices;
65+
public class Win32 {
66+
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
67+
public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);
68+
public const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x4;
69+
}
70+
"@
71+
72+
function Register-ForDeletionOnReboot {
73+
param([string]$FilePath)
74+
try {
75+
if (Test-Path $FilePath) {
76+
$result = [Win32]::MoveFileEx($FilePath, $null, [Win32]::MOVEFILE_DELAY_UNTIL_REBOOT)
77+
if ($result) {
78+
Write-Info "Marked for deletion on reboot: $FilePath"
79+
return $true
80+
}
81+
}
82+
} catch {
83+
# Silently fail - not critical
84+
}
85+
return $false
86+
}
87+
88+
# ============================================================================
89+
# Process Termination (Aggressive - handles file locks)
90+
# ============================================================================
91+
92+
function Stop-PersistenceAIProcesses {
93+
Write-Step "Terminating PersistenceAI processes..."
94+
95+
# Find processes by name
96+
$processes = Get-Process | Where-Object {
97+
($_.ProcessName -eq "pai") -or
98+
($_.ProcessName -eq "persistenceai") -or
99+
($_.ProcessName -like "*persistenceai*")
100+
} -ErrorAction SilentlyContinue
101+
102+
if ($processes) {
103+
Write-Info "Found $($processes.Count) process(es) to terminate"
104+
foreach ($proc in $processes) {
105+
try {
106+
Write-Info "Terminating process: $($proc.ProcessName) (PID: $($proc.Id))"
107+
# Use taskkill with /T to kill process tree (child processes)
108+
$result = Start-Process -FilePath "taskkill" -ArgumentList "/F", "/T", "/PID", $proc.Id -Wait -NoNewWindow -PassThru -ErrorAction SilentlyContinue
109+
if ($result -and $result.ExitCode -eq 0) {
110+
Write-Success "Terminated process tree: $($proc.ProcessName)"
111+
} else {
112+
# Fallback to Stop-Process
113+
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
114+
}
115+
} catch {
116+
Write-Warning "Error terminating process: $_"
117+
}
118+
}
119+
} else {
120+
Write-Info "No PersistenceAI processes found"
121+
}
122+
123+
# Wait for processes to fully terminate
124+
Start-Sleep -Seconds 3
125+
}
126+
127+
# ============================================================================
128+
# File/Directory Removal with Retry and Reboot Marking
129+
# ============================================================================
130+
131+
function Remove-ItemWithRetry {
132+
param(
133+
[string]$Path,
134+
[int]$MaxRetries = 3,
135+
[int]$DelaySeconds = 2
136+
)
137+
138+
if (-not (Test-Path $Path)) {
139+
return $true
140+
}
141+
142+
for ($i = 1; $i -le $MaxRetries; $i++) {
143+
try {
144+
if (Test-Path $Path -PathType Container) {
145+
Remove-Item -Path $Path -Recurse -Force -ErrorAction Stop
146+
} else {
147+
Remove-Item -Path $Path -Force -ErrorAction Stop
148+
}
149+
Write-Success "Removed: $Path"
150+
return $true
151+
} catch {
152+
if ($i -lt $MaxRetries) {
153+
Write-Warning "Attempt $i failed, retrying in $DelaySeconds seconds..."
154+
Start-Sleep -Seconds $DelaySeconds
155+
} else {
156+
Write-Warning "Failed to remove after $MaxRetries attempts: $Path"
157+
Write-Info "Marking for deletion on reboot..."
158+
if (Test-Path $Path -PathType Container) {
159+
# For directories, mark all files inside
160+
Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
161+
Register-ForDeletionOnReboot $_.FullName
162+
}
163+
Register-ForDeletionOnReboot $Path
164+
} else {
165+
Register-ForDeletionOnReboot $Path
166+
}
167+
return $false
168+
}
169+
}
170+
}
171+
return $false
172+
}
173+
174+
# ============================================================================
175+
# Main Uninstall Logic
176+
# ============================================================================
177+
178+
Write-Step "Starting uninstall of PersistenceAI..."
179+
180+
# Step 1: Stop all processes (aggressive termination)
181+
Stop-PersistenceAIProcesses
182+
183+
# Step 2: Find all installation directories
184+
Write-Step "Locating installation directories..."
185+
186+
$dirsToRemove = @(
187+
"$env:USERPROFILE\.persistenceai",
188+
"$env:USERPROFILE\.pai",
189+
"$env:USERPROFILE\.config\persistenceai",
190+
"$env:USERPROFILE\.config\pai",
191+
"$env:LOCALAPPDATA\persistenceai",
192+
"$env:LOCALAPPDATA\pai"
193+
)
194+
195+
# Also find installation directories from PATH
196+
$paiCmd = Get-Command -Name "pai" -ErrorAction SilentlyContinue
197+
$persistenceaiCmd = Get-Command -Name "persistenceai" -ErrorAction SilentlyContinue
198+
199+
if ($paiCmd) {
200+
$binDir = Split-Path $paiCmd.Source -Parent
201+
$installDir = Split-Path $binDir -Parent
202+
if ($installDir -and $installDir -notin $dirsToRemove) {
203+
$dirsToRemove += $installDir
204+
}
205+
# Also add the bin directory itself
206+
if ($binDir -and $binDir -notin $dirsToRemove) {
207+
$dirsToRemove += $binDir
208+
}
209+
}
210+
211+
if ($persistenceaiCmd) {
212+
$binDir = Split-Path $persistenceaiCmd.Source -Parent
213+
$installDir = Split-Path $binDir -Parent
214+
if ($installDir -and $installDir -notin $dirsToRemove) {
215+
$dirsToRemove += $installDir
216+
}
217+
# Also add the bin directory itself
218+
if ($binDir -and $binDir -notin $dirsToRemove) {
219+
$dirsToRemove += $binDir
220+
}
221+
}
222+
223+
# Remove duplicates
224+
$dirsToRemove = $dirsToRemove | Select-Object -Unique
225+
226+
# Step 3: Remove directories with retry logic
227+
Write-Step "Removing installation directories..."
228+
229+
$removedCount = 0
230+
$markedForReboot = 0
231+
232+
foreach ($dir in $dirsToRemove) {
233+
if (Test-Path $dir) {
234+
Write-Info "Removing: $dir"
235+
if (Remove-ItemWithRetry -Path $dir) {
236+
$removedCount++
237+
} else {
238+
$markedForReboot++
239+
}
240+
}
241+
}
242+
243+
# Step 4: Clean PATH
244+
Write-Step "Cleaning PATH environment variable..."
245+
246+
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
247+
if ($userPath) {
248+
$newUserPath = ($userPath -split ";" | Where-Object {
249+
$_ -and $_ -notmatch "\.persistenceai" -and $_ -notmatch "\.pai"
250+
}) -join ";"
251+
[Environment]::SetEnvironmentVariable("Path", $newUserPath, "User")
252+
Write-Success "Cleaned user PATH"
253+
}
254+
255+
# Update current session PATH
256+
$env:Path = ($env:Path -split ";" | Where-Object {
257+
$_ -and $_ -notmatch "\.persistenceai" -and $_ -notmatch "\.pai"
258+
}) -join ";"
259+
260+
# Step 5: Summary
261+
Write-Host ""
262+
Write-Host " " -NoNewline; Write-Host "================================" -ForegroundColor DarkGray
263+
if ($markedForReboot -gt 0) {
264+
Write-Warning "Some files could not be removed and were marked for deletion on reboot"
265+
Write-Info "Please restart your computer to complete the uninstallation"
266+
Write-Info "Removed $removedCount directory/directories"
267+
Write-Info "$markedForReboot item(s) marked for deletion on reboot"
268+
} else {
269+
Write-Success "PersistenceAI uninstalled successfully"
270+
Write-Info "Removed $removedCount directory/directories"
271+
}
272+
Write-Host " " -NoNewline; Write-Host "================================" -ForegroundColor DarkGray
273+
Write-Host ""
274+
Write-Host " " -NoNewline; Write-Host "Note:" -ForegroundColor Yellow -NoNewline; Write-Host " Restart PowerShell for PATH changes to take effect" -ForegroundColor Gray
275+
Write-Host ""

0 commit comments

Comments
 (0)