Files
claudetools/projects/msp-tools/guru-rmm/installer/build-msi.ps1
Mike Swanson 148ac75a25 Add GuruRMM Agent MSI installer (WiX 5) — Phase 1 MVP
Signed Windows installer using our Azure Trusted Signing pipeline. Phase 1
scope: installs signed agent to Program Files, creates ProgramData dir,
Apps & Features entry with proper publisher, clean install + uninstall.

Phase 2 deferred: service registration, MSI properties for site-code
injection, agent install/uninstall custom actions, firewall rules.

Verified end-to-end on Windows workstation:
- wix build produces 1.16 MB MSI
- sign.ps1 signs it against gururmm-public-trust cert profile
- msiexec /qn installs silently, signature chain verifies on installed binary
- msiexec /x uninstalls cleanly, retains ProgramData

Tooling prerequisites documented in installer/README.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:19:52 -07:00

76 lines
2.8 KiB
PowerShell

<#
.SYNOPSIS
Build + sign a GuruRMM Agent MSI installer.
.DESCRIPTION
Downloads the signed agent binary for the target version, packages it into
an MSI via WiX, signs the MSI with Azure Trusted Signing, and writes the
result to the current directory.
Requires:
- .NET SDK 8
- wix global tool (dotnet tool install --global wix --version 5.0.2)
- Azure Trusted Signing access via sign.ps1 at C:\tools\trusted-signing\
- az login session (DefaultAzureCredential)
.EXAMPLE
.\build-msi.ps1 -Version 0.6.1
.\build-msi.ps1 -Version 0.6.1 -SourceUrl https://rmm-api.azcomputerguru.com/downloads -SkipSign
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string] $Version,
[string] $SourceUrl = 'https://rmm-api.azcomputerguru.com/downloads',
[string] $WixExe = "$env:USERPROFILE\.dotnet\tools\wix.exe",
[string] $SignScript = 'C:\tools\trusted-signing\sign.ps1',
[switch] $SkipSign,
[switch] $KeepSource
)
$ErrorActionPreference = 'Stop'
Set-Location $PSScriptRoot
if (-not (Test-Path $WixExe)) { throw "wix.exe not found at $WixExe" }
$srcDir = Join-Path $PSScriptRoot 'src'
if (-not (Test-Path $srcDir)) { New-Item -ItemType Directory -Path $srcDir | Out-Null }
$exePath = Join-Path $srcDir 'gururmm-agent.exe'
$downloadUrl = "$SourceUrl/gururmm-agent-windows-amd64-$Version.exe"
Write-Host "[1] Downloading signed agent $Version from $downloadUrl ..." -ForegroundColor Cyan
Invoke-WebRequest -Uri $downloadUrl -OutFile $exePath -UseBasicParsing
$sig = Get-AuthenticodeSignature $exePath
if ($sig.Status -ne 'Valid') {
throw "Downloaded agent has invalid or missing signature: $($sig.Status). Refusing to package an unsigned agent."
}
Write-Host " signed by: $($sig.SignerCertificate.Subject)" -ForegroundColor Gray
$msiName = "gururmm-agent-$Version.msi"
Write-Host "[2] Building $msiName via WiX ..." -ForegroundColor Cyan
& $WixExe build gururmm.wxs -arch x64 -o $msiName -d "Version=$Version"
if ($LASTEXITCODE -ne 0) { throw "wix build failed (exit $LASTEXITCODE)" }
if (-not $SkipSign) {
if (-not (Test-Path $SignScript)) { throw "sign.ps1 not found at $SignScript" }
Write-Host "[3] Signing $msiName ..." -ForegroundColor Cyan
& $SignScript -File (Join-Path $PSScriptRoot $msiName) `
-Description "GuruRMM Agent Installer v$Version" `
-Url 'https://www.azcomputerguru.com' `
-Verify
if ($LASTEXITCODE -ne 0) { throw "signing failed (exit $LASTEXITCODE)" }
}
if (-not $KeepSource) {
Remove-Item $exePath -ErrorAction SilentlyContinue
}
$msiPath = Join-Path $PSScriptRoot $msiName
$hash = (Get-FileHash $msiPath -Algorithm SHA256).Hash.ToLower()
$hash | Set-Content "$msiPath.sha256"
"$hash $msiName" | Set-Content "$msiPath.sha256"
Write-Host ""
Write-Host "[DONE]" -ForegroundColor Green
Write-Host " msi: $msiPath"
Write-Host " sha256: $hash"