Monday, June 22, 2015

Powershell script: Cleaning up C:\Windows\Installer directory - the correct way

This very simple script is built off Heath Stewart's VB Script which identifies the files linked for installed products that need to be kept.  My powershell wrapper simply takes his output and automates the deleting of what's not needed.  Usage is simple: drop the script in a temp directory, and run. It will create and run Heath's script which creates another file (output.txt) which is then read back in and parsed.  You'll see what's being removed and what's being kept.

It can be pushed as a scriptblock to remote servers using PS Remoting or PSexec.exe.

Enjoy!

1 comment:

JohnLBevan said...

This is great; thank-you for sharing.

FYI: To avoid mixing VBS and PS, I've created a PS version of the VBS script. Hope this is useful to yourself & your readers:

[code]

clear-host
function Get-WindowsInstallerPatchInfo {
[CmdletBinding()]
Param ()
$msi = New-Object -ComObject 'WindowsInstaller.Installer'
#using trick from: https://p0w3rsh3ll.wordpress.com/2012/01/10/working-with-the-windowsinstaller-installer-object/
$msi | Add-Member -Name 'InvokeMethod' -MemberType ScriptMethod -Value {
$type = $this.GetType();
$index = $args.Count -1 ;
$methodargs=$args[1..$index]
$type.invokeMember($args[0],[System.Reflection.BindingFlags]::InvokeMethod,$null,$this,$methodargs)

}
$msi | Add-Member -Name 'GetProperty' -MemberType ScriptMethod -Value {
$type = $this.gettype();
$index = $args.count -1 ;
$methodargs=$args[1..$index]
$type.invokeMember($args[0],[System.Reflection.BindingFlags]::GetProperty,$null,$this,$methodargs)
}

$products = $msi.GetProperty('Products')
if ($products) {
Write-Verbose "Product Count: $($products.Count)"
foreach ($productCode in $products) {
Write-Verbose "Product: $productCode"
$patches = $msi.GetProperty('Patches',$productCode)
if ($patches) {
foreach ($patchCode in $patches) {
Write-Verbose "Patch: $patchCode"
$location = $msi.GetProperty('PatchInfo', $patchCode, 'LocalPackage')
Write-Verbose "Location: $location"
if ($location) {
(New-Object -TypeName 'PSObject' -Property @{
ProductCode = $productCode
PatchCode = $patchCode
Location = $location
})
}
}
}
}
}
}
[PSObject[]]$patchLocationInfo = Get-WindowsInstallerPatchInfo -Verbose
$patchLocationInfo | format-table -autofit #optional: include this line to see what we gathered with the above script in table form
[string[]]$filelocation = $patchLocationInfo | select-object -expandproperty location
#continue with Bryan's script from line 68.

[/code]