<# .SYNOPSIS Build kanholec MSI installer using WiX Toolset .DESCRIPTION Builds the kanholec binary (with GUI support) and packages it into an MSI installer using WiX v7. .PARAMETER Arch Target architecture: amd64 (default) or arm64 .PARAMETER SkipBuild Skip building the Go binary (use existing one) .PARAMETER OutputDir Output directory for the MSI (default: bin/) .EXAMPLE .\build-msi.ps1 .\build-msi.ps1 -Arch arm64 .\build-msi.ps1 -SkipBuild #> param( [ValidateSet("amd64", "arm64")] [string]$Arch = "amd64", [switch]$SkipBuild, [string]$OutputDir = "" ) $ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $PSCommandPath $rootDir = Resolve-Path (Join-Path $scriptDir "..\..") if ($OutputDir -eq "") { $OutputDir = Join-Path $rootDir "bin" } $version = "0.69.0" $binaryName = "kanholec-windows-$Arch.exe" $binaryPath = Join-Path $OutputDir $binaryName Write-Host "========================================" -ForegroundColor Cyan Write-Host " kanholec MSI Builder (WiX v7)" -ForegroundColor Cyan Write-Host " Version: $version | Arch: $Arch" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" # Check WiX try { $wixVersion = & wix --version 2>&1 Write-Host " WiX: $wixVersion" -ForegroundColor Green } catch { Write-Host " ERROR: WiX Toolset not found. Install with:" -ForegroundColor Red Write-Host " dotnet tool install --global wix" -ForegroundColor Yellow exit 1 } # Check Go try { $goVersion = & go version 2>&1 Write-Host " Go: $goVersion" -ForegroundColor Green } catch { Write-Host " ERROR: Go not found." -ForegroundColor Red exit 1 } # Build binary if (-not $SkipBuild) { Write-Host "" Write-Host " Building kanholec (GUI + CGO)..." -ForegroundColor Yellow $env:CGO_ENABLED = "1" $env:GOOS = "windows" $env:GOARCH = $Arch New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null $ldflags = "-s -w -H windowsgui" $tags = "kanholec,kanholec_gui" & go build -trimpath -ldflags $ldflags -tags $tags -o $binaryPath ./cmd/kanholec if ($LASTEXITCODE -ne 0) { Write-Host " ERROR: Go build failed" -ForegroundColor Red exit 1 } $env:CGO_ENABLED = "" $env:GOOS = "" $env:GOARCH = "" Write-Host " Binary: $binaryPath" -ForegroundColor Green } else { if (-not (Test-Path $binaryPath)) { Write-Host " ERROR: Binary not found at $binaryPath" -ForegroundColor Red Write-Host " Build it first or remove -SkipBuild flag" -ForegroundColor Yellow exit 1 } Write-Host " Using existing binary: $binaryPath" -ForegroundColor Green } # Create icon if missing $iconPath = Join-Path $scriptDir "kanholec.ico" if (-not (Test-Path $iconPath)) { Write-Host "" Write-Host " Creating placeholder icon..." -ForegroundColor Yellow # Create a minimal valid .ico file (16x16 32-bit) $ico = New-Object byte[] 318 # ICO header $ico[0] = 0; $ico[1] = 0 # reserved $ico[2] = 1; $ico[3] = 0 # type: icon $ico[4] = 1; $ico[5] = 0 # count: 1 # Directory entry $ico[6] = 16 # width $ico[7] = 16 # height $ico[8] = 0 # colors $ico[9] = 0 # reserved $ico[10] = 1; $ico[11] = 0 # planes $ico[12] = 32; $ico[13] = 0 # bpp $ico[14] = 0; $ico[15] = 1; $ico[16] = 0; $ico[17] = 0 # size = 256 $ico[18] = 22; $ico[19] = 0; $ico[20] = 0; $ico[21] = 0 # offset = 22 # BMP header (40 bytes) $ico[22] = 40; $ico[23] = 0; $ico[24] = 0; $ico[25] = 0 # header size $ico[26] = 16; $ico[27] = 0; $ico[28] = 0; $ico[29] = 0 # width $ico[30] = 32; $ico[31] = 0; $ico[32] = 0; $ico[33] = 0 # height (2x for icon) $ico[34] = 1; $ico[35] = 0 # planes $ico[36] = 32; $ico[37] = 0 # bpp # Fill pixel data with blue-ish color (kanhole brand) for ($i = 62; $i -lt 318; $i += 4) { $ico[$i] = 236 # B $ico[$i+1] = 152 # G $ico[$i+2] = 56 # R $ico[$i+3] = 255 # A } [System.IO.File]::WriteAllBytes($iconPath, $ico) Write-Host " Icon: $iconPath (placeholder)" -ForegroundColor Green } # Build MSI Write-Host "" Write-Host " Building MSI with WiX..." -ForegroundColor Yellow $wixprojPath = Join-Path $scriptDir "kanholec.wixproj" $msiOutput = Join-Path $OutputDir "kanholec-$version-$Arch.msi" Push-Location $rootDir try { & dotnet build $wixprojPath -c Release -p:Platform=x64 -o $OutputDir if ($LASTEXITCODE -ne 0) { Write-Host " ERROR: WiX build failed" -ForegroundColor Red exit 1 } $builtMsi = Get-ChildItem -Path $OutputDir -Filter "*.msi" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if ($builtMsi) { if ($builtMsi.FullName -ne $msiOutput) { Move-Item -Path $builtMsi.FullName -Destination $msiOutput -Force } Write-Host "" Write-Host " MSI: $msiOutput" -ForegroundColor Green Write-Host " Size: $([math]::Round((Get-Item $msiOutput).Length / 1KB, 1)) KB" -ForegroundColor Green } } finally { Pop-Location } Write-Host "" Write-Host " Done!" -ForegroundColor Cyan Write-Host ""