Read MSI information with PowerShell

I tried to search for some way to read MSI-information with PowerShell, that wasn’t to easy to find.

Anyway, here is a function that helps you read the “Property” view from one MSI-file, the result is stored in a hash table.

# Load some TypeData
$SavedEA = $Global:ErrorActionPreference
$Global:ErrorActionPreference = "SilentlyContinue"
Update-TypeData -AppendPath ((Split-Path -Parent $MyInvocation.MyCommand.Path) + "\comObject.types.ps1xml")
$Global:ErrorActionPreference = $SavedEA

function global:get-msiproperties {
	PARAM (
		[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="MSI Database Filename",ValueFromPipeline=$true)]
		[Alias("Filename","Path","Database","Msi")]
		$msiDbName
	)

	# A quick check to see if the file exist
	if(!(Test-Path $msiDbName)){
		throw "Could not find " + $msiDbName
	}

	# Create an empty hashtable to store properties in
	$msiProps = @{}
	
	# Creating WI object and load MSI database
	$wiObject = New-Object -com WindowsInstaller.Installer
	$wiDatabase = $wiObject.InvokeMethod("OpenDatabase", (Resolve-Path $msiDbName).Path, 0)
	
	# Open the Property-view
	$view = $wiDatabase.InvokeMethod("OpenView", "SELECT * FROM Property")
	$view.InvokeMethod("Execute")
	
	# Loop thru the table
	$r = $view.InvokeMethod("Fetch")
	while($r -ne $null) {
		# Add property and value to hash table
		$msiProps[$r.InvokeParamProperty("StringData",1)] = $r.InvokeParamProperty("StringData",2)
		
		# Fetch the next row
		$r = $view.InvokeMethod("Fetch")
	}

	$view.InvokeMethod("Close")
	
	# Return the hash table
	return $msiProps
}

You need to expand your type configuration with this file, saved as comObject.types.ps1xml in the same directory as the script above.

<!--
Copy from: Abhishek's PowerShell Blog - http://abhishek225.spaces.live.com/blog/

Original post: http://abhishek225.spaces.live.com/blog/cns!13469C7B7CE6E911!165.entry
-->
<Types>
	<Type>
		<Name>System.__ComObject</Name>
		<Members>
			<ScriptMethod>
				<Name>GetProperty</Name>
				<Script>
					$type = $this.gettype();
					$type.invokeMember($args[0],[System.Reflection.BindingFlags]::GetProperty,$null,$this,$null)
				</Script>
			</ScriptMethod>
			<ScriptMethod>
				<Name>SetProperty</Name>
				<Script>
					$type = $this.gettype();
					$type.invokeMember($args[0],[System.Reflection.BindingFlags]::GetProperty,$null,$this,@($args[1]))
				</Script>
			</ScriptMethod>
			<ScriptMethod>
				<Name>InvokeParamProperty</Name>
				<Script>
					$type = $this.gettype();
					$index = $args.count -1 ;
					$methodargs=$args[1..$index]
					$type.invokeMember($args[0],[System.Reflection.BindingFlags]::GetProperty,$null,$this,$methodargs)
				</Script>
			</ScriptMethod>
			<ScriptMethod>
				<Name>InvokeMethod</Name>
				<Script>
					$type = $this.gettype();
					$index = $args.count -1 ;
					$methodargs=$args[1..$index]
					$type.invokeMember($args[0],[System.Reflection.BindingFlags]::InvokeMethod,$null,$this,$methodargs)
				</Script>
			</ScriptMethod>
		</Members>
	</Type>
</Types>

7 comments

  1. Pingback: Remove non-windows MSP packages with powershell | PHP Developer Resource
  2. Dan

    Exception calling “InvokeMember” with “5″ argument(s): “OpenDatabase,DatabasePath,OpenMode”

    How did you get around this error?