# 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). # # Usage in Datto RMM: # - Create a new Component → Script (PowerShell). # - Paste this script in the code editor. # - Run As: System # - Architecture: 64-bit # - Test on one device before wide rollout. # - Deploy via Job or Policy at the Site level to target all devices. # # 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 }