Update uninstall-MS-Visual-C++-2010.ps1

This commit is contained in:
Ivo Oskamp 2025-08-29 09:44:51 +02:00
parent 44e364caeb
commit 15cd2b8c3f

View File

@ -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: # Exit codes:
# 0 = OK (nothing found or everything removed successfully) # 0 = OK (nothing found or everything removed successfully)
# 1 = Failures occurred # 1 = Failures occurred
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$fails = 0 $fails = 0
@ -12,13 +14,14 @@ function Invoke-Uninstall {
) )
if (-not $CmdLine) { if (-not $CmdLine) {
Write-Warning "No UninstallString found for: $AppName" Write-Warning ("No UninstallString found for " + $AppName)
$script:fails++ $script:fails++
return return
} }
# Normalize to exe + args # Normalize to exe + args
$exe = $null; $args = '' $exe = $null
$args = ""
if ($CmdLine -match '^\s*"(.+?)"\s*(.*)$') { if ($CmdLine -match '^\s*"(.+?)"\s*(.*)$') {
$exe = $Matches[1] $exe = $Matches[1]
$args = $Matches[2] $args = $Matches[2]
@ -29,21 +32,20 @@ function Invoke-Uninstall {
# MSI: force silent uninstall # MSI: force silent uninstall
if ($exe -match '(?i)msiexec\.exe') { if ($exe -match '(?i)msiexec\.exe') {
# Convert /I {GUID} -> /x {GUID}
if ($args -match '(?i)/I\s*{([0-9A-F\-]+)}') { if ($args -match '(?i)/I\s*{([0-9A-F\-]+)}') {
$guid = $Matches[1] $guid = $Matches[1]
$args = "/x {$guid} /quiet /norestart" $args = "/x {" + $guid + "} /quiet /norestart"
} else { } else {
if ($args -notmatch '(?i)/x') { $args = "/x $args" } if ($args -notmatch '(?i)/x') { $args = "/x " + $args }
if ($args -notmatch '(?i)/quiet|/qn') { $args += ' /quiet' } if ($args -notmatch '(?i)/quiet|/qn') { $args = $args + " /quiet" }
if ($args -notmatch '(?i)/norestart') { $args += ' /norestart' } if ($args -notmatch '(?i)/norestart') { $args = $args + " /norestart" }
} }
Write-Output "Uninstall (MSI) $AppName -> msiexec $args" Write-Output ("Uninstall (MSI) " + $AppName + " -> msiexec " + $args)
} else { } else {
# Non-MSI: try to enforce silent switches if missing # Non-MSI: try to enforce silent switches
if ($args -notmatch '(?i)/quiet|/qn|/silent|/s') { $args += ' /quiet' } if ($args -notmatch '(?i)/quiet|/qn|/silent|/s') { $args = $args + " /quiet" }
if ($args -notmatch '(?i)/norestart') { $args += ' /norestart' } if ($args -notmatch '(?i)/norestart') { $args = $args + " /norestart" }
Write-Output "Uninstall (EXE) $AppName -> $exe $args" Write-Output ("Uninstall (EXE) " + $AppName + " -> " + $exe + " " + $args)
} }
try { try {
@ -52,54 +54,27 @@ function Invoke-Uninstall {
# Common msiexec codes: 0=success, 3010=reboot required, 1605=not installed # Common msiexec codes: 0=success, 3010=reboot required, 1605=not installed
if ($exe -match '(?i)msiexec\.exe') { if ($exe -match '(?i)msiexec\.exe') {
if ($code -in 0,3010,1605) { if ($code -in 0,3010,1605) {
if ($code -eq 3010) { Write-Output "Note: reboot required (3010) for $AppName" } if ($code -eq 3010) { Write-Output ("Note: reboot required (3010) for " + $AppName) }
elseif ($code -eq 1605) { Write-Output "Not installed (1605) for $AppName, skipping." } elseif ($code -eq 1605) { Write-Output ("Not installed (1605) for " + $AppName + ", skipping.") }
return return
} }
} else { } else {
if ($code -eq 0) { return } 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++ $script:fails++
} catch { } catch {
$msg = $_.Exception.Message $msg = $_.Exception.Message
Write-Warning "Error while uninstalling $AppName: $msg" Write-Warning ("Error while uninstalling " + $AppName + ": " + $msg)
$script:fails++ $script:fails++
} }
} }
# Pre-check: look for target apps # Pre-check: look for target apps
$uninstallKeys = @( $uninstallKeys = @(
'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\*"
) )
$targets = foreach ($key in $uninstallKeys) { $targets = foreach ($key in $uninstallKeys) {
Get-ItemProperty -Path $key -ErrorAction SilentlyContinue | 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
}