Random_scripts/uninstall-MS-Visual-C++-2010.ps1

116 lines
4.2 KiB
PowerShell

# This script is designed for use in Datto RMM (CentraStage).
# Purpose: Uninstall all "Microsoft Visual C++ 2010 ... Redistributable" (x86/x64), version independent.
#
# Example run / expected output:
# Uninstall Microsoft Visual C++ 2010
# Found: Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219, Microsoft Visual C++ 2010 x86 Redistributable - 10.0.40219
# Uninstall (MSI) Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219 -> msiexec /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7} /quiet /norestart
# Uninstall (MSI) Microsoft Visual C++ 2010 x86 Redistributable - 10.0.40219 -> msiexec /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} /quiet /norestart
# Completed: all target items successfully removed (or not present).
#
# Exit codes:
# 0 = OK (nothing found or everything removed successfully)
# 1 = Failures occurred
$ErrorActionPreference = 'Stop'
$fails = 0
function Invoke-Uninstall {
param(
[string]$CmdLine,
[string]$AppName
)
if (-not $CmdLine) {
Write-Warning ("No UninstallString found for " + $AppName)
$script:fails++
return
}
# Normalize to exe + args
$exe = $null
$args = ""
if ($CmdLine -match '^\s*"(.+?)"\s*(.*)$') {
$exe = $Matches[1]
$args = $Matches[2]
} elseif ($CmdLine -match '^\s*(\S+)\s*(.*)$') {
$exe = $Matches[1]
$args = $Matches[2]
}
# MSI: force silent uninstall
if ($exe -match '(?i)msiexec\.exe') {
if ($args -match '(?i)/I\s*{([0-9A-F\-]+)}') {
$guid = $Matches[1]
$args = "/x {" + $guid + "} /quiet /norestart"
} else {
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)
} else {
# 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 {
$p = Start-Process -FilePath $exe -ArgumentList $args -Wait -PassThru -WindowStyle Hidden
$code = $p.ExitCode
# 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.") }
return
}
} else {
if ($code -eq 0) { return }
}
Write-Warning ("Uninstall failed for " + $AppName + " with exit code " + $code)
$script:fails++
} catch {
$msg = $_.Exception.Message
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\*"
)
$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
}
$foundList = ($targets.DisplayName | Sort-Object -Unique) -join ", "
Write-Output ("Found: " + $foundList)
# 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
}