Private/Read-IntuneWinPackage.ps1
|
function Read-IntuneWinPackage { <# .SYNOPSIS Reads the metadata of a .intunewin package and extracts its encrypted content. .DESCRIPTION A .intunewin file is a zip archive with two folders: Contents, which holds the encrypted package (IntunePackage.intunewin), and Metadata, which holds Detection.xml with the file encryption information (https://learn.microsoft.com/troubleshoot/mem/intune/app-management/develop-deliver-working-win32-app-via-intune). This function reads Detection.xml and, with -ExtractTo, copies the encrypted package to a file. #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory)] [string]$Path, [string]$ExtractTo ) Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop $FullPath = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath $Archive = [System.IO.Compression.ZipFile]::OpenRead($FullPath) try { $Entries = @($Archive.Entries) $DetectionEntry = $Entries | Where-Object { $_.FullName.Replace('\', '/') -like '*Metadata/Detection.xml' } | Select-Object -First 1 $ContentEntry = $Entries | Where-Object { $_.FullName.Replace('\', '/') -like '*Contents/*.intunewin' } | Select-Object -First 1 if (-not $DetectionEntry -or -not $ContentEntry) { throw "'$Path' is not a .intunewin package: Metadata/Detection.xml or the encrypted content in Contents/ is missing." } $Reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $DetectionEntry.Open() try { [xml]$Detection = $Reader.ReadToEnd() } finally { $Reader.Dispose() } $Info = $Detection.ApplicationInfo $Encryption = $Info.EncryptionInfo if (-not $Info -or -not $Encryption) { throw "Detection.xml in '$Path' does not contain ApplicationInfo/EncryptionInfo." } $EncryptedPath = $null if ($ExtractTo) { $EncryptedPath = $ExtractTo $Source = $ContentEntry.Open() try { $Target = [System.IO.File]::Create($EncryptedPath) try { $Source.CopyTo($Target) } finally { $Target.Dispose() } } finally { $Source.Dispose() } } # Present for MSI setup files: MsiProductCode, MsiProductVersion, MsiUpgradeCode, MsiPublisher ... $MsiInfo = $null if ($Info.MsiInfo) { $MsiInfo = [ordered]@{} foreach ($Node in @($Info.MsiInfo.ChildNodes | Where-Object { $_.NodeType -eq 'Element' })) { $MsiInfo[$Node.LocalName] = $Node.InnerText } $MsiInfo = [PSCustomObject]$MsiInfo } [PSCustomObject]@{ Name = [string]$Info.Name FileName = [string]$Info.FileName SetupFile = [string]$Info.SetupFile UnencryptedContentSize = [int64]$Info.UnencryptedContentSize EncryptedContentSize = [int64]$ContentEntry.Length EncryptedContentPath = $EncryptedPath ToolVersion = [string]$Info.ToolVersion MsiInfo = $MsiInfo EncryptionInfo = [ordered]@{ encryptionKey = [string]$Encryption.EncryptionKey macKey = [string]$Encryption.MacKey initializationVector = [string]$Encryption.InitializationVector mac = [string]$Encryption.Mac profileIdentifier = [string]$Encryption.ProfileIdentifier fileDigest = [string]$Encryption.FileDigest fileDigestAlgorithm = [string]$Encryption.FileDigestAlgorithm } } } finally { $Archive.Dispose() } } |