puppetlabs/puppet — pull request #847 by joshcooper (2012-06-11 18:31:09+00:00)
Title: (#11868) Use `Installer` automation interface to query package state

Previously, Puppet recorded MSI packages it had installed in a YAML
file. However, if the file was deleted or the system modified, e.g.
Add/Remove Programs, then Puppet did not know the package state had
changed.

Also, if the name of the package did not change across versions, e.g.
VMware Tools, then puppet would report the package as insync even though
the installed version could be different than the one pointed to by the
source parameter.

This commit changes the msi package provider to use the `Installer`
Automation (COM) interface to query the state of the system[1]. It will
now accurately report on installed packages, even those it did not
install, including Puppet itself (#13444). If a package is removed via
Add/Remove Programs, Puppet will re-install it the next time it runs.

When using the msi package resource, the resource title should match the
'ProductName' property in the MSI Property table, which is also the value
displayed in Add/Remove Programs, e.g.

package { 'Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148':
ensure => installed,
...
}

In cases where the ProductName does not change across versions, e.g.
VMware Tools, you should use the PackageCode as the name of the resource:

package { '{0E3AA38E-EAD3-4348-B5C5-051B6852CED6}':
ensure => installed,
...
}

You can obtain the PackageCode in ruby using:

require 'win32ole'
installer = WIN32OLE.new('WindowsInstaller.Installer')
db = installer.OpenDatabase(path, 0)
puts db.SummaryInformation.Property(9)

where is the path to the MSI.

The msi provider does not automatically compare PackageCodes when
determining if the resource is insync, because the source MSI could be on
a network share, and we do not want to copy the potentially large file
just to see if changes need to be made.

[1] http://msdn.microsoft.com/en-us/library/windows/desktop/aa369432(v=vs.85).aspx