Skip to main content

Extract Msi File Properties by using PowerShell

· 2 min read
Naw Awn

This post is about retrieving the MSI file properties from PowerShell. There are some tools if you need to read the metadata from the msi database.

  • Orca
  • InstEd

The script will just loop through all the available properties with value and return the result in PSCustomObject. You can use this script to read the ProductCode of an MSI file before the installation.

Get-MsiFileInfo.ps1
Function Get-MsiFileInfo{ 
[CmdletBinding()]
Param(
[parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[Alias ("FullName")][String]$Path
)
Begin{
$Query = "SELECT * FROM Property"
}
Process{
If (-Not([System.IO.Path]::IsPathRooted($Path))){
$MsiPath = (Resolve-Path -Path $Path).Path -As [System.IO.FileInfo]
}
Else{
$MsiPath = (Get-ChildItem -Path $Path) -As [System.IO.FileInfo]
}
if ($MsiPath.Extension -ne ".msi"){
throw "Path must be an msi file."
}
$MsiValue = @{}
Write-Verbose "Open and Read property from MSI database"
$MsiObj = New-Object -ComObject WindowsInstaller.Installer
$MsiDb = $MsiObj.GetType().InvokeMember('OpenDatabase','InvokeMethod',$null,$MsiObj, @($MsiPath.FullName, 0))
$View = $MsiDb.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $MsiDb, ($Query))
$View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $View, $null)
While($Record = $View.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $View, $null)){
$Name = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 1)
$Value = $Record.GetType().InvokeMember('StringData', 'GetProperty', $null, $Record, 2)
$MsiValue.Add($Name, $Value)
}
$MsiValue.Add('FileName', $MsiPath.Name)
$MsiValue.Add('FilePath', $MsiPath.FullName)

Write-Verbose "Commit database and close view"
$MsiDb.GetType().InvokeMember('Commit', 'InvokeMethod', $null, $MsiDb, $null)
$View.GetType().InvokeMember('Close', 'InvokeMethod', $null, $View, $null)
$MsiDb = $null
$View = $null

#Run garbage collection and release ComObject
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($MsiObj)
$MsiObj = $null
[System.GC]::Collect()

return ([PSCustomObject]$MsiValue)
}
<#
.Synopsis
Read MSI file properties
.EXAMPLE
Get-MsiFileInfo -Path 'C:\temp\Microsoft\msodbcsql.msi'
.EXAMPLE
$Property = @("ProductCode","ProductVersion","ProductName","Manufacturer","ProductLanguage")
Get-ChildItem c:\temp\*.msi -File -Recurse | Get-MsiFileInfo | ft $Property
#>
}

If you are planning to create msi application on Intune, this can be really handy.

$Property = @(
@{n='DisplayName';e={$_.ProductName}},
@{n='Publisher'; e={$_.Manufacturer}},
'ProductCode',
'ProductVersion',
'FileName'
)
$MyMsiInfo = Get-MsiFileInfo -Path 'C:\temp\Orca.msi' | Select $Property
$Param = @{}
$MyMsiInfo.psobject.properties | %{$Param.Add($_.Name,$_.Value)}

#This is the cmdlet from Microsoft.Graph.Intune PowerShell Module
$AppObject = New-MobileAppObject -windowsMobileMSI @Param
tip

Note that the return properties are not always the same for different msi file depending on what has been defined on the msi file itself.