Working with the WindowsInstaller.Installer object

I started working on converting some vbscripts proposed by Microsoft to extract the XML information of MSP files created by the OCT (Office Customization Tool). http://technet.microsoft.com/en-us/library/cc179027.aspx

As usual to start exploring the object, I simply typed at command prompt:

New-Object -ComObject WindowsInstaller.Installer | gm

I got the following output that shows how poor is the object and that there aren’t the methods I was looking for.
I’m actually looking for OpenDatabase method as it’s being used by the vbscript and it’s also referenced on this page:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa369432%28v=VS.85%29.aspx
WindowsInstaller.Installer output 1

I decided to have a look the MSDN documentation and found the following page
http://msdn.microsoft.com/en-us/library/1yece858%28v=VS.110%29.aspx

Idem, I explored the object’s methods with the Get-Member cmdlet.

New-Object System.Configuration.Install.Installer | gm

I had a better result but definitly not the methods I expected.
System.Configuration.Install.Installer output 2

Actually, I came across the following page, http://www.snowland.se/2010/02/21/read-msi-information-with-powershell and decided to extend the original WindowsInstaller.Installer COM Object but without using the Update-TypeData cmdlet and the additional get-help .ps1xml file as it should be signed,…
Moreover the help on this page, http://technet.microsoft.com/en-us/library/dd347581.aspx states that:

However, if you need to add properties or methods only to one instance of an object, use the Add-Member cmdlet.

get-help about_types.ps1xml -full

Things worked great with the following code

# Connect to Windows Installer object    
$wi = New-Object -ComObject WindowsInstaller.Installer

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

# Open OCT patch and read the metadata stream
try
{
    # 32 = msiOpenDatabaseModePatchFile
    $wiStorage = $wi.InvokeMethod("OpenDatabase",$Path,32)
} catch {
    $_
    exit
}

Until I had to use the ReadStream method that has many parameters.
I had a the following error

Exception calling "InvokeMethod" with "4" argument(s): "Exception calling "InvokeMember" with "5" argument(s): "Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))""

The answer came actually both from this command

($wi.GetType() | Get-Member) | Where-Object Name -eq InvokeMember | fl -Property *

WindowsInstaller.installer output 3
as well as from this page:
http://stackoverflow.com/questions/5544844/how-to-call-a-complex-com-method-from-powershell

So, the solution is:

# $vw.Execute()
$vw = $vw | Add-Member -MemberType ScriptMethod -Value $codeInvokeMethod -Name InvokeMethod -PassThru
$vw.InvokeMethod("Execute")

# $rec = $vw.Fetch()
$rec = $vw.InvokeMethod("Fetch")

$codeInvokeParamProperty = {
    $type = $this.gettype();
    $index = $args.count -1 ;
    $methodargs=$args[1..$index]
    $type.invokeMember($args[0],[System.Reflection.BindingFlags]::GetProperty,$null,$this,$methodargs)
}

$rec = $rec | Add-Member -MemberType ScriptMethod -Value $codeInvokeParamProperty -Name InvokeParamProperty -PassThru

If ($rec -ne $null)
{
    
    $DataSize = $rec.InvokeParamProperty("DataSize",2)

    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa371140%28v=vs.85%29.aspx
    $paramHT = @{Field = 2 ; Length = [int]$DataSize ; Format = 1}

    $sMetadata = $rec.GetType().InvokeMember("ReadStream", [System.Reflection.BindingFlags]::InvokeMethod,
                $null,  # Binder
                $rec,  # Target
                ([Object[]]($paramHT.Values)),  # Args
                $null,  # Modifiers
                $null,  # Culture
                ([String[]]($paramHT.Keys))  # NamedParameters
            )
    
} else {
    Write-Output -InputObject "No Metadata stream was found in this file: $Path"
    Exit 2
}
Advertisements

5 thoughts on “Working with the WindowsInstaller.Installer object

  1. Pingback: Powershell – “InvokeMember” with “5” argument(s) error |

  2. A very good article. Exactly the info, I’m looking for. But it seems to be an Object $vw .The last part runs on an error. What is needed? $vw = New-Object -ComObject … what is missing?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s