6

Stackers,

I am trying to get (from an MSI of Chrome Enterprise) a version number. After I download Chrome as a .MSI , I notice that I can see a number of properties. The one I want to be able to access and build an "if statement" off of is the "Comments" section.

Proof of Data

When I try to use Get-Item and format it as a list, it says there is nothing in there and I cannot seem to identify what to do.

(Get-Item ".\Chrome.msi").VersionInfo | fl

That command returns:

No Output

How can I pull the "Comments" section and the data from it?

2

5 Answers 5

8

These properties are not stored in the System.IO.FileInfo object returned by Get-Item or Get-Command. A solution would be to use the shell.application COM object to retrieve these attributes for you:

$filePath   = ".\Chrome.msi"
$parentPath = (Resolve-Path -Path (Split-Path -Path $filePath)).Path
$fileName   = Split-Path -Path $filePath -Leaf

$shell = New-Object -COMObject Shell.Application
$shellFolder = $Shell.NameSpace($parentPath)
$shellFile   = $ShellFolder.ParseName($fileName)

$shellFolder.GetDetailsOf($shellFile,24)

24, is the ID of the specific property you're after so in this case it's comments needed for .GetDetailsOf(.,.) to get that info . Luckily, I came across this issue before when I too was trying to parse for the comments. I don't recall where but, I found the solution proposed above so I will link it when I can once again find it.

4
  • Any advice to quicken my understanding of... all of this type of stuff? There is so much I do not understand.... I only understood about half of what you posted if I am being honest, but you solved my issue and that worked. Thank you so much. Commented Apr 28, 2022 at 17:25
  • 1
    If you're referring to the COM Object, you can think of it as an interface for some type of administration. Before we had PowerShell, we had COM Objects which let us tap into OS related "stuff" through them and were able to invoke their methods like you see above (.NameSpace(), and .ParseName, etc.). To get a friendly understanding of those, they're really just functions meant to perform a specific purpose. Were you referring to something else? Commented Apr 28, 2022 at 17:46
  • Ah I see thank you; I was referring to COM objects but also just... everything. I supposed if I kept studying PowerShell and Windows in general I would learn all of this (COM Objects, properties, get-member, etc). It just seems like there is so much and the amount of stuff I could learn is way too dep and way too wide haha... but I love it. Thank you for the help. Commented Apr 29, 2022 at 14:02
  • @BradyMigel, no problem man. Just remember, COM objects aren't native to PowerShell so, there is probably a more PowerShell idiomatic way of doing this, like tapping into .Net instead. Get-Member is definitely a great cmdlet to use, so good luck on ur journey! Commented Apr 29, 2022 at 14:03
5

You can obtain the MSI Property "ProductVersion" with Get-AppLockerFileInformation :

Get-AppLockerFileInformation -Path "C:\PathTo\my.msi" | Select -ExpandProperty Publisher | select BinaryVersion

it works only if your MSI is digitally signed.

2

There's also a PowerShell module for this. It's easy to install, use, and has many other features for getting information about products and patches, and can install, modify, and uninstall products and patches with PowerShell progress:

Install-Module MSI
Get-MSISummaryInfo <path>
2
  • Hmm I would want the version: Get-MSIproperty productversion Box-x64.msi
    – js2010
    Commented Oct 26, 2022 at 19:37
  • Yes, it also has an Get-MSIProperty cmdlet as well.
    – Heath
    Commented Oct 26, 2022 at 23:29
1

My take that is cobbled together from the internet.

$msifile = 'C:\googlechromestandaloneenterprise64.msi'

function Which-MSIVersion {
    <#
    .SYNOPSIS
    Function to Check Version of an MSI file.
    
    .DESCRIPTION
    Function to Check Version of an MSI file for comparision in other scripts.
    Accepts path to single file.
    
    .PARAMETER msifile
    Specifies the path to MSI file.
    
    .EXAMPLE
    PS> Which-MSIVersion -msifile $msifile
    68.213.49193
    
    .NOTES
    General notes
    #>
    param (
        [Parameter(Mandatory = $true, HelpMessage = 'Specifies path to MSI file.')][ValidateScript({
        if ($_.EndsWith('.msi')) {
            $true
        } else {
            throw ("{0} must be an '*.msi' file." -f $_)
        }
    })]
    [String[]] $msifile
    )

    $invokemethod = 'InvokeMethod'
    try {

        #calling com object
        $FullPath = (Resolve-Path -Path $msifile).Path
        $windowsInstaller = New-Object -ComObject WindowsInstaller.Installer

        ## opening database from file
        $database = $windowsInstaller.GetType().InvokeMember(
            'OpenDatabase', $invokemethod, $Null, 
            $windowsInstaller, @($FullPath, 0)
        )

        ## select productversion from database
        $q = "SELECT Value FROM Property WHERE Property = 'ProductVersion'"
        $View = $database.GetType().InvokeMember(
            'OpenView', $invokemethod, $Null, $database, ($q)
        )

        ##execute
        $View.GetType().InvokeMember('Execute', $invokemethod, $Null, $View, $Null)

        ## fetch
        $record = $View.GetType().InvokeMember(
            'Fetch', $invokemethod, $Null, $View, $Null
        )

        ## write to variable
        $productVersion = $record.GetType().InvokeMember(
            'StringData', 'GetProperty', $Null, $record, 1
        )

        $View.GetType().InvokeMember('Close', $invokemethod, $Null, $View, $Null)


        ## return productversion
        return $productVersion

    }
    catch {
        throw 'Failed to get MSI file version the error was: {0}.' -f $_
    }
}

Which-MSIVersion -msifile $msifile
0

$msiFilePath = "C:\Path\To\Your\File.msi"

$shell = New-Object -ComObject Shell.Application

$folder = $shell.Namespace((Get-Item $msiFilePath).DirectoryName)

$file = $folder.ParseName((Get-Item $msiFilePath).Name)

$subject = $folder.GetDetailsOf($file, 24)

$versionRegex = "\d+(.\d+){2,3}"

$version = ($subject | Select-String -Pattern $versionRegex).Matches.Value

Write-Host "Version: $version"

Not the answer you're looking for? Browse other questions tagged or ask your own question.