Hey guys hopefully someone can help me. I have a powershell script that identifies old .msi(s) and deletes them from Windows/Installer folder, but I need to add some code to bypass or (skip) a certain Product ID/Source hash. Basically I need the script to skip this: {1610CB69-BE80-41B9-9B77-E346C1DA12F3} and have it not be deleted. Does anyone know how I can achieve this?
Here's my script:
<#
This script uses VB script to identify which files need to be saved and then removes everything else.
#>
$VBSFile = @"
'' Identify which patches are registered on the system, and to which
'' products those patches are installed.
'Option Explicit
Dim msi : Set msi = CreateObject("WindowsInstaller.Installer")
'Output CSV header
WScript.Echo "The data format is ProductCode, PatchCode, PatchLocation"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("output.txt", True)
objFile.WriteLine "ProductCode, PatchCode, PatchLocation"
objFile.WriteLine ""
' Enumerate all products
Dim products : Set products = msi.Products
Dim productCode
For Each productCode in products
' For each product, enumerate its applied patches
Dim patches : Set patches = msi.Patches(productCode)
Dim patchCode
For Each patchCode in patches
' Get the local patch location
Dim location : location = msi.PatchInfo(patchCode, "LocalPackage")
objFile.WriteLine productCode & ", " & patchCode & ", " & location
Next
Next
WScript.Echo "Data written to output.txt, these are the registered objects and SHOULD be kept!"
"@
$VBSFile | Set-Content .\WiMsps.vbs
cscript .\WiMsps.vbs
$savelist = Import-Csv .\output.txt
$filelocation = $savelist | select -ExpandProperty PatchLocation
#First pass to remove exact file names
dir C:\windows\Installer -file | ForEach-Object{
$fullname = $_.FullName
if($filelocation | Where-Object{$_ -like "*$fullname*"}){
"Keeping $fullname"
}
else{
Remove-Item $fullname -Force -Verbose
}
}
#second pass to match product and patch codes
dir C:\windows\Installer -Directory | ForEach-Object{
$fullname = $_.name
if($savelist | Where-Object{$_.ProductCode -like "*$fullname*" -or $_.PatchCode -like "*$fullname*" }){
"Keeping $fullname"
}
else{
Remove-Item $_.fullname -Force -Verbose -Recurse
}
}
pause
Basically right now it's deleting everything it can't find a source for dependency. Or at least I think it is... I got this script from someone else, so yeah basically I can't figure out what to do.
MSI Cache Folder: You must not mess around in this folder! You typically end up with products that can not be uninstalled.
cleanmgr.exe
. More on that in the links below. The files should also be removed when the product in question is uninstalled.Disk Space: If you are looking to clear out some disk space, perhaps try these suggestions instead: Ways to clear disk space. And there is a long version of the same list. Please visit at least the first link and locate information about cleanmgr.exe
. You can also run the newer ms-settings:storagesense
from the run dialog. Also described in the link.
Tools Summary: Accessible from Windows Key
+ Tap R
:
cleanmgr.exe
ms-settings:storagesense
COM Automation: For the record you can uninstall a product via COM automation selectively (excluding your product) like this:
Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
'Iterate over all MSI packages on the box
For Each product In products
If LCase("{1610CB69-BE80-41B9-9B77-E346C1DA12F3}") = LCase(product.productcode) Then
MsgBox "Found Product: " + product.InstallProperty("ProductName")
Else
' Can run uninstall here via COM method - ADMIN RIGHTS!
' installer.ConfigureProduct product.productcode, 0, 2
End If
Next
MsgBox "Finished."
Powershell MSI Module: There is also a Powershell module for MSI made by deployment guru Heath Stewart. Github.com: https://github.com/heaths/psmsi. I have not used it actively, but surely this module has sorted out most problems and will be a better option than going via COM? Personally I would just use a VBScript and COM - easier in my opinion.