param([Parameter(Mandatory=$true)][string]$OutputPath, [string]$CatalogPath) $ErrorActionPreference='Stop' . (Join-Path $PSScriptRoot 'Catalog.ps1') $output=[IO.Path]::GetFullPath($OutputPath) if ([IO.File]::Exists($output)) { throw 'Output already exists. Choose a new ZIP name.' } $catalog=$null if ($CatalogPath) { $catalog=Read-PanelCatalog ([IO.Path]::GetFullPath($CatalogPath)) } $staging=Join-Path ([IO.Path]::GetTempPath()) ('panel-kit-'+[Guid]::NewGuid().ToString('N')) [IO.Directory]::CreateDirectory($staging) | Out-Null try { if ($env:OS -eq 'Windows_NT') { $acl=New-Object Security.AccessControl.DirectorySecurity $sid=[Security.Principal.WindowsIdentity]::GetCurrent().User; $acl.SetOwner($sid); $acl.SetAccessRuleProtection($true,$false) foreach ($principal in @($sid,[Security.Principal.SecurityIdentifier]::new('S-1-5-18'))) { $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new($principal,'FullControl','ContainerInherit,ObjectInherit','None','Allow')) } Set-Acl -LiteralPath $staging -AclObject $acl } else { & chmod 700 -- $staging; if ($LASTEXITCODE -ne 0) { throw 'Cannot protect staging directory.' } } $files=@('Install.cmd','Install.ps1','Catalog.ps1','Build-Package.ps1','Test-Catalog.ps1','README.txt','connections.example.json') foreach ($name in $files) { Copy-Item -LiteralPath (Join-Path $PSScriptRoot $name) -Destination $staging } # CMD uses explicit UTF-8 file reads for PowerShell. Ship conventional CRLF batch text. $cmd=Join-Path $staging 'Install.cmd' [IO.File]::WriteAllText($cmd, ([IO.File]::ReadAllText($cmd) -replace '\r?\n',"`r`n"),[Text.Encoding]::ASCII) if ($catalog) { Write-PanelCatalog (Join-Path $staging 'connections.json') $catalog } $hashes=@() foreach ($file in Get-ChildItem -LiteralPath $staging -File | Sort-Object Name) { $hashes += ((Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant()+' '+$file.Name) } [IO.File]::WriteAllText((Join-Path $staging 'SHA256SUMS.txt'),($hashes -join "`r`n")+"`r`n",[Text.Encoding]::ASCII) Add-Type -AssemblyName System.IO.Compression.FileSystem [IO.Compression.ZipFile]::CreateFromDirectory($staging,$output) if ($env:OS -ne 'Windows_NT') { & chmod 600 -- $output; if ($LASTEXITCODE -ne 0) { throw 'Cannot protect output ZIP.' } } Write-Output ('Created '+$output) } finally { if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Recurse -Force } }