PrintToVeraeTimeStamp/platform/windows/scripts/build-tray-startmenu.ps1
George Lambert 48da24a661 feat: 2026 brand UI — statuslang, tray/menubar, CERT pdf, site kit
- Brand receipt status strings (statuslang) for notify/queue
- Windows tray + Start Menu/Startup install; macOS menubar helper
- CERT-01 plum/gold PDF + multihash/blake3 when present
- printit.verae.ai brand kit, queue page, customer-auth helper
- verae-print pending/tray-status/menubar commands
2026-10-13 21:11:32 -04:00

241 lines
9.6 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Practical Start Menu + Startup tray packaging (PT-W3) without WiX/NSIS/MSI.
Stamps package version from internal/job.HelperVersion (A4).
.DESCRIPTION
Creates user-level shortcuts under:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Verae\
and (unless -NoStartup) a login Startup shortcut via install-tray-startup.ps1:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\Verae Tray.lnk
This is intentionally a lightweight presence stub — not a commercial MSI.
IPP POST is untouched; shortcuts only launch the tray (GET /status) or open
the loopback queue page.
Full product installers (NSIS installer-windows.nsi, future WiX MSI) remain
separate. If WiX Toolset / candle+light are not installed, this script is the
supported path for Start Menu + Startup tray presence.
.PARAMETER Uninstall
Remove Verae Start Menu folder shortcuts and optional Startup shortcut.
.PARAMETER Addr
Helper loopback host:port (default 127.0.0.1:8631 or $env:VERAE_IPP_ADDR).
.PARAMETER TrayScript
Path to verae-tray.ps1. Default: same folder as this script.
.PARAMETER VeraePrint
Optional path to verae-print.exe. When found, adds Setup signing key and
Start print helper shortcuts. Auto-detected next to scripts or on PATH.
.PARAMETER NoStartup
Skip Startup-folder shortcut (Start Menu only).
.PARAMETER StartMenuFolder
Start Menu Programs subfolder name (default Verae).
.EXAMPLE
powershell -NoProfile -ExecutionPolicy Bypass -File build-tray-startmenu.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File build-tray-startmenu.ps1 -Uninstall
verae-print menubar --install # Startup only; this script adds Start Menu folder
#>
param(
[switch]$Uninstall,
[string]$Addr = $(if ($env:VERAE_IPP_ADDR) { $env:VERAE_IPP_ADDR } else { "127.0.0.1:8631" }),
[string]$TrayScript = "",
[string]$VeraePrint = "",
[switch]$NoStartup,
[string]$StartMenuFolder = "Verae"
)
$ErrorActionPreference = "Stop"
# Package version = internal/job.HelperVersion (A4 packaging metadata).
$common = Join-Path $PSScriptRoot "common.ps1"
if (Test-Path -LiteralPath $common) { . $common }
if (Get-Command Get-VeraePackageVersion -ErrorAction SilentlyContinue) {
$PackageVersion = Get-VeraePackageVersion
} elseif ($env:VERSION -and $env:VERSION.Trim()) {
$PackageVersion = $env:VERSION.Trim()
} else {
$PackageVersion = "0.3.6"
}
function Get-ProgramsDir {
$base = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs"
if (-not (Test-Path -LiteralPath $base)) {
New-Item -ItemType Directory -Force -Path $base | Out-Null
}
return $base
}
function Get-PsExe {
$psExe = Join-Path $env:WINDIR "System32\WindowsPowerShell\v1.0\powershell.exe"
if (-not (Test-Path $psExe)) { $psExe = "powershell.exe" }
return $psExe
}
function New-Lnk {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$Target,
[string]$Arguments = "",
[string]$WorkDir = "",
[string]$Description = "",
[int]$WindowStyle = 1
)
$dir = Split-Path -Parent $Path
if ($dir) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
$wsh = New-Object -ComObject WScript.Shell
try {
$sc = $wsh.CreateShortcut($Path)
$sc.TargetPath = $Target
if ($Arguments) { $sc.Arguments = $Arguments }
if ($WorkDir) { $sc.WorkingDirectory = $WorkDir }
if ($Description) { $sc.Description = $Description }
$sc.WindowStyle = $WindowStyle
$sc.Save()
} finally {
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($wsh)
}
Write-Host " + $Path"
}
function Find-VeraePrint([string]$Hint) {
if ($Hint -and (Test-Path -LiteralPath $Hint)) {
return (Resolve-Path -LiteralPath $Hint).Path
}
$candidates = @(
(Join-Path $PSScriptRoot "..\..\..\bin\verae-print.exe"),
(Join-Path $PSScriptRoot "..\bin\verae-print.exe"),
(Join-Path $PSScriptRoot "verae-print.exe"),
(Join-Path (Split-Path -Parent $PSScriptRoot) "bin\verae-print.exe")
)
foreach ($c in $candidates) {
if (Test-Path -LiteralPath $c) { return (Resolve-Path -LiteralPath $c).Path }
}
$cmd = Get-Command verae-print.exe -ErrorAction SilentlyContinue
if ($cmd -and $cmd.Source) { return $cmd.Source }
$cmd2 = Get-Command verae-print -ErrorAction SilentlyContinue
if ($cmd2 -and $cmd2.Source) { return $cmd2.Source }
return ""
}
$Programs = Get-ProgramsDir
$VeraeMenu = Join-Path $Programs $StartMenuFolder
$StartupInstaller = Join-Path $PSScriptRoot "install-tray-startup.ps1"
if ($Uninstall) {
Write-Host "Removing Start Menu folder: $VeraeMenu"
if (Test-Path -LiteralPath $VeraeMenu) {
Get-ChildItem -LiteralPath $VeraeMenu -Filter "*.lnk" -ErrorAction SilentlyContinue |
ForEach-Object { Remove-Item -LiteralPath $_.FullName -Force; Write-Host " - $($_.FullName)" }
# Remove folder only when empty (do not wipe other products' shortcuts).
$left = @(Get-ChildItem -LiteralPath $VeraeMenu -Force -ErrorAction SilentlyContinue)
if ($left.Count -eq 0) {
Remove-Item -LiteralPath $VeraeMenu -Force -ErrorAction SilentlyContinue
Write-Host " removed empty folder"
} else {
Write-Host " left non-empty folder ($($left.Count) items)"
}
} else {
Write-Host " (folder not present)"
}
if (-not $NoStartup -and (Test-Path -LiteralPath $StartupInstaller)) {
& $StartupInstaller -Uninstall
} else {
$startupLnk = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\Verae Tray.lnk"
if (Test-Path -LiteralPath $startupLnk) {
Remove-Item -LiteralPath $startupLnk -Force
Write-Host "Removed Startup shortcut: $startupLnk"
}
}
Write-Host "Done. IPP path unchanged. Hold ids are never evidence."
exit 0
}
if (-not $TrayScript) {
$TrayScript = Join-Path $PSScriptRoot "verae-tray.ps1"
}
if (-not (Test-Path -LiteralPath $TrayScript)) {
Write-Error "verae-tray.ps1 not found: $TrayScript"
}
$TrayScript = (Resolve-Path -LiteralPath $TrayScript).Path
$TrayDir = Split-Path -Parent $TrayScript
$psExe = Get-PsExe
$printExe = Find-VeraePrint $VeraePrint
Write-Host "Start Menu folder: $VeraeMenu"
Write-Host " Addr: $Addr"
Write-Host " Tray: $TrayScript"
Write-Host " Version: $PackageVersion (internal/job.HelperVersion)"
if ($printExe) { Write-Host " verae-print: $printExe" } else { Write-Host " verae-print: (not found — tray/queue shortcuts only)" }
# --- Start Menu\Programs\Verae ---
$trayArgs = "-NoProfile -ExecutionPolicy Bypass -STA -WindowStyle Hidden -File `"$TrayScript`" -Addr $Addr"
New-Lnk -Path (Join-Path $VeraeMenu "Verae Tray.lnk") `
-Target $psExe -Arguments $trayArgs -WorkDir $TrayDir -WindowStyle 7 `
-Description "Verae Timestamping tray v$PackageVersion — polls GET /status; Open queue → /queue. Hold id ≠ evidence."
$queueUrl = "http://$Addr/queue"
# Prefer verae-print tray-status --open when available (no default browser .url needed).
if ($printExe) {
New-Lnk -Path (Join-Path $VeraeMenu "Verae - Open print job queue.lnk") `
-Target $printExe -Arguments "tray-status --open --addr $Addr" `
-WorkDir (Split-Path -Parent $printExe) `
-Description "Open loopback print job queue (GET /queue). Hold id ≠ evidence."
New-Lnk -Path (Join-Path $VeraeMenu "Verae - Setup signing key.lnk") `
-Target $printExe -Arguments "setup" `
-WorkDir (Split-Path -Parent $printExe) `
-Description "Create or paste an xVerae- signing key (portal / login)."
New-Lnk -Path (Join-Path $VeraeMenu "Verae - Start print helper.lnk") `
-Target $printExe -Arguments "serve" `
-WorkDir (Split-Path -Parent $printExe) `
-Description "Start IPP helper + loopback GET /status and /queue."
} else {
# URL shortcut when binary is absent (dev tree / scripts-only layout).
$urlPath = Join-Path $VeraeMenu "Verae - Open print job queue.url"
New-Item -ItemType Directory -Force -Path $VeraeMenu | Out-Null
@(
"[InternetShortcut]"
"URL=$queueUrl"
) | Set-Content -LiteralPath $urlPath -Encoding ASCII
Write-Host " + $urlPath"
}
$portalUrl = "https://customer.verae.ai/portal/"
$portalPath = Join-Path $VeraeMenu "Verae - Customer portal.url"
@(
"[InternetShortcut]"
"URL=$portalUrl"
) | Set-Content -LiteralPath $portalPath -Encoding ASCII
Write-Host " + $portalPath"
# --- Startup (login) ---
if (-not $NoStartup) {
if (Test-Path -LiteralPath $StartupInstaller) {
Write-Host "Installing Startup shortcut via install-tray-startup.ps1 ..."
& $StartupInstaller -Addr $Addr -TrayScript $TrayScript
} else {
$startupDir = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup"
$startupLnk = Join-Path $startupDir "Verae Tray.lnk"
New-Lnk -Path $startupLnk -Target $psExe -Arguments $trayArgs -WorkDir $TrayDir -WindowStyle 7 `
-Description "Verae Timestamping tray at login — polls GET /status. Hold id ≠ evidence."
}
} else {
Write-Host "Skipped Startup (-NoStartup)."
}
Write-Host ""
Write-Host "Packaging notes (not a full MSI product):"
Write-Host " • Package version: $PackageVersion (stamped from internal/job.HelperVersion)."
Write-Host " • This script uses WScript.Shell .lnk files only (no WiX, no NSIS, no elevated MSI)."
Write-Host " • WiX Toolset (candle/light) is optional and not required for tray presence."
Write-Host " • Commercial MSI / elevated Start Menu under ProgramData can ship later."
Write-Host " • Existing NSIS product: platform/windows/installer-windows.nsi (separate path)."
Write-Host " • IPP POST untouched — tray only uses GET /status and /queue."
Write-Host "Run tray now: verae-print menubar (or double-click Start > Verae > Verae Tray)"
Write-Host "Only a final receipt is evidence — hold ids are local queue handles, not proof."