Introduction
In this blog post I describe a simple method to enumerate all products that are installed on a given computer and then un-install a subset of these after applying a regular expression filter to the MSI product names. The PowerShell script that I wrote to implement this idea let’s you for example automatically un-install all products that have for example “Apple” in their product Name.
Note: While writing this post, I found two related blog posts on the internet that make querying of un-installable products even easier. All you need to do is to query a specific registry key. Here are the two links:
http://blogs.msdn.com/powershell/archive/2009/11/15/i-can-do-that-with-1-line-of-powershell-installed-software.aspx
http://myitforum.com/cs2/blogs/yli628/archive/2008/01/16/powershell-script-to-list-installed-software-on-local-computer.aspx
gp HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*, `
HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* `
| Select DisplayName, DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString |ogv
Nevertheless this blog post still can serve as an nice real world example about using the new PowerShell 2.0 features to parse the output of a command line utility and create PSObjects from the output strings that got converted into a hash table. The hash table is then used for the new properties parameter of the new-object cmdlet.
Figure 1: Add/Remove programs
MSIConfig.exe
This command line utility enumerates all installed products on the local machine and emits nicely formatted output that contains the following attributes: Name, Guid, Location, Date and Version
Figure 2: MSIConfig.exe example output
The PowerShell script
As you can see in the output window, a PowerShell script would have to capture the output of MSIConfig.exe. Then the script would parse key value pairs for the five properties: Name, Guid, Version, Location and Date and create PSObjects. Once you have this collection of MSI objects you can do all kinds of things to filter and search for specific property values. In my case I was looking for the “Apple” in the product name. Then I would use the Guid that goes with it and un-install the product using msiexec.
Here is the complete listing of the PowerShell script:
$DebugPreference = "Continue"
Set-StrictMode -Version "Latest"
$InstalledProducts = ./MSIConfig
function Convert-MSIConfigToMSITable([object[]] $InstalledProducts)
{
$InstalledProductsList = New-Object -TypeName "System.Collections.ArrayList"
$ProductTable = @{}
$FieldCounter = 0
$Regex = '^(?<KEY>.*?)(: )(?<VALUE>.*)$'
$InstalledProducts | ForEach-Object `
{
if($_ -ne "")
{
Write-Debug "$_"
$TestString = $_.Trim()
$MatchResult = $TestString -match $Regex
$Key = $Matches.KEY
$Value = $Matches.VALUE
Write-Debug "Key: $Key`t`t Value: $Value"
$ProductTable[$Key] = $Value
$FieldCounter++
}
if ($FieldCounter -eq 5)
{
$FieldCounter = 0
$MSIProduct = New-Object PSObject -Property $ProductTable
[void] $InstalledProductsList.Add($MSIProduct)
}
}
return $InstalledProductsList
}
function Get-InstalledAppleProducts()
{
$Result = Convert-MSIConfigToMSITable $InstalledProducts
$InstalledAppleProducts = New-Object -TypeName "System.Collections.Arraylist"
$Result | ForEach-Object `
{
if($_.Name -match "Apple")
{
Write-Debug "$($_.Name) $($_.Version) $($_.Guid)"
[void] $InstalledAppleProducts.Add($_)
}
}
return $InstalledAppleProducts
}
function Uninstall-AppleProducts()
{
$Result = Get-InstalledAppleProducts
$Result = $Result | Sort-Object -Property "Name"
if($Result -ne $Null -and $Result.Length -gt 0)
{
$Result | ForEach-Object `
{
Write-Debug "Un-installing $($_.Name) Version: $($_.Version) Product Code: $($_.Guid)"
$MSIParameterString = "/qn /x {0} /l*v `"C:\Un-Install-Log-{1}.{2}.txt`"" -f $_.Guid, $_.Name, $_.Version
Write-Debug "$MSIParameterString"
msiexec $MSIParameterString.Split() | out-null
}
}
}
Uninstall-AppleProducts
Download
The files for this article can be downloaded here: MSIConfigStudy.zip
Ausblick
This PowerShell example demonstrates how easy it is to integrate different technologies, such as console applications and .NET. In this example we parsed the output string and converted it to PSObjects.