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>
Now that’s what I call helpful.
Thanks a lot Rikard!
Thank you very much for this code sample.
Missing at the end, before returning
$view.InvokeMethod("Close")Thanks Ferdi, the script is updated.