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