diff --git a/uninstall-MS-Visual-C++-2010.ps1 b/uninstall-MS-Visual-C++-2010.ps1 index 7e44fe3..5932dad 100644 --- a/uninstall-MS-Visual-C++-2010.ps1 +++ b/uninstall-MS-Visual-C++-2010.ps1 @@ -1,7 +1,9 @@ -# Remove all "Microsoft Visual C++ 2010 ... Redistributable" (x86/x64), version independent +# This script is designed for use in Datto RMM (CentraStage). +# Purpose: Uninstall all "Microsoft Visual C++ 2010 ... Redistributable" (x86/x64), version independent. # Exit codes: # 0 = OK (nothing found or everything removed successfully) # 1 = Failures occurred + $ErrorActionPreference = 'Stop' $fails = 0 @@ -12,13 +14,14 @@ function Invoke-Uninstall { ) if (-not $CmdLine) { - Write-Warning "No UninstallString found for: $AppName" + Write-Warning ("No UninstallString found for " + $AppName) $script:fails++ return } # Normalize to exe + args - $exe = $null; $args = '' + $exe = $null + $args = "" if ($CmdLine -match '^\s*"(.+?)"\s*(.*)$') { $exe = $Matches[1] $args = $Matches[2] @@ -29,21 +32,20 @@ function Invoke-Uninstall { # MSI: force silent uninstall if ($exe -match '(?i)msiexec\.exe') { - # Convert /I {GUID} -> /x {GUID} if ($args -match '(?i)/I\s*{([0-9A-F\-]+)}') { $guid = $Matches[1] - $args = "/x {$guid} /quiet /norestart" + $args = "/x {" + $guid + "} /quiet /norestart" } else { - if ($args -notmatch '(?i)/x') { $args = "/x $args" } - if ($args -notmatch '(?i)/quiet|/qn') { $args += ' /quiet' } - if ($args -notmatch '(?i)/norestart') { $args += ' /norestart' } + if ($args -notmatch '(?i)/x') { $args = "/x " + $args } + if ($args -notmatch '(?i)/quiet|/qn') { $args = $args + " /quiet" } + if ($args -notmatch '(?i)/norestart') { $args = $args + " /norestart" } } - Write-Output "Uninstall (MSI) $AppName -> msiexec $args" + Write-Output ("Uninstall (MSI) " + $AppName + " -> msiexec " + $args) } else { - # Non-MSI: try to enforce silent switches if missing - if ($args -notmatch '(?i)/quiet|/qn|/silent|/s') { $args += ' /quiet' } - if ($args -notmatch '(?i)/norestart') { $args += ' /norestart' } - Write-Output "Uninstall (EXE) $AppName -> $exe $args" + # Non-MSI: try to enforce silent switches + if ($args -notmatch '(?i)/quiet|/qn|/silent|/s') { $args = $args + " /quiet" } + if ($args -notmatch '(?i)/norestart') { $args = $args + " /norestart" } + Write-Output ("Uninstall (EXE) " + $AppName + " -> " + $exe + " " + $args) } try { @@ -52,54 +54,27 @@ function Invoke-Uninstall { # Common msiexec codes: 0=success, 3010=reboot required, 1605=not installed if ($exe -match '(?i)msiexec\.exe') { if ($code -in 0,3010,1605) { - if ($code -eq 3010) { Write-Output "Note: reboot required (3010) for $AppName" } - elseif ($code -eq 1605) { Write-Output "Not installed (1605) for $AppName, skipping." } + if ($code -eq 3010) { Write-Output ("Note: reboot required (3010) for " + $AppName) } + elseif ($code -eq 1605) { Write-Output ("Not installed (1605) for " + $AppName + ", skipping.") } return } } else { if ($code -eq 0) { return } } - Write-Warning "Uninstall failed for $AppName with exit code $code" + Write-Warning ("Uninstall failed for " + $AppName + " with exit code " + $code) $script:fails++ } catch { $msg = $_.Exception.Message - Write-Warning "Error while uninstalling $AppName: $msg" + Write-Warning ("Error while uninstalling " + $AppName + ": " + $msg) $script:fails++ } } # Pre-check: look for target apps $uninstallKeys = @( - 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', - 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) $targets = foreach ($key in $uninstallKeys) { - Get-ItemProperty -Path $key -ErrorAction SilentlyContinue | - Where-Object { - $_.DisplayName -and - $_.DisplayName -like 'Microsoft Visual C++ 2010*Redistributable*' - } -} - -if (-not $targets) { - Write-Output 'No Microsoft Visual C++ 2010 Redistributables found. Nothing to do.' - exit 0 -} - -Write-Output ("Found: " + ($targets.DisplayName | Sort-Object -Unique -join ', ')) - -# Uninstall each item -foreach ($app in $targets) { - $name = $app.DisplayName - $cmd = if ($app.QuietUninstallString) { $app.QuietUninstallString } else { $app.UninstallString } - Invoke-Uninstall -CmdLine $cmd -AppName $name -} - -if ($fails -gt 0) { - Write-Output "Completed with errors: $fails item(s) failed to uninstall." - exit 1 -} else { - Write-Output 'Completed: all target items successfully removed (or not present).' - exit 0 -} + Get-ItemProperty -Path $key -ErrorAction SilentlyContinue |