Files
SITS_RMM_SCRIPTS/3-Uninstall-RustDesk.ps1
uhlwoogiandClaude Opus 4.7 fca02b2435 Uninstall all RustDesk/ScoutIT versions, not just the first match
Previous script used Select-Object -First 1 + break, so side-by-side
installs (hyphen vs space branding, old + new) left entries behind.
Now iterates every matching registry entry, collects every
InstallLocation, and stops every matching service.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 20:28:50 +00:00

155 lines
7.3 KiB
PowerShell

# ScoutIT Remote Support (RustDesk) - Uninstall Script
# Removes ALL installed versions: ScoutIT-RemoteSupport (hyphen), ScoutIT Remote Support
# (spaces), plain RustDesk — side-by-side installs included.
$ErrorActionPreference = 'SilentlyContinue'
# ── Config ────────────────────────────────────────────────────────────────────
# Pattern is case-insensitive via -match. [-\s]? tolerates hyphen OR space OR
# nothing between "ScoutIT", "Remote", and "Support" — covers every branding
# we've shipped.
$namePattern = 'ScoutIT[-\s]?Remote[-\s]?Support|ScoutIT|RustDesk'
$servicePattern = 'ScoutIT[-\s]?Remote[-\s]?Support|RustDesk'
$processPattern = 'ScoutIT[-\s]?Remote[-\s]?Support|scoutit|rustdesk'
$fallbackInstallDirs = @(
'C:\Program Files\ScoutIT-RemoteSupport',
'C:\Program Files (x86)\ScoutIT-RemoteSupport',
'C:\Program Files\ScoutIT Remote Support',
'C:\Program Files (x86)\ScoutIT Remote Support',
'C:\Program Files\RustDesk',
'C:\Program Files (x86)\RustDesk'
)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "Starting ScoutIT Remote Support / RustDesk uninstall (all versions)..."
# ── Stop every matching service ──────────────────────────────────────────────
$services = Get-Service -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match $servicePattern -or $_.DisplayName -match $servicePattern }
if ($services) {
foreach ($s in $services) {
Write-Host "Stopping service: $($s.Name) ($($s.DisplayName))..."
Stop-Service -Name $s.Name -Force -ErrorAction SilentlyContinue
}
Start-Sleep -Seconds 3
} else {
Write-Host "No matching services found."
}
# ── Enumerate every matching registry uninstall entry ────────────────────────
Write-Host "Scanning registry for all matching uninstall entries..."
$uninstallKeys = @(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
$entries = foreach ($key in $uninstallKeys) {
Get-ItemProperty $key -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match $namePattern -or $_.Publisher -match $namePattern }
}
if ($entries) {
Write-Host "Found $($entries.Count) matching entry/entries:"
$entries | ForEach-Object { Write-Host " - $($_.DisplayName) [$($_.PSChildName)]" }
} else {
Write-Host "No matching uninstall entries in registry."
}
# Collect InstallLocation values so we can both run exe --uninstall-service
# and clean the folders after MSI removal.
$installLocations = @()
foreach ($e in $entries) {
if ($e.InstallLocation -and (Test-Path $e.InstallLocation)) {
$installLocations += $e.InstallLocation.TrimEnd('\')
}
}
$installLocations += $fallbackInstallDirs | Where-Object { Test-Path $_ }
$installLocations = $installLocations | Select-Object -Unique
# ── Graceful service unregister via every exe we can find ────────────────────
foreach ($dir in $installLocations) {
Get-ChildItem $dir -Filter '*.exe' -ErrorAction SilentlyContinue | ForEach-Object {
Write-Host "Unregistering service via: $($_.FullName)"
Start-Process -FilePath $_.FullName -ArgumentList '--uninstall-service' -Wait -ErrorAction SilentlyContinue
}
}
if ($installLocations) { Start-Sleep -Seconds 5 }
# ── Uninstall every matching MSI / entry ─────────────────────────────────────
foreach ($e in $entries) {
$name = $e.DisplayName
$code = $e.PSChildName
if ($code -match '^\{') {
Write-Host "Running MSI uninstall for $name [$code]..."
Start-Process -FilePath "msiexec.exe" `
-ArgumentList "/x `"$code`" /qn /norestart" `
-Wait
Start-Sleep -Seconds 10
} elseif ($e.UninstallString) {
Write-Host "Running UninstallString for $name..."
$cmd = $e.UninstallString -replace '"', ''
$exe = ($cmd -split ' ')[0]
$rest = ($cmd -split ' ', 2)[1]
$args = "$rest /S /qn /norestart".Trim()
Start-Process -FilePath $exe -ArgumentList $args -Wait -ErrorAction SilentlyContinue
Start-Sleep -Seconds 10
} else {
Write-Warning "No ProductCode or UninstallString for $name - skipping MSI step."
}
}
# ── Kill any remaining processes ─────────────────────────────────────────────
Write-Host "Killing any remaining processes..."
Get-Process | Where-Object { $_.Path -match $processPattern } |
Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
# ── Remove install directories (registry-reported + fallbacks) ───────────────
foreach ($dir in $installLocations) {
if (Test-Path $dir) {
Write-Host "Removing install directory: $dir"
Remove-Item -Path $dir -Recurse -Force -ErrorAction SilentlyContinue
if (Test-Path $dir) {
Write-Warning "Directory still exists: $dir (locked files - reboot may be required)"
}
}
}
# ── Remove leftover AppData / config ─────────────────────────────────────────
$appDataPaths = @(
"$env:APPDATA\ScoutIT-RemoteSupport",
"$env:APPDATA\ScoutIT Remote Support",
"$env:APPDATA\RustDesk",
"$env:ProgramData\ScoutIT-RemoteSupport",
"$env:ProgramData\ScoutIT Remote Support",
"$env:ProgramData\RustDesk"
)
foreach ($path in $appDataPaths) {
if (Test-Path $path) {
Write-Host "Removing: $path"
Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue
}
}
# ── Confirm ───────────────────────────────────────────────────────────────────
$svcRemaining = Get-Service -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match $servicePattern -or $_.DisplayName -match $servicePattern }
$regRemaining = foreach ($key in $uninstallKeys) {
Get-ItemProperty $key -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match $namePattern -or $_.Publisher -match $namePattern }
}
$dirRemaining = $installLocations | Where-Object { Test-Path $_ }
Write-Output "................................................."
if (-not $svcRemaining -and -not $regRemaining -and -not $dirRemaining) {
Write-Output "ScoutIT Remote Support / RustDesk fully uninstalled (all versions)."
} else {
if ($svcRemaining) { Write-Warning "Services still present: $(($svcRemaining | Select-Object -Expand Name) -join ', ')" }
if ($regRemaining) { Write-Warning "Registry entries still present: $(($regRemaining | Select-Object -Expand DisplayName) -join ', ')" }
if ($dirRemaining) { Write-Warning "Directories still present: $($dirRemaining -join ', ') - reboot may be required." }
}
Write-Output "................................................."
exit 0