private/Get-ManifestDetails.ps1

<#
    .SYNOPSIS
        Retrieves details from an MSIX or APPV package manifest.
 
    .DESCRIPTION
        The Get-ManifestDetail function retrieves details from an MSIX or APPV package manifest.
 
    .PARAMETER Filename
        Specifies the path to the package.
 
    .NOTES
        Function : Get-ManifestDetail
        Author : John Billekens
        Copyright: Copyright (c) AppVentiX
        Version : 1.1
#>

function Get-ManifestDetail {
    [CmdletBinding()]
    Param (
        [ValidateScript({
                try {
                    if ((Test-Path -Path "$_") -and ("$_" -like '*.msix' -or "$_" -like '*.appv')) {
                        $true
                    } else {
                        Throw [System.Management.Automation.ItemNotFoundException] "The parameter must be a valid and accessable *.msix or *.appv file!"
                    }
                } catch {
                    Throw [System.Management.Automation.ItemNotFoundException] "The parameter must be a valid and accessable *.msix or *.appv file!"
                }

            })]
        [System.IO.FileInfo]$Filename
    )
    $packageType = ($Filename.Name.Split('.')[-1]).ToUpper()
    #Retrieve the manifest from the package
    [xml]$manifestXml = Get-AppXManifest -Filename $Filename
    #Gather the package data
    $appManifest = @{}
    $appManifest.Name = $manifestXml.Package.Identity.Name
    $appManifest.Version = $manifestXml.Package.Identity.Version
    $appManifest.Publisher = $manifestXml.Package.Identity.Publisher
    $appManifest.PublisherID = Get-PublisherId -Publisher $appManifest.Publisher
    switch ($packageType) {
        "MSIX" {
            $appManifest.Architecture = $manifestXml.Package.Identity.ProcessorArchitecture
            $appManifest.PackageFullName = Get-PackageFullName @appManifest
        }
        "APPV" {
            $appManifest.PackageId = $manifestXml.Package.Identity.PackageId
            $appManifest.VersionId = $manifestXml.Package.Identity.VersionId
        }
        Default {
            Write-Warning "Unknown package type: $packageType"
        }
    }
    $appManifest.Type = $packageType
    $appManifest.FamilyName = '{0}_{1}' -f $manifestXml.Package.Identity.Name, $appManifest.PublisherID
    $appManifest.DisplayName = $manifestXml.Package.Properties.DisplayName
    $appManifest.PublisherDisplayName = $manifestXml.Package.Properties.PublisherDisplayName
    $appManifest.LastUpdated = ([DateTime]$Filename.LastWriteTime).ToString("o").Substring(0, 27)
    #Gather the application data
    $appManifest.Applications = @()
    #Get the package files, treat the package as zip file to extract file entries
    $packageFiles = [IO.Compression.ZipFile]::OpenRead($Filename)
    $packageFilesEntries = $packageFiles.Entries
    #Release the package as soon as possible to remove the lock on the file
    $packageFiles.Dispose()
    $appvNumber = 0
    ForEach ($application in $manifestXml.Package.Applications.Application) {
        #Gather the application data
        $app = @{}
        switch ($packageType) {
            "MSIX" {
                $app.Id = $application.Id
                $app.AppUserModelID = '{0}!{1}' -f $appManifest.FamilyName, $application.Id
                $app.Executable = $application.Executable
                $app.Description = $application.VisualElements.Description
                $app.FriendlyName = $application.VisualElements.DisplayName
                $app.AppVentiXExecutable = '{0}#{1}' -f $application.Id, $application.Executable
                #Select the icon image, this is a bit tricky because the icon image can be in different locations
                if (-Not [String]::IsNullOrEmpty($($application.VisualElements.Square44x44Logo))) {
                    $imageFilename = Split-Path -Path $application.VisualElements.Square44x44Logo -Leaf
                    $imageExtension = $imageFilename.Split(".")[-1]
                    $imageBase = $imageFilename.Replace(".$($imageExtension)", $null)
                    $imagePath = Split-Path -Path $application.VisualElements.Square44x44Logo -Parent
                    $iconImageNamePath = $packageFilesEntries | Where-Object { $_.Fullname -like "*$($imagePath)/$($imageBase)*.$($imageExtension)" } | Select-Object -ExpandProperty FullName
                    if ([String]::IsNullOrEmpty($iconImageNamePath) -or $iconImageNamePath.Count -gt 1) {
                        $iconImageNamePath = $packageFilesEntries | Where-Object { $_.Fullname -like "*$($imagePath)/$($imageBase)*scale-100*.$($imageExtension)" } | Select-Object -ExpandProperty FullName
                    }
                }
                if ([String]::IsNullOrEmpty($iconImageNamePath) -or $iconImageNamePath.Count -gt 1) {
                    $iconImageNamePath = $packageFilesEntries | Where-Object { $_.FullName -like "*Assets*$($application.Id)Square44x44*" } | Select-Object -ExpandProperty FullName
                }
                if ($iconImageNamePath.Count -gt 1) {
                    $iconImageNamePath = $iconImageNamePath | Where-Object { $_ -like "*scale-100*" }
                }
                if ([String]::IsNullOrEmpty($iconImageNamePath)) {
                    $iconImageNamePath = $packageFilesEntries | Where-Object { $_.FullName -like '*Square44x44Logo.*' -or $_.FullName -like '*Square44x44Logo.scale-100.*' } | Select-Object -ExpandProperty FullName | Select-Object -First 1 | Select-Object -ExpandProperty FullName
                    Write-Warning "Selected a random icon: $($iconImageNamePath)"
                }
                if ([String]::IsNullOrEmpty($iconImageNamePath)) {
                    Write-Warning "Cannot set an application image (path), none found"
                }
                $app.Iconpath = $iconImageNamePath.Replace('/', '\')
                $app.IconWindowsPath = [io.path]::combine('C:\Program Files\WindowsApps', $appManifest.PackageFullName, $iconImageNamePath.Replace('/', '\'))
                $app.IconPackagePath = [io.path]::combine($appManifest.PackageFullName, $iconImageNamePath.Replace('/', '\'))
            }
            "APPV" {
                $app.Number = $appvNumber
                $app.Executable = $application.Target
                $app.Id = $application.Id
                $app.Description = $application.VisualElements.Description
                $app.FriendlyName = $application.VisualElements.Name
                $app.Version = $application.VisualElements.Version
                $app.Iconpath = $application.Target.Replace('[{', $null).Replace('}]', $null)
                $app.IconWindowsPath = [io.path]::combine('C:\ProgramData\App-V', $appManifest.PackageId, $appManifest.VersionId, 'Root\VFS', $app.Iconpath)
                $appvNumber++
            }
            Default {
                Write-Warning "Unknown package type: $packageType"
            }
        }
        $appManifest.Applications += [PSCustomObject]$app.Clone()
    }
    #Clear the XML data
    $manifestXml.RemoveAll()
    #Return all the gathered data
    return [PSCustomObject]$appManifest
}