Update 8x8-Cleanup-script.ps1

This commit is contained in:
CristianD committed 2026-10-20 14:34:02 +01:00
1 parent 2630572cd9
commit 86ea0a945c
1 file changed
+366 -366
+366 -366
View File
@@ -1,367 +1,367 @@
<# <#
.SYNOPSIS .SYNOPSIS
Detects 8x8 Work installations with version <= 8.36.2.3, silently uninstalls them, Detects 8x8 Work installations with version <= 8.36.2.3, silently uninstalls them,
and cleans up leftover processes, files, temp directories, and registry entries. and cleans up leftover processes, files, temp directories, and registry entries.
.DESCRIPTION .DESCRIPTION
1. Scans Machine (64-bit & 32-bit) and User (HKCU + loaded user hives) Uninstall registry keys for "8x8 Work". 1. Scans Machine (64-bit & 32-bit) and User (HKCU + loaded user hives) Uninstall registry keys for "8x8 Work".
2. Checks if the installed version is less than or equal to 8.36.2.3. 2. Checks if the installed version is less than or equal to 8.36.2.3.
3. Stops running 8x8 Work processes. 3. Stops running 8x8 Work processes.
4. Runs silent uninstallation (MSI /x /qn or EXE silent flags). 4. Runs silent uninstallation (MSI /x /qn or EXE silent flags).
5. Cleans up leftover folders (Program Files, ProgramData, AppData Local/Roaming, Temp) and registry entries. 5. Cleans up leftover folders (Program Files, ProgramData, AppData Local/Roaming, Temp) and registry entries.
.NOTES .NOTES
Run as Administrator for system-wide cleanup, or in user context if only removing per-user installs. Run as Administrator for system-wide cleanup, or in user context if only removing per-user installs.
#> #>
[CmdletBinding(SupportsShouldProcess = $true)] [CmdletBinding(SupportsShouldProcess = $true)]
param ( param (
[version]$MaxTargetVersion = [version]"8.36.2.3", [version]$MaxTargetVersion = [version]"8.36.2.3",
[string]$AppNamePattern = "*8x8 Work*" [string]$AppNamePattern = "*8x8 Work*"
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
function Write-Log { function Write-Log {
param ( param (
[string]$Message, [string]$Message,
[ValidateSet("INFO", "WARN", "ERROR")][string]$Level = "INFO" [ValidateSet("INFO", "WARN", "ERROR")][string]$Level = "INFO"
) )
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Output "[$timestamp] [$Level] $Message" Write-Output "[$timestamp] [$Level] $Message"
} }
function ConvertTo-SafeVersion { function ConvertTo-SafeVersion {
param ([string]$VersionString) param ([string]$VersionString)
if ([string]::IsNullOrWhiteSpace($VersionString)) { return $null } if ([string]::IsNullOrWhiteSpace($VersionString)) { return $null }
# Extract numeric dot-separated version component (e.g. "8.36.2.3-beta" -> "8.36.2.3") # Extract numeric dot-separated version component (e.g. "8.36.2.3-beta" -> "8.36.2.3")
if ($VersionString -match '(\d+(\.\d+){1,3})') { if ($VersionString -match '(\d+(\.\d+){1,3})') {
try { try {
return [version]$Matches[1] return [version]$Matches[1]
} catch { } catch {
return $null return $null
} }
} }
return $null return $null
} }
Write-Log "Starting check for 8x8 Work (Target version <= $MaxTargetVersion)..." Write-Log "Starting check for 8x8 Work (Target version <= $MaxTargetVersion)..."
# 1. Gather Uninstall Registry Paths (System + Current User + Loaded User Hives) # 1. Gather Uninstall Registry Paths (System + Current User + Loaded User Hives)
$UninstallPaths = @( $UninstallPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
) )
# Also check other loaded user hives in HKU when running as SYSTEM/Admin # Also check other loaded user hives in HKU when running as SYSTEM/Admin
Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object { Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object {
$_.PSChildName -match '^S-1-5-21-[\d\-]+$' $_.PSChildName -match '^S-1-5-21-[\d\-]+$'
} | ForEach-Object { } | ForEach-Object {
$UninstallPaths += "Registry::HKEY_USERS\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" $UninstallPaths += "Registry::HKEY_USERS\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
} }
$FoundInstallations = @() $FoundInstallations = @()
foreach ($regPath in $UninstallPaths) { foreach ($regPath in $UninstallPaths) {
if (Test-Path $regPath) { if (Test-Path $regPath) {
$items = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue | Where-Object { $items = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue | Where-Object {
$_.DisplayName -like $AppNamePattern $_.DisplayName -like $AppNamePattern
} }
if ($items) { if ($items) {
$FoundInstallations += $items $FoundInstallations += $items
} }
} }
} }
# Also check per-user Squirrel/Electron executable path in case registry entry is missing/corrupted # Also check per-user Squirrel/Electron executable path in case registry entry is missing/corrupted
$UserProfileList = Get-ChildItem -Path "$env:SystemDrive\Users" -Directory -ErrorAction SilentlyContinue $UserProfileList = Get-ChildItem -Path "$env:SystemDrive\Users" -Directory -ErrorAction SilentlyContinue
foreach ($userDir in $UserProfileList) { foreach ($userDir in $UserProfileList) {
$possibleExePaths = @( $possibleExePaths = @(
Join-Path $userDir.FullName "AppData\Local\8x8-work\8x8 Work.exe" Join-Path $userDir.FullName "AppData\Local\8x8-work\8x8 Work.exe"
Join-Path $userDir.FullName "AppData\Local\Programs\8x8-work\8x8 Work.exe" Join-Path $userDir.FullName "AppData\Local\Programs\8x8-work\8x8 Work.exe"
Join-Path $userDir.FullName "AppData\Local\8x8 Work\8x8 Work.exe" Join-Path $userDir.FullName "AppData\Local\8x8 Work\8x8 Work.exe"
) )
foreach ($exePath in $possibleExePaths) { foreach ($exePath in $possibleExePaths) {
if (Test-Path $exePath) { if (Test-Path $exePath) {
$fileVer = (Get-Item $exePath).VersionInfo.ProductVersion $fileVer = (Get-Item $exePath).VersionInfo.ProductVersion
if (-not ($FoundInstallations | Where-Object { $_.InstallLocation -and ($exePath -like "$($_.InstallLocation)*") })) { if (-not ($FoundInstallations | Where-Object { $_.InstallLocation -and ($exePath -like "$($_.InstallLocation)*") })) {
$FoundInstallations += [PSCustomObject]@{ $FoundInstallations += [PSCustomObject]@{
DisplayName = "8x8 Work (File Detection)" DisplayName = "8x8 Work (File Detection)"
DisplayVersion = $fileVer DisplayVersion = $fileVer
UninstallString = $null UninstallString = $null
QuietUninstallString = $null QuietUninstallString = $null
InstallLocation = Split-Path $exePath -Parent InstallLocation = Split-Path $exePath -Parent
PSPath = $null PSPath = $null
} }
} }
} }
} }
} }
if ($FoundInstallations.Count -eq 0) { if ($FoundInstallations.Count -eq 0) {
Write-Log "8x8 Work was not found on this device. Exiting." Write-Log "8x8 Work was not found on this device. Exiting."
exit 0 exit 0
} }
# Filter installations matching version <= 8.36.2.3 # Filter installations matching version <= 8.36.2.3
$TargetInstalls = @() $TargetInstalls = @()
foreach ($install in $FoundInstallations) { foreach ($install in $FoundInstallations) {
$parsedVer = ConvertTo-SafeVersion -VersionString $install.DisplayVersion $parsedVer = ConvertTo-SafeVersion -VersionString $install.DisplayVersion
Write-Log "Found '$($install.DisplayName)' with version '$($install.DisplayVersion)' (Parsed: $parsedVer)" Write-Log "Found '$($install.DisplayName)' with version '$($install.DisplayVersion)' (Parsed: $parsedVer)"
if ($null -ne $parsedVer -and $parsedVer -le $MaxTargetVersion) { if ($null -ne $parsedVer -and $parsedVer -le $MaxTargetVersion) {
$TargetInstalls += $install $TargetInstalls += $install
} elseif ($null -eq $parsedVer) { } elseif ($null -eq $parsedVer) {
Write-Log "Could not parse version '$($install.DisplayVersion)' for $($install.DisplayName). Skipping version match." -Level "WARN" Write-Log "Could not parse version '$($install.DisplayVersion)' for $($install.DisplayName). Skipping version match." -Level "WARN"
} else { } else {
Write-Log "Installed version ($parsedVer) is newer than $MaxTargetVersion. Skipping uninstall." Write-Log "Installed version ($parsedVer) is newer than $MaxTargetVersion. Skipping uninstall."
} }
} }
if ($TargetInstalls.Count -eq 0) { if ($TargetInstalls.Count -eq 0) {
Write-Log "No 8x8 Work installation <= $MaxTargetVersion found. Nothing to uninstall." Write-Log "No 8x8 Work installation <= $MaxTargetVersion found. Nothing to uninstall."
exit 0 exit 0
} }
# 2. Stop running 8x8 Work processes before uninstalling # 2. Stop running 8x8 Work processes before uninstalling
Write-Log "Stopping any running 8x8 Work processes..." Write-Log "Stopping any running 8x8 Work processes..."
$ProcessNames = @("8x8 Work*", "8x8-work*", "VirtualOffice*") $ProcessNames = @("8x8 Work*", "8x8-work*", "VirtualOffice*")
foreach ($procPattern in $ProcessNames) { foreach ($procPattern in $ProcessNames) {
Get-Process -Name $procPattern -ErrorAction SilentlyContinue | ForEach-Object { Get-Process -Name $procPattern -ErrorAction SilentlyContinue | ForEach-Object {
try { try {
Write-Log "Stopping process: $($_.ProcessName) (PID: $($_.Id))" Write-Log "Stopping process: $($_.ProcessName) (PID: $($_.Id))"
Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue
} catch { } catch {
Write-Log "Failed to stop process $($_.ProcessName): $_" -Level "WARN" Write-Log "Failed to stop process $($_.ProcessName): $_" -Level "WARN"
} }
} }
} }
Start-Sleep -Seconds 2 Start-Sleep -Seconds 2
# 3. Uninstall matching versions silently # 3. Uninstall matching versions silently
foreach ($app in $TargetInstalls) { foreach ($app in $TargetInstalls) {
Write-Log "Uninstalling $($app.DisplayName) (Version: $($app.DisplayVersion))..." Write-Log "Uninstalling $($app.DisplayName) (Version: $($app.DisplayVersion))..."
$uninstallCmd = if ($app.QuietUninstallString) { $app.QuietUninstallString } else { $app.UninstallString } $uninstallCmd = if ($app.QuietUninstallString) { $app.QuietUninstallString } else { $app.UninstallString }
if ($app.PSChildName -match '^\{[0-9A-Fa-f\-]{36}\}$' -or $uninstallCmd -match 'msiexec') { if ($app.PSChildName -match '^\{[0-9A-Fa-f\-]{36}\}$' -or $uninstallCmd -match 'msiexec') {
# MSI-based Uninstall # MSI-based Uninstall
$guid = if ($app.PSChildName -match '^\{[0-9A-Fa-f\-]{36}\}$') { $guid = if ($app.PSChildName -match '^\{[0-9A-Fa-f\-]{36}\}$') {
$app.PSChildName $app.PSChildName
} elseif ($uninstallCmd -match '(\{[0-9A-Fa-f\-]{36}\})') { } elseif ($uninstallCmd -match '(\{[0-9A-Fa-f\-]{36}\})') {
$Matches[1] $Matches[1]
} }
if ($guid) { if ($guid) {
$msiArgs = "/x `"$guid`" /qn /norestart REBOOT=ReallySuppress" $msiArgs = "/x `"$guid`" /qn /norestart REBOOT=ReallySuppress"
Write-Log "Executing MSI uninstall: msiexec.exe $msiArgs" Write-Log "Executing MSI uninstall: msiexec.exe $msiArgs"
$proc = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru -NoNewWindow $proc = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru -NoNewWindow
Write-Log "MSI uninstall finished with exit code: $($proc.ExitCode)" Write-Log "MSI uninstall finished with exit code: $($proc.ExitCode)"
} }
} }
elseif (-not [string]::IsNullOrWhiteSpace($uninstallCmd)) { elseif (-not [string]::IsNullOrWhiteSpace($uninstallCmd)) {
# EXE-based Uninstall (Squirrel / NSIS / InstallShield / Burn) # EXE-based Uninstall (Squirrel / NSIS / InstallShield / Burn)
if ($uninstallCmd -match '^"([^"]+)"\s*(.*)$') { if ($uninstallCmd -match '^"([^"]+)"\s*(.*)$') {
$exePath = $Matches[1] $exePath = $Matches[1]
$existingArgs = $Matches[2] $existingArgs = $Matches[2]
} else { } else {
$parts = $uninstallCmd -split '\s+', 2 $parts = $uninstallCmd -split '\s+', 2
$exePath = $parts[0] $exePath = $parts[0]
$existingArgs = if ($parts.Count -gt 1) { $parts[1] } else { "" } $existingArgs = if ($parts.Count -gt 1) { $parts[1] } else { "" }
} }
if (Test-Path $exePath) { if (Test-Path $exePath) {
# Add appropriate silent flags if not already present # Add appropriate silent flags if not already present
$silentArgs = $existingArgs $silentArgs = $existingArgs
if ($exePath -like "*Update.exe*") { if ($exePath -like "*Update.exe*") {
if ($silentArgs -notmatch '--uninstall') { $silentArgs += " --uninstall" } if ($silentArgs -notmatch '--uninstall') { $silentArgs += " --uninstall" }
if ($silentArgs -notmatch '-s') { $silentArgs += " -s" } if ($silentArgs -notmatch '-s') { $silentArgs += " -s" }
} else { } else {
if ($silentArgs -notmatch '(/S|/silent|/quiet|/qn|--silent)') { if ($silentArgs -notmatch '(/S|/silent|/quiet|/qn|--silent)') {
$silentArgs = "$silentArgs /S /quiet /norestart".Trim() $silentArgs = "$silentArgs /S /quiet /norestart".Trim()
} }
} }
Write-Log "Executing EXE uninstall: `"$exePath`" $silentArgs" Write-Log "Executing EXE uninstall: `"$exePath`" $silentArgs"
$proc = Start-Process -FilePath $exePath -ArgumentList $silentArgs -Wait -PassThru -NoNewWindow $proc = Start-Process -FilePath $exePath -ArgumentList $silentArgs -Wait -PassThru -NoNewWindow
Write-Log "EXE uninstall finished with exit code: $($proc.ExitCode)" Write-Log "EXE uninstall finished with exit code: $($proc.ExitCode)"
} else { } else {
Write-Log "Uninstaller executable not found at: $exePath" -Level "WARN" Write-Log "Uninstaller executable not found at: $exePath" -Level "WARN"
} }
} }
# Remove the Uninstall Registry Key if it still exists # Remove the Uninstall Registry Key if it still exists
if ($app.PSPath -and (Test-Path $app.PSPath)) { if ($app.PSPath -and (Test-Path $app.PSPath)) {
Write-Log "Removing leftover Uninstall registry entry: $($app.PSPath)" Write-Log "Removing leftover Uninstall registry entry: $($app.PSPath)"
Remove-Item -Path $app.PSPath -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $app.PSPath -Recurse -Force -ErrorAction SilentlyContinue
} }
} }
Start-Sleep -Seconds 2 Start-Sleep -Seconds 2
# 4. Clean up File System Leftovers (Program Files, ProgramData, User AppData, Temp, Shortcuts) # 4. Clean up File System Leftovers (Program Files, ProgramData, User AppData, Temp, Shortcuts)
Write-Log "Cleaning up leftover directories, caches, shortcuts, and temporary files..." Write-Log "Cleaning up leftover directories, caches, shortcuts, and temporary files..."
$SystemFoldersToClean = @( $SystemFoldersToClean = @(
"$env:ProgramFiles\8x8\8x8 Work", "$env:ProgramFiles\8x8\8x8 Work",
"$env:ProgramFiles\8x8 Work", "$env:ProgramFiles\8x8 Work",
"${env:ProgramFiles(x86)}\8x8\8x8 Work", "${env:ProgramFiles(x86)}\8x8\8x8 Work",
"${env:ProgramFiles(x86)}\8x8 Work", "${env:ProgramFiles(x86)}\8x8 Work",
"$env:ProgramData\8x8\8x8 Work", "$env:ProgramData\8x8\8x8 Work",
"$env:ProgramData\8x8 Work", "$env:ProgramData\8x8 Work",
"$env:ProgramData\8x8-work", "$env:ProgramData\8x8-work",
"$env:ProgramData\Microsoft\Windows\Start Menu\Programs\8x8 Work*", "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\8x8 Work*",
"$env:PUBLIC\Desktop\8x8 Work*.lnk" "$env:PUBLIC\Desktop\8x8 Work*.lnk"
) )
foreach ($path in $SystemFoldersToClean) { foreach ($path in $SystemFoldersToClean) {
Get-Item -Path $path -Force -ErrorAction SilentlyContinue | ForEach-Object { Get-Item -Path $path -Force -ErrorAction SilentlyContinue | ForEach-Object {
try { try {
Write-Log "Removing system path: $($_.FullName)" Write-Log "Removing system path: $($_.FullName)"
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
} catch { } catch {
Write-Log "Could not remove $($_.FullName): $_" -Level "WARN" Write-Log "Could not remove $($_.FullName): $_" -Level "WARN"
} }
} }
} }
# Clean Windows Temp # Clean Windows Temp
$WinTempPatterns = @( $WinTempPatterns = @(
"$env:SystemRoot\Temp\*8x8*", "$env:SystemRoot\Temp\*8x8*",
"$env:TEMP\*8x8*" "$env:TEMP\*8x8*"
) )
foreach ($pattern in $WinTempPatterns) { foreach ($pattern in $WinTempPatterns) {
Get-Item -Path $pattern -Force -ErrorAction SilentlyContinue | ForEach-Object { Get-Item -Path $pattern -Force -ErrorAction SilentlyContinue | ForEach-Object {
Write-Log "Removing temp item: $($_.FullName)" Write-Log "Removing temp item: $($_.FullName)"
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
} }
} }
# Clean Per-User Leftovers across all user profiles on the machine # Clean Per-User Leftovers across all user profiles on the machine
foreach ($userDir in $UserProfileList) { foreach ($userDir in $UserProfileList) {
$uPath = $userDir.FullName $uPath = $userDir.FullName
$UserItemsToClean = @( $UserItemsToClean = @(
"$uPath\AppData\Local\8x8\8x8 Work", "$uPath\AppData\Local\8x8\8x8 Work",
"$uPath\AppData\Local\8x8 Work", "$uPath\AppData\Local\8x8 Work",
"$uPath\AppData\Local\8x8-work", "$uPath\AppData\Local\8x8-work",
"$uPath\AppData\Local\Programs\8x8-work", "$uPath\AppData\Local\Programs\8x8-work",
"$uPath\AppData\Local\Programs\8x8 Work", "$uPath\AppData\Local\Programs\8x8 Work",
"$uPath\AppData\Local\SquirrelTemp", "$uPath\AppData\Local\SquirrelTemp",
"$uPath\AppData\Roaming\8x8\8x8 Work", "$uPath\AppData\Roaming\8x8\8x8 Work",
"$uPath\AppData\Roaming\8x8 Work", "$uPath\AppData\Roaming\8x8 Work",
"$uPath\AppData\Roaming\8x8-work", "$uPath\AppData\Roaming\8x8-work",
"$uPath\AppData\Local\Temp\*8x8*", "$uPath\AppData\Local\Temp\*8x8*",
"$uPath\Desktop\8x8 Work*.lnk", "$uPath\Desktop\8x8 Work*.lnk",
"$uPath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\8x8 Work*", "$uPath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\8x8 Work*",
"$uPath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\8x8 Inc*" "$uPath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\8x8 Inc*"
) )
foreach ($itemPattern in $UserItemsToClean) { foreach ($itemPattern in $UserItemsToClean) {
Get-Item -Path $itemPattern -Force -ErrorAction SilentlyContinue | ForEach-Object { Get-Item -Path $itemPattern -Force -ErrorAction SilentlyContinue | ForEach-Object {
# Only remove SquirrelTemp if it references 8x8 or is empty # Only remove SquirrelTemp if it references 8x8 or is empty
if ($_.Name -eq "SquirrelTemp") { if ($_.Name -eq "SquirrelTemp") {
$squirrelLog = Join-Path $_.FullName "SquirrelSetup.log" $squirrelLog = Join-Path $_.FullName "SquirrelSetup.log"
if ((Test-Path $squirrelLog) -and (Select-String -Path $squirrelLog -Pattern "8x8" -Quiet -ErrorAction SilentlyContinue)) { if ((Test-Path $squirrelLog) -and (Select-String -Path $squirrelLog -Pattern "8x8" -Quiet -ErrorAction SilentlyContinue)) {
Write-Log "Removing 8x8 SquirrelTemp folder: $($_.FullName)" Write-Log "Removing 8x8 SquirrelTemp folder: $($_.FullName)"
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
} }
} else { } else {
Write-Log "Removing user path: $($_.FullName)" Write-Log "Removing user path: $($_.FullName)"
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
} }
} }
} }
} }
# Remove empty parent "8x8" directories if no other 8x8 software is inside them # Remove empty parent "8x8" directories if no other 8x8 software is inside them
$Parent8x8Dirs = @( $Parent8x8Dirs = @(
"$env:ProgramFiles\8x8", "$env:ProgramFiles\8x8",
"${env:ProgramFiles(x86)}\8x8", "${env:ProgramFiles(x86)}\8x8",
"$env:ProgramData\8x8" "$env:ProgramData\8x8"
) + ($UserProfileList | ForEach-Object { ) + ($UserProfileList | ForEach-Object {
"$($_.FullName)\AppData\Local\8x8" "$($_.FullName)\AppData\Local\8x8"
"$($_.FullName)\AppData\Roaming\8x8" "$($_.FullName)\AppData\Roaming\8x8"
}) })
foreach ($parentDir in $Parent8x8Dirs) { foreach ($parentDir in $Parent8x8Dirs) {
if (Test-Path $parentDir) { if (Test-Path $parentDir) {
$remaining = Get-ChildItem -Path $parentDir -Force -ErrorAction SilentlyContinue $remaining = Get-ChildItem -Path $parentDir -Force -ErrorAction SilentlyContinue
if ($null -eq $remaining -or $remaining.Count -eq 0) { if ($null -eq $remaining -or $remaining.Count -eq 0) {
Write-Log "Removing empty parent folder: $parentDir" Write-Log "Removing empty parent folder: $parentDir"
Remove-Item -Path $parentDir -Force -ErrorAction SilentlyContinue Remove-Item -Path $parentDir -Force -ErrorAction SilentlyContinue
} }
} }
} }
# 5. Clean up Leftover Registry Keys & Startup Entries # 5. Clean up Leftover Registry Keys & Startup Entries
Write-Log "Cleaning up leftover registry keys and startup entries..." Write-Log "Cleaning up leftover registry keys and startup entries..."
$RegistrySoftwarePaths = @( $RegistrySoftwarePaths = @(
"HKLM:\SOFTWARE\8x8\8x8 Work", "HKLM:\SOFTWARE\8x8\8x8 Work",
"HKLM:\SOFTWARE\8x8 Work", "HKLM:\SOFTWARE\8x8 Work",
"HKLM:\SOFTWARE\WOW6432Node\8x8\8x8 Work", "HKLM:\SOFTWARE\WOW6432Node\8x8\8x8 Work",
"HKLM:\SOFTWARE\WOW6432Node\8x8 Work", "HKLM:\SOFTWARE\WOW6432Node\8x8 Work",
"HKCU:\SOFTWARE\8x8\8x8 Work", "HKCU:\SOFTWARE\8x8\8x8 Work",
"HKCU:\SOFTWARE\8x8 Work" "HKCU:\SOFTWARE\8x8 Work"
) )
# Include loaded user hives # Include loaded user hives
Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object { Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object {
$_.PSChildName -match '^S-1-5-21-[\d\-]+$' $_.PSChildName -match '^S-1-5-21-[\d\-]+$'
} | ForEach-Object { } | ForEach-Object {
$sid = $_.PSChildName $sid = $_.PSChildName
$RegistrySoftwarePaths += @( $RegistrySoftwarePaths += @(
"Registry::HKEY_USERS\$sid\Software\8x8\8x8 Work", "Registry::HKEY_USERS\$sid\Software\8x8\8x8 Work",
"Registry::HKEY_USERS\$sid\Software\8x8 Work" "Registry::HKEY_USERS\$sid\Software\8x8 Work"
) )
} }
foreach ($regKey in $RegistrySoftwarePaths) { foreach ($regKey in $RegistrySoftwarePaths) {
if (Test-Path $regKey) { if (Test-Path $regKey) {
Write-Log "Removing registry key: $regKey" Write-Log "Removing registry key: $regKey"
Remove-Item -Path $regKey -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $regKey -Recurse -Force -ErrorAction SilentlyContinue
} }
} }
# Clean Windows Installer Product/Upgrade Codes in HKCR\Installer\Products if orphaned # Clean Windows Installer Product/Upgrade Codes in HKCR\Installer\Products if orphaned
$InstallerProductsPath = "Registry::HKEY_CLASSES_ROOT\Installer\Products" $InstallerProductsPath = "Registry::HKEY_CLASSES_ROOT\Installer\Products"
if (Test-Path $InstallerProductsPath) { if (Test-Path $InstallerProductsPath) {
Get-ChildItem -Path $InstallerProductsPath -ErrorAction SilentlyContinue | ForEach-Object { Get-ChildItem -Path $InstallerProductsPath -ErrorAction SilentlyContinue | ForEach-Object {
$prodName = (Get-ItemProperty -Path $_.PSPath -Name "ProductName" -ErrorAction SilentlyContinue).ProductName $prodName = (Get-ItemProperty -Path $_.PSPath -Name "ProductName" -ErrorAction SilentlyContinue).ProductName
if ($prodName -like $AppNamePattern) { if ($prodName -like $AppNamePattern) {
Write-Log "Removing orphaned Windows Installer product registration: $($_.PSPath) ($prodName)" Write-Log "Removing orphaned Windows Installer product registration: $($_.PSPath) ($prodName)"
Remove-Item -Path $_.PSPath -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $_.PSPath -Recurse -Force -ErrorAction SilentlyContinue
} }
} }
} }
# Clean Run / Startup registry values referencing 8x8 Work # Clean Run / Startup registry values referencing 8x8 Work
$RunKeys = @( $RunKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
) )
Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object { Get-ChildItem -Path "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | Where-Object {
$_.PSChildName -match '^S-1-5-21-[\d\-]+$' $_.PSChildName -match '^S-1-5-21-[\d\-]+$'
} | ForEach-Object { } | ForEach-Object {
$RunKeys += "Registry::HKEY_USERS\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Run" $RunKeys += "Registry::HKEY_USERS\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Run"
} }
foreach ($runKey in $RunKeys) { foreach ($runKey in $RunKeys) {
if (Test-Path $runKey) { if (Test-Path $runKey) {
$props = Get-ItemProperty -Path $runKey -ErrorAction SilentlyContinue $props = Get-ItemProperty -Path $runKey -ErrorAction SilentlyContinue
if ($props) { if ($props) {
$props.PSObject.Properties | Where-Object { $props.PSObject.Properties | Where-Object {
$_.Name -notIn @("PSPath", "PSParentPath", "PSChildName", "PSDrive", "PSProvider") -and $_.Name -notIn @("PSPath", "PSParentPath", "PSChildName", "PSDrive", "PSProvider") -and
($_.Name -like "*8x8*" -or $_.Value -like "*8x8*") ($_.Name -like "*8x8*" -or $_.Value -like "*8x8*")
} | ForEach-Object { } | ForEach-Object {
Write-Log "Removing startup Run value '$($_.Name)' from $runKey" Write-Log "Removing startup Run value '$($_.Name)' from $runKey"
Remove-ItemProperty -Path $runKey -Name $_.Name -Force -ErrorAction SilentlyContinue Remove-ItemProperty -Path $runKey -Name $_.Name -Force -ErrorAction SilentlyContinue
} }
} }
} }
} }
Write-Log "8x8 Work uninstallation and cleanup completed successfully." Write-Log "8x8 Work uninstallation and cleanup completed successfully."
exit 0 exit 0