Search code examples
phpwindows-installer

Read Windows Installer (MSI file) attributes from PHP


I have a Windows MSI file, that I need to programmatically read the version number from. The only place I can see this version is within the Subject of the file details:

MSI file

If I somehow can read the entire content of Subject this would be fine but is there any way to get this from PHP? The PHP is running in an IIS web server, if this helps ;-)

stat is of no help for this.

I considered doing a checksum of the file, and can do that, but I really need the real version.


Solution

  • For now I am unable to find a native PHP solution for this, so I have temporarily solved this by calling a Powershell script as it seems easier to do in there.

    I am now having this PHP code: $version = exec("powershell.exe -file GetMsiVersion.ps1 MyFile.msi);

    With my above picture then $version will contain 1.5.9, so I will not even require to interpret the data from Subject.

    The GetMsiVersion.ps1 Powershell script has this code:

    function Get-Property ($Object, $PropertyName, [object[]]$ArgumentList) {
        return $Object.GetType().InvokeMember($PropertyName, 'Public, Instance, GetProperty', $null, $Object, $ArgumentList)
    }
    
    function Invoke-Method ($Object, $MethodName, $ArgumentList) {
        return $Object.GetType().InvokeMember($MethodName, 'Public, Instance, InvokeMethod', $null, $Object, $ArgumentList)
    }
    
    $Path = $args[0]
    $msiOpenDatabaseModeReadOnly = 0
    $Installer = New-Object -ComObject WindowsInstaller.Installer
    $Database = Invoke-Method $Installer OpenDatabase  @($Path, $msiOpenDatabaseModeReadOnly)
    $View = Invoke-Method $Database OpenView  @("SELECT Value FROM Property WHERE Property='ProductVersion'")
    Invoke-Method $View Execute
    $Record = Invoke-Method $View Fetch
    if ($Record) {
        Write-Output (Get-Property $Record StringData 1)
    }
    
    Invoke-Method $View Close @()
    

    I will accept this as the best solution here-and-now but, I hope this can be archieved natively from PHP as I see this as a better and more clean solution - and by then I will accept that as the best answer (or at least unaccept my own temporary solution).

    Doing an exec is a little evil ;-)