For a large orgnization, it’s common to push a software to clients for auto installation and update. Usually the process needs to know the version information of a software installation package (on Windows it is likely a MSI file) to compare to what has been installed on client machines.
Getting the version information is crucial for this process. For some MSI files, its file meta data contains the information which can be retrieved with the following PowerShell commands:
PS D:\Users\joeli\Downloads> Get-ItemProperty .\Wireshark-win64-3.4.3.exe|Format-List
Directory: D:\Users\joeli\Downloads
Name : Wireshark-win64-3.4.3.exe
Length : 61482312
CreationTime : 2/26/2021 9:39:53 PM
LastWriteTime : 2/26/2021 9:41:42 PM
LastAccessTime : 2/26/2021 9:41:42 PM
Mode : -a----
LinkType :
Target : {}
VersionInfo : File: D:\Users\joeli\Downloads\Wireshark-win64-3.4.3.exe
InternalName:
OriginalFilename:
FileVersion: 3.4.3.0
FileDescription: Wireshark installer for 64-bit Windows
Product: Wireshark
ProductVersion: 3.4.3.0
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language: English (United States)
PS D:\Users\joeli\Downloads> Get-Item .\Wireshark-win64-3.4.3.exe|Select-Object -ExpandProperty VersionInfo
ProductVersion FileVersion FileName
-------------- ----------- --------
3.4.3.0 3.4.3.0 D:\Users\joeli\Downloads\Wireshark-win64-3.4.3.exe
However, for some MSI files, the meta data doesn’t contain this information and the commands above will return nothing.
PS C:\Users\Administrator\Desktop> Get-Item .\JoeTest.msi|Select-Object -ExpandProperty VersionInfo
ProductVersion FileVersion FileName
-------------- ----------- --------
C:\Users\Administrator\Desktop\JoeTest.msi
In this case, likely for those MSI files, the version information is stored in the MSI database. A small script is needed to open MSI database and query the version information:
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[System.IO.FileInfo] $MSIPATH
)
if (!(Test-Path $MSIPATH.FullName)) {
throw "File '{0}' does not exist" -f $MSIPATH.FullName
}
try {
$WindowsInstaller = New-Object -com WindowsInstaller.Installer
$Database = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $WindowsInstaller, @($MSIPATH.FullName, 0))
$Query = "SELECT Value FROM Property WHERE Property = 'ProductVersion'"
$View = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $Null, $Database, ($Query))
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null) | Out-Null
$Record = $View.GetType().InvokeMember( "Fetch", "InvokeMethod", $Null, $View, $Null )
$Version = $Record.GetType().InvokeMember( "StringData", "GetProperty", $Null, $Record, 1 )
return $Version
} catch {
throw "Failed to get MSI file version: {0}." -f $_
}
PS C:\Users\Administrator\Desktop> .\get_msi_version.ps1 -MSIPATH .\JoeTest.msi
4.0.202101.2024
In the script above, the proerty value is hard coded with “ProductVersion”. Other information such as “ProductCode”, “ProductVersion”, “ProductName”, “Manufacturer”, “ProductLanguage” can also be retrieved.
Reference:
Thanks. It was very useful, and exactly what I needed. Kudos to you 🙂
LikeLike