Private/Get-Win32IntuneWinMetadata.ps1

function Get-Win32IntuneWinMetadata {
    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$IntuneWinPath
    )

    # System.IO.Compression.ZipFile is available by default on PowerShell 7.
    $zip = [System.IO.Compression.ZipFile]::OpenRead($IntuneWinPath)
    try {
        # ── Read Detection.xml ──────────────────────────────────────────────────
        # Actual path produced by IntuneWinAppUtil.exe: IntuneWinPackage/Metadata/Detection.xml
        $metaEntry = $zip.Entries | Where-Object { $_.FullName -eq 'IntuneWinPackage/Metadata/Detection.xml' } | Select-Object -First 1
        if (-not $metaEntry) {
            throw "Detection.xml not found inside .intunewin archive: $IntuneWinPath"
        }

        $stream  = $metaEntry.Open()
        $reader  = [System.IO.StreamReader]::new($stream)
        $xmlText = $reader.ReadToEnd()
        $reader.Close()
        $stream.Close()

        [xml]$xml = $xmlText
        $appInfo  = $xml.ApplicationInfo
        $encInfo  = $appInfo.EncryptionInfo

        # ── Find inner encrypted content file ─────────────────────────────────────
        # IntuneWinAppUtil.exe always names the inner file IntunePackage.intunewin
        $innerEntry = $zip.Entries |
            Where-Object { $_.FullName -eq 'IntuneWinPackage/Contents/IntunePackage.intunewin' } |
            Select-Object -First 1

        # Fallback: any .intunewin file inside Contents/ (future-proofing)
        if (-not $innerEntry) {
            $innerEntry = $zip.Entries |
                Where-Object { $_.FullName -like 'IntuneWinPackage/Contents/*.intunewin' } |
                Select-Object -First 1
        }

        if (-not $innerEntry) {
            throw "Inner content file not found in .intunewin archive: $IntuneWinPath"
        }

        return @{
            FileName             = $appInfo.FileName
            SetupFile            = $appInfo.SetupFile
            UnencryptedSize      = [long]$appInfo.UnencryptedContentSize
            EncryptionKey        = $encInfo.EncryptionKey
            MacKey               = $encInfo.MacKey
            InitializationVector = $encInfo.InitializationVector
            Mac                  = $encInfo.Mac
            FileDigest           = $encInfo.FileDigest
            FileDigestAlgorithm  = $encInfo.FileDigestAlgorithm
            ProfileIdentifier    = $encInfo.ProfileIdentifier
            InnerEntryName       = $innerEntry.FullName
            SizeEncrypted        = $innerEntry.Length   # uncompressed length = actual encrypted file size
        }
    }
    finally {
        $zip.Dispose()
    }
}