Private/Get-OSDAppCachedPackageVersion.ps1

function Get-OSDAppMsiProductVersion {
    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return }
    if (Test-OSDAppWinPE) { return }

    $installer = $null
    $database = $null
    $view = $null
    $record = $null
    try {
        # Windows Installer COM opens the database read-only (mode 0).
        # Never invoke installation, extraction or cache updates.
        $installer = New-Object -ComObject WindowsInstaller.Installer -ErrorAction Stop
        $database = $installer.OpenDatabase($Path, 0)
        $query = ("SELECT {0}Value{0} FROM {0}Property{0} WHERE {0}Property{0} = 'ProductVersion'" -f [char]96)
        $view = $database.OpenView($query)
        # Suppress COM method return values: empty results can otherwise
        # become extra pipeline items surrounding the version string.
        [void]$view.Execute()
        $record = $view.Fetch()
        if ($null -ne $record) {
            $version = ([string]$record.StringData(1)).Trim()
            if ($version -match '^\d+(?:\.\d+){1,3}$') { return $version }
        }
    }
    catch {
        Write-Verbose "MSI ProductVersion could not be read from '$Path': $($_.Exception.Message)"
    }
    finally {
        if ($view) { try { [void]$view.Close() } catch { } }
        foreach ($comObject in @($record,$view,$database,$installer)) {
            if ($null -ne $comObject -and [System.Runtime.InteropServices.Marshal]::IsComObject($comObject)) {
                try { [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($comObject) } catch { }
            }
        }
    }
}

function Get-OSDAppAdobePatchVersion {
    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return }

    $archive = $null
    try {
        Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
        # Opening the ZIP central directory does not unpack the multi-GB payload.
        $archive = [System.IO.Compression.ZipFile]::OpenRead($Path)
        $setupIni = @($archive.Entries |
            Where-Object { $_.FullName -match '(?i)(^|/)setup\.ini$' -and $_.Length -le 1MB } |
            Select-Object -First 1)
        if ($setupIni.Count -eq 0) { return }

        $reader = [System.IO.StreamReader]::new($setupIni[0].Open())
        try { $ini = $reader.ReadToEnd() }
        finally { $reader.Dispose() }

        $patch = [regex]::Match($ini,'(?im)^\s*PATCH\s*=\s*(?<patch>[^\r\n;]+)')
        if (-not $patch.Success) { return }
        $patchName = [System.IO.Path]::GetFileName($patch.Groups['patch'].Value.Trim().Trim('"'))
        # Example: AcrobatDCx64Upd2600221931.msp -> 26.002.21931
        $match = [regex]::Match($patchName,'(?i)^AcrobatDC(?:x64)?Upd(?<major>\d{2})(?<minor>\d{3})(?<build>\d{5})\.msp$')
        if ($match.Success) {
            return '{0}.{1}.{2}' -f $match.Groups['major'].Value,$match.Groups['minor'].Value,$match.Groups['build'].Value
        }
    }
    catch {
        Write-Verbose "Adobe Acrobat patch version could not be read from '$Path': $($_.Exception.Message)"
    }
    finally {
        if ($archive) { $archive.Dispose() }
    }
}

function Get-OSDAppCachedPackageVersion {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$Id,
        [Parameter(Mandatory)][string]$CacheEntryPath
    )

    $version = $null
    $source = $null
    switch ($Id) {
        { $_ -in @('GoogleChromeEnterprise','CiscoWebex','MozillaFirefoxEnterprise') } {
            $version = Get-OSDAppMsiProductVersion -Path (Join-Path $CacheEntryPath 'Package.msi')
            if ($version) { $source = 'MsiProductVersion' }
            break
        }
        'AdobeAcrobatUnified' {
            $version = Get-OSDAppAdobePatchVersion -Path (Join-Path $CacheEntryPath 'Package.zip')
            if ($version) { $source = 'AdobePatchFileName' }
            break
        }
    }

    [pscustomobject]@{
        Version = if ($version) { ([string]$version).Trim() } else { $null }
        VersionSource = $source
    }
}