39 lines
5.3 KiB
PowerShell
39 lines
5.3 KiB
PowerShell
#Requires -Version 5.1
|
|
[CmdletBinding()]param([string]$OutputDirectory,[string]$Version='0.0.1')
|
|
Set-StrictMode -Version Latest;$ErrorActionPreference='Stop'
|
|
if($Version-notmatch'^\d+\.\d+\.\d+$'){throw 'Version must use major.minor.patch.'}
|
|
$root=[IO.Path]::GetFullPath($PSScriptRoot);if(-not$OutputDirectory){$OutputDirectory=Join-Path $root ('dist\ms-private-'+$Version+'-final-'+(Get-Date -Format yyyyMMdd))};$output=[IO.Path]::GetFullPath($OutputDirectory);[IO.Directory]::CreateDirectory($output)|Out-Null
|
|
$target=Join-Path $output ("ms-private-$Version.exe");if(Test-Path -LiteralPath $target){throw 'Executable already exists. Use an empty output directory.'}
|
|
$dotnet=(Get-Command dotnet.exe -CommandType Application -ErrorAction Stop).Source
|
|
$temp=Join-Path ([IO.Path]::GetTempPath()) ('ms-private-native-'+[guid]::NewGuid().ToString('N'));[IO.Directory]::CreateDirectory($temp)|Out-Null
|
|
try{
|
|
$payload=Join-Path $temp 'ms-private.payload.zip';$entries=[Collections.Generic.List[object]]::new()
|
|
$rootScripts=@('Accounts.ps1','Cleanup.ps1','Hardware.ps1','Home.ps1','Install-Apps.ps1','Lock-Event.ps1','Lock.ps1','Manage-Apps.ps1','ms-private-GUI.ps1','ms-private.ps1','Network.ps1','Offline-Updates.ps1','Preset.ps1','Recall.ps1','Security.ps1','Services.ps1')
|
|
$files=@($rootScripts|ForEach-Object{Get-Item -LiteralPath (Join-Path $root $_)})
|
|
foreach($folder in @('src','config')){$files+=@(Get-ChildItem -LiteralPath (Join-Path $root $folder) -Recurse -File -Force)}
|
|
foreach($doc in @('docs\HOME-GUIDE.md','docs\PRIVACY.md','docs\ANONYMITY.md','docs\TOOL-BREAKDOWN.md','docs\OFFLINE-UPDATES.md','docs\NATIVE-API.md','docs\ROADMAP.md')){$files+=Get-Item -LiteralPath (Join-Path $root $doc)}
|
|
Add-Type -AssemblyName System.IO.Compression;Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$zip=[IO.Compression.ZipFile]::Open($payload,[IO.Compression.ZipArchiveMode]::Create)
|
|
try{
|
|
foreach($file in @($files|Sort-Object FullName)){
|
|
if(-not$file.FullName.StartsWith($root+'\',[StringComparison]::OrdinalIgnoreCase)-or($file.Attributes-band[IO.FileAttributes]::ReparsePoint)){throw 'Unsafe executable payload input.'}
|
|
$relative=$file.FullName.Substring($root.Length+1).Replace('\','/');$hash=(Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant();$entries.Add([ordered]@{Path=$relative;Length=[long]$file.Length;Sha256=$hash})
|
|
[IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip,$file.FullName,$relative,[IO.Compression.CompressionLevel]::Optimal)|Out-Null
|
|
}
|
|
$manifest=[ordered]@{Schema=1;Version=$Version;EntryPoint='ms-private-GUI.ps1';Files=@($entries)}|ConvertTo-Json -Depth 5 -Compress
|
|
$entry=$zip.CreateEntry('payload.manifest.json',[IO.Compression.CompressionLevel]::Optimal);$stream=$entry.Open();try{$writer=[IO.StreamWriter]::new($stream,[Text.UTF8Encoding]::new($false));try{$writer.Write($manifest)}finally{$writer.Dispose()}}finally{$stream.Dispose()}
|
|
}finally{$zip.Dispose()}
|
|
$appManifest=Join-Path $temp 'app.manifest';$appManifestText=[IO.File]::ReadAllText((Join-Path $root 'native\MsPrivate.Launcher\app.manifest'));$appManifestText=[regex]::Replace($appManifestText,'(?<=<assemblyIdentity version=")[^"]+',($Version+'.0'));[IO.File]::WriteAllText($appManifest,$appManifestText,[Text.UTF8Encoding]::new($false))
|
|
$testObj=Join-Path $temp 'test-obj\';$testBin=Join-Path $temp 'test-bin\'
|
|
& $dotnet run --project (Join-Path $root 'native\MsPrivate.Launcher.Tests\MsPrivate.Launcher.Tests.csproj') -c Release --nologo "-p:BaseIntermediateOutputPath=$testObj" "-p:BaseOutputPath=$testBin";if($LASTEXITCODE-ne0){throw 'Native launcher tests failed.'}
|
|
$publish=Join-Path $temp 'publish';$arguments=@('publish',(Join-Path $root 'native\MsPrivate.Launcher\MsPrivate.Launcher.csproj'),'-c','Release','-r','win-x64','--self-contained','true','--source','https://api.nuget.org/v3/index.json','--nologo','-o',$publish,"-p:PayloadZip=$payload","-p:ApplicationManifest=$appManifest","-p:Version=$Version","-p:AssemblyVersion=$Version.0","-p:FileVersion=$Version.0","-p:BaseIntermediateOutputPath=$(Join-Path $temp 'obj\')","-p:BaseOutputPath=$(Join-Path $temp 'bin\')")
|
|
& $dotnet @arguments;if($LASTEXITCODE-ne0){throw 'Single-file publish failed.'}
|
|
$published=@(Get-ChildItem -LiteralPath $publish -File);$exe=@($published|Where-Object Extension -eq '.exe');if($exe.Count-ne1-or$published.Count-ne1){throw "Expected one executable; publish produced $($published.Count) files."}
|
|
Copy-Item -LiteralPath $exe[0].FullName -Destination $target
|
|
$hash=(Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash.ToLowerInvariant();[IO.File]::WriteAllText((Join-Path $output ("ms-private-$Version.exe.sha256")),($hash+' '+[IO.Path]::GetFileName($target)+[Environment]::NewLine),[Text.UTF8Encoding]::new($false))
|
|
& (Join-Path $root 'tests\Inspect-Executable.ps1') -Path $target -Version $Version
|
|
$sumLines=@(Get-ChildItem -LiteralPath $output -File|Where-Object{$_.Extension-in@('.exe','.zip','.apbx')}|Sort-Object Name|ForEach-Object{((Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant())+' '+$_.Name})
|
|
[IO.File]::WriteAllText((Join-Path $output 'SHA256SUMS.txt'),(($sumLines-join[Environment]::NewLine)+[Environment]::NewLine),[Text.UTF8Encoding]::new($false))
|
|
Write-Output "Created $target ($($entries.Count) embedded files). SHA256: $hash"
|
|
}finally{if(Test-Path -LiteralPath $temp){[IO.Directory]::Delete($temp,$true)}}
|