spotube/windows/uninstaller/Uninstall-Spotube.ps1
Shreyas D R 4b09d2133d feat(windows): add GUI uninstaller script
Adds a Windows-specific uninstaller under windows/uninstaller/ that:
- Shows a Yes/No confirmation dialog via Windows Forms
- Displays a live progress window (no console) during removal
- Removes app files, Start Menu/Desktop/Startup shortcuts,
  AppData configuration, and all registry entries
- Mirrors paths/keys from the Inno Setup installer (inno_setup.iss)
- Includes a Register-SpotubeUninstaller.ps1 helper to surface the
  uninstaller in Control Panel -> Programs and Features
- Provides a .bat wrapper (WindowStyle Hidden) so only GUI dialogs show

Closes: N/A
2026-04-03 00:14:03 +05:30

204 lines
8.2 KiB
PowerShell

<#
.SYNOPSIS
GUI-based uninstaller for Spotube on Windows.
.DESCRIPTION
Removes all Spotube installation artifacts: application files, shortcuts,
user data, and registry entries. Mirrors what the Inno Setup installer
creates (inno_setup.iss / make_config.yaml).
.PARAMETER Silent
Suppresses all GUI dialogs and runs non-interactively.
#>
param (
[switch]$Silent
)
# Application metadata — must match Inno Setup make_config.yaml
$APP_NAME = "Spotube"
$APP_ID = "80B901C8-D6FE-494E-8AF7-A2BD440E8644"
$INNO_REG_KEY = "${APP_ID}_is1"
$CUSTOM_REG_KEY = "SpotubeCustomUninstaller"
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# Displays a standard Windows message box and returns the DialogResult.
function Show-MessageBox {
param(
[string]$Message,
[string]$Title = "Spotube Uninstaller",
[System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::Information
)
return [System.Windows.Forms.MessageBox]::Show($Message, $Title, $Buttons, $Icon)
}
# Creates and displays the progress window. Returns a hashtable of controls
# so the caller can update label text, sub-label, and progress bar value.
function Show-ProgressForm {
$form = New-Object System.Windows.Forms.Form
$form.Text = "Spotube Uninstaller"
$form.Size = New-Object System.Drawing.Size(460, 200)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$form.ControlBox = $false # Disable X button during active uninstall
$form.TopMost = $true
# Use the installed Spotube executable's icon if available
foreach ($candidate in @(
(Join-Path $env:ProgramFiles "Spotube\spotube.exe"),
(Join-Path $env:LOCALAPPDATA "Programs\Spotube\spotube.exe")
)) {
if (Test-Path $candidate) {
try { $form.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($candidate) } catch {}
break
}
}
$lblStatus = New-Object System.Windows.Forms.Label
$lblStatus.Location = New-Object System.Drawing.Point(16, 16)
$lblStatus.Size = New-Object System.Drawing.Size(420, 20)
$lblStatus.Text = "Preparing..."
$lblStatus.Font = New-Object System.Drawing.Font("Segoe UI", 10)
$form.Controls.Add($lblStatus)
$progressBar = New-Object System.Windows.Forms.ProgressBar
$progressBar.Location = New-Object System.Drawing.Point(16, 48)
$progressBar.Size = New-Object System.Drawing.Size(420, 22)
$progressBar.Minimum = 0
$progressBar.Maximum = 100
$progressBar.Value = 0
$form.Controls.Add($progressBar)
$lblDetail = New-Object System.Windows.Forms.Label
$lblDetail.Location = New-Object System.Drawing.Point(16, 80)
$lblDetail.Size = New-Object System.Drawing.Size(420, 16)
$lblDetail.Text = ""
$lblDetail.Font = New-Object System.Drawing.Font("Segoe UI", 8)
$lblDetail.ForeColor = [System.Drawing.Color]::DimGray
$form.Controls.Add($lblDetail)
$form.Show()
$form.Refresh()
return @{
Form = $form
Status = $lblStatus
Detail = $lblDetail
Progress = $progressBar
}
}
# Re-elevate as Administrator if the script is not already running elevated.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)
if (-not $isAdmin) {
$relaunchArgs = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
if ($Silent) { $relaunchArgs += " -Silent" }
Start-Process powershell -ArgumentList $relaunchArgs -Verb RunAs
exit
}
# Prompt the user before making any changes.
if (-not $Silent) {
$confirmMsg = @"
Are you sure you want to uninstall Spotube?
This will permanently remove:
Application files
Desktop, Start Menu, and Startup shortcuts
User configuration and cached data
Windows registry entries
"@
$result = Show-MessageBox -Message $confirmMsg -Title "Uninstall Spotube" `
-Buttons ([System.Windows.Forms.MessageBoxButtons]::YesNo) `
-Icon ([System.Windows.Forms.MessageBoxIcon]::Question)
if ($result -ne [System.Windows.Forms.DialogResult]::Yes) {
Show-MessageBox -Message "Uninstallation was cancelled. No changes were made." `
-Title "Cancelled" -Icon ([System.Windows.Forms.MessageBoxIcon]::Information)
exit
}
}
$ui = Show-ProgressForm
# Updates the progress window with new status text and a percentage value.
function Update-Progress ([string]$status, [string]$detail, [int]$percent) {
$ui.Status.Text = $status
$ui.Detail.Text = $detail
$ui.Progress.Value = [Math]::Min($percent, 100)
$ui.Form.Refresh()
}
# Silently removes a file or directory; no-ops if the path does not exist.
function Safe-Remove ([string]$path) {
if ($path -and (Test-Path $path)) {
try { Remove-Item -Path $path -Recurse -Force -ErrorAction Stop } catch {}
}
}
# Step 1: Terminate any running Spotube processes before touching files.
Update-Progress "Stopping Spotube..." "Terminating running processes" 5
Get-Process -Name "spotube" -ErrorAction SilentlyContinue |
Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Milliseconds 1500
# Step 2: Delete the installation directory.
# Inno Setup installs to {autopf}\Spotube — covers both admin and per-user installs.
Update-Progress "Removing application files..." "Deleting installation directory" 20
@(
(Join-Path $env:ProgramFiles $APP_NAME),
(Join-Path $env:ProgramW6432 $APP_NAME),
(Join-Path $env:LOCALAPPDATA "Programs\$APP_NAME")
) | Select-Object -Unique | ForEach-Object { Safe-Remove $_ }
# Step 3: Remove shortcuts created by the Inno Setup [Icons] section.
# Covers: {autoprograms} (Start Menu), {autodesktop} (Desktop), {userstartup} (Startup).
Update-Progress "Removing shortcuts..." "Cleaning Start Menu, Desktop, and Startup" 40
@(
(Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"),
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"),
(Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME"),
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME"),
(Join-Path ([Environment]::GetFolderPath("CommonDesktopDirectory")) "$APP_NAME.lnk"),
(Join-Path ([Environment]::GetFolderPath("Desktop")) "$APP_NAME.lnk"),
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\$APP_NAME.lnk")
) | ForEach-Object { Safe-Remove $_ }
# Step 4: Remove Flutter application data stored in AppData.
Update-Progress "Removing user data..." "Clearing configuration and cache" 60
@(
(Join-Path $env:APPDATA "com.krtirtho.spotube"),
(Join-Path $env:LOCALAPPDATA "com.krtirtho.spotube"),
(Join-Path $env:APPDATA "spotube"),
(Join-Path $env:LOCALAPPDATA "spotube")
) | ForEach-Object { Safe-Remove $_ }
# Step 5: Remove all Windows registry entries.
# Targets the Inno Setup key ({AppId}_is1) and our custom Control Panel key.
Update-Progress "Removing registry entries..." "Cleaning uninstall records" 80
foreach ($root in @("HKLM:\SOFTWARE", "HKCU:\SOFTWARE", "HKLM:\SOFTWARE\WOW6432Node")) {
foreach ($key in @($INNO_REG_KEY, $CUSTOM_REG_KEY)) {
Safe-Remove "$root\Microsoft\Windows\CurrentVersion\Uninstall\$key"
}
}
Safe-Remove "HKCU:\SOFTWARE\KRTirtho"
Safe-Remove "HKCU:\SOFTWARE\Spotube"
Update-Progress "Complete" "Spotube has been removed." 100
Start-Sleep -Milliseconds 500
$ui.Form.Close()
$ui.Form.Dispose()
# Show the final confirmation dialog with an OK button to dismiss.
if (-not $Silent) {
Show-MessageBox `
-Message "Spotube has been successfully uninstalled.`n`nClick OK to close." `
-Title "Uninstall Complete" `
-Buttons ([System.Windows.Forms.MessageBoxButtons]::OK) `
-Icon ([System.Windows.Forms.MessageBoxIcon]::Information)
}