Safely remove *.msi and *.msp files that are in C:\Windows\Installer but are not the mentioned in the registry
The following VBS clean-windows-installer pass1 uninstalls MSP patches marked as superseded:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
option explicit const HKLM=&H80000002 const instKey="SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products" dim reg, shell, product,force force = false if WScript.Arguments.count > 0 then force = WScript.Arguments.Item(0) = "/f" end if set reg = getObject ("Winmgmts:root\default:StdRegProv" ) set shell= WScript.CreateObject ("WSCript.shell") dim arrProducts reg.EnumKey HKLM,instKey,arrProducts for each product in arrProducts dim productU,productN,arrPatches, patch productU=ReconstructProductCode(product) reg.GetStringValue HKLM, instKey & "\" & product & "\InstallProperties", "DisplayName", productN 'Wscript.Echo productU & "\" & productN reg.EnumKey HKLM,instKey & "\" & product & "\" & "Patches",arrPatches if not IsNull(arrPatches) then for each patch in arrPatches dim patchU,patchN,sta,cmd,ret,msi3,uninsta patchU=ReconstructProductCode(patch) reg.GetStringValue HKLM, instKey & "\" & product & "\Patches\" & patch, "DisplayName", patchN reg.GetDWORDValue HKLM, instKey & "\" & product & "\Patches\" & patch, "State", sta reg.GetDWORDValue HKLM, instKey & "\" & product & "\Patches\" & patch, "MSI3", msi3 reg.GetDWORDValue HKLM, instKey & "\" & product & "\Patches\" & patch, "Uninstallable", uninsta if sta = 2 then if msi3 = 1 then if uninsta = 1 then WScript.Echo "Uninstalling "&productN&" : "&patchN &"…" cmd="msiexec /package " & productU &" /uninstall " & patchU & " /passive /qr /norestart" WScript.Echo cmd ret = shell.Run(cmd,0,true) WScript.Echo "finished with code " & ret else if force then reg.SetDWORDValue HKLM, instKey & "\" & product & "\Patches\" & patch, "Uninstallable", 1 WScript.Echo "Force uninstall "&productN&" : "&patchN &"…" cmd="msiexec /package " & productU &" /uninstall " & patchU & " /passive /qr /norestart" WScript.Echo cmd ret = shell.Run(cmd,0,true) WScript.Echo "finished with code " & ret else WScript.Echo productN&" : "&patchN &" is a permanent patch, run this script with /f to uninstall it" end if end if else WScript.Echo "Not uninstalling "&productN&" : "&patchN &" — Patch removal is available starting with MSI 3.0" end if end if next end if next Function ReconstructProductCode(ByVal strMungedCode) Dim arrSequence Dim strProductCode ,intIndex Const intArraySize = 32 strProductCode = "{" arrSequence = Array(8,7,6,5,4,3,2,1,12,11,10,9,16,15,14,13,18,17,20,19,22,21,24,23,26,25,28,27,30,29,32,31) '// Generate the Product Code For intIndex = 0 to intArraySize - 1 strProductCode = strProductCode & Mid(strMungedCode,arrSequence(intIndex),1) If intIndex = 7 Or intIndex = 11 Or intIndex = 15 Or intIndex = 19 Then strProductCode = strProductCode & "-" End If Next strProductCode = strProductCode & "}" ReconstructProductCode = strProductCode End Function |
This needs to be run with cscript.
This is completely SAFE as it does not remove any .msp files manually, but only calls Windows Installer to uninstall patches which have been marked as superseded in registry!
Your uninstall and future patching capability will be unhindered!
On systems which have Office 2013 installed this can save several GB’s of old versions of large patches such as mso, excel, word, project…
This script is hereby released into public domain and comes without ANY WARRANTY.
The ReconstructProductCode function is shamelessly stolen from here, but probably does not meet the threshold of originality, as there are only so many ways to write the GUID-unmunging algorithm.
More MSI space to save: Set the MaxPatchCacheSize policy to 0 and delete everything inside the $PatchCache$ folder. This is actually the ONLY thing that is safe to delete manually in %SystemRoot%\Installer.
After doing this, uninstalling patches for some very old products may prompt for the original installation source. This does NOT include Office 2007+, Acrobat Reader DC or Visual Studio 2012/2013, as they cache the original source anyway and the $PatchCache$ is completely redundant and useless.
To uninstall permanent patches (like Adobe Reader and Silverlight) run the script with the “/f” option. I recommend to run the script normally first.
When uninstalling Silverlight patches, a harmless warning message “Could not write value UpdateConsentMode…” appears. Click Ignore
When Uninstalling Adobe Reader patches (, the script needs to be run several times due to Adobe Reader using incremental service packs in the past — the script does not know the order in which patches need to be removed.
EDIT: Some Reader updates can’t be removed even with the /f option. This usually means that the lastest update is installed from a delta patch rather than cumulative, and the older patch files are still needed. They will be able to be removed if you install a later cumulative patch.