Enumerating and un-installing products by name using PowerShell and MSIConfig.exe

by Klaus Graefensteiner 13. November 2009 08:03

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.

AddRemove Programs

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

MSIConfigOutput 

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.

Tags: ,

Test Automation | PowerShell | Tips & Tricks

Comments

11/22/2009 12:26:45 PM #

pingback

Pingback from powerscripting.wordpress.com

Episode 93 – Jeff Atwood tells us Rock Hard Awesome will create teleportation and we talk about ServerFault «  PowerScripting Podcast

powerscripting.wordpress.com |

Comments are closed

About Klaus Graefensteiner

I like the programming of machines.

Add to Google Reader or Homepage

LinkedIn FacebookTwitter View Klaus Graefensteiner's profile on Technorati
Klaus Graefensteiner

Klaus Graefensteiner
works as Developer In Test and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Open Source Projects

PSUnit is a Unit Testing framwork for PowerShell. It is designed for simplicity and hosted by Codeplex.
BlogShell is The tool for lazy developers who like to automate the composition of blog content during the writing of a blog post. It is hosted by CodePlex.

Administration

About

Powered by:
BlogEngine.Net
Version: 1.6.1.0

License:
Creative Commons License

Copyright:
© Copyright 2012, Klaus Graefensteiner.

Disclaimer:
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design:
This blog theme was designed and is copyrighted 2012 by Klaus Graefensteiner

Rendertime:
Page rendered at 2/5/2012 11:06:09 PM (PST Pacific Standard Time UTC DST -7)