From 111916ea992fb782d0d6159c3a64cb10a74e6d34 Mon Sep 17 00:00:00 2001 From: Ivo Oskamp Date: Fri, 29 Aug 2025 09:26:02 +0200 Subject: [PATCH] Add uninstall-MS-Visual-C++-2010.ps1 --- uninstall-MS-Visual-C++-2010.ps1 | 104 +++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 uninstall-MS-Visual-C++-2010.ps1 diff --git a/uninstall-MS-Visual-C++-2010.ps1 b/uninstall-MS-Visual-C++-2010.ps1 new file mode 100644 index 0000000..64e47b2 --- /dev/null +++ b/uninstall-MS-Visual-C++-2010.ps1 @@ -0,0 +1,104 @@ +# Remove 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 + +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') { + # Convert /I {GUID} -> /x {GUID} + 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 += ' /quiet' } + if ($args -notmatch '(?i)/norestart') { $args += ' /norestart' } + } + 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" + } + + 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 { + Write-Warning "Error while uninstalling $AppName: $($_.Exception.Message)" + $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 +} + +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 +}