AppHandling/Extract-AppFileToFolder.ps1
<#
.Synopsis Extract the content of an App File to a Folder .Description .Parameter AppFilename Path of the application file .Parameter AppFolder Path of the folder in which the application File will be unpacked. If this folder exists, the content will be deleted. Default is $appFile.source. .Parameter GenerateAppJson Add this switch to generate an sample app.json file in the AppFolder, containing the manifest properties. .Example Extract-AppFileToFolder -appFilename c:\temp\baseapp.app #> function Extract-AppFileToFolder { Param ( [string] $appFilename, [string] $appFolder = "$($appFilename).source", [switch] $generateAppJson ) if ("$appFolder" -eq "$hostHelperFolder" -or "$appFolder" -eq "$hostHelperFolder\") { throw "The folder specified in ObjectsFolder will be erased, you cannot specify $hostHelperFolder" } Write-Host "Extracting $appFilename" if (Test-Path $appFolder -PathType Container) { Get-ChildItem -Path $appFolder -Include * | Remove-Item -Recurse -Force } else { New-Item -Path $appFolder -ItemType Directory -Force -ErrorAction Ignore | Out-Null } try { $filestream = [System.IO.File]::OpenRead($appFileName) $binaryReader = [System.IO.BinaryReader]::new($filestream) $magicNumber1 = $binaryReader.ReadUInt32() $metadataSize = $binaryReader.ReadUInt32() $metadataVersion = $binaryReader.ReadUInt32() $packageId = [Guid]::new($binaryReader.ReadBytes(16)) $contentLength = $binaryReader.ReadInt64() $magicNumber2 = $binaryReader.ReadUInt32() if ($magicNumber1 -ne 0x5856414E -or $magicNumber2 -ne 0x5856414E -or $metadataVersion -gt 2 -or $filestream.Position + $contentLength -gt $filestream.Length) { throw "Unsupported package format" } Add-Type -Assembly System.IO.Compression Add-Type -Assembly System.IO.Compression.FileSystem $content = $binaryReader.ReadBytes($contentLength) $memoryStream = [System.IO.MemoryStream]::new($content) $zipArchive = [System.IO.Compression.ZipArchive]::new($memoryStream, [System.IO.Compression.ZipArchiveMode]::Read) $prevdir = "" $zipArchive.Entries | ForEach-Object { $fullname = Join-Path $appFolder ([Uri]::UnescapeDataString($_.FullName)) $dir = [System.IO.Path]::GetDirectoryName($fullname) if ($dir -ne $prevdir) { if (-not (Test-Path $dir -PathType Container)) { New-Item -Path $dir -ItemType Directory | Out-Null } } $prevdir = $dir [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $fullname) } } finally { $binaryReader.Close() $filestream.Close() } if ($generateAppJson) { #Set-StrictMode -Off $manifest = [xml](Get-Content -path (Join-Path $appFolder "NavxManifest.xml")) $appJson = [ordered]@{ "id" = $manifest.Package.App.Id "name" = $manifest.Package.App.Name "publisher" = $manifest.Package.App.Publisher "version" = $manifest.Package.App.Version "brief" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Brief" } | % { $_.Value } )" "description" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Description" } | % { $_.Value } )" "platform" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Platform" } | % { $_.Value } )" "showMyCode" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "ShowMyCode" } | % { $_.Value } )" -eq "True" "runtime" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Runtime" } | % { $_.Value } )" "logo" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Logo" } | % { $_.Value } )".TrimStart('/') "url" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Url" } | % { $_.Value } )" "EULA" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "EULA" } | % { $_.Value } )" "privacyStatement" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "PrivacyStatement" } | % { $_.Value } )" "help" = "$($manifest.Package.App.Attributes | Where-Object { $_.name -eq "Help" } | % { $_.Value } )" "screenshots" = @() "dependencies" = @() "idRanges" = @() "features" = @() } $manifest.Package.ChildNodes | Where-Object { $_.name -eq "Dependencies" } | % { $_.GetEnumerator() | % { $appJson.dependencies += [ordered]@{ "appId" = $_.Id "publisher" = $_.publisher "name" = $_.name "version" = $_.minVersion } } } $manifest.Package.ChildNodes | Where-Object { $_.name -eq "IdRanges" } | % { $_.GetEnumerator() | % { $appJson.idRanges += [ordered]@{ "from" = [Int]::Parse($_.MinObjectId) "to" = [Int]::Parse($_.MaxObjectId) } } } $manifest.Package.ChildNodes | Where-Object { $_.name -eq "Features" } | % { $_.GetEnumerator() | % { $feature = $_.'#text' 'TranslationFile','GenerateCaptions' | % { if ($feature -eq $_) { $appJson.features += $_ } } } } $appJson | convertTo-json | Set-Content -Path (Join-Path $appFolder "app.json") Set-StrictMode -Version 2.0 } } Export-ModuleMember -Function Extract-AppFileToFolder |