param( [Parameter(Mandatory = $true)] [string]$SetupExe, [Parameter(Mandatory = $true)] [string]$OutputMsi, [Parameter(Mandatory = $true)] [string]$Version, [string]$UpgradeCode = "194198A0-0A65-52A3-9E49-CCDE26A5BF65", [string]$ProductId = "F2AECE98-63E9-5A32-9B4B-9D7C6254CBA8" ) $ErrorActionPreference = "Stop" function Get-MsiVersion { param([string]$InputVersion) $parts = $InputVersion.Split(".") while ($parts.Count -lt 4) { $parts += "0" } return ($parts[0..3] -join ".") } function Find-SevenZip { $candidates = @( "${env:ProgramFiles}\7-Zip\7z.exe", "${env:ProgramFiles(x86)}\7-Zip\7z.exe" ) foreach ($candidate in $candidates) { if (Test-Path $candidate) { return $candidate } } return $null } function Ensure-WixToolset { $cacheRoot = Join-Path $env:LOCALAPPDATA "farmcontrol-server-build" $wixRoot = Join-Path $cacheRoot "wix-4.0.0.5512.2" $candle = Join-Path $wixRoot "candle.exe" $light = Join-Path $wixRoot "light.exe" if ((Test-Path $candle) -and (Test-Path $light)) { return @{ Candle = $candle Light = $light } } $archivePath = Join-Path $cacheRoot "wix-4.0.0.5512.2.7z" $archiveUrl = "https://github.com/electron-userland/electron-builder-binaries/releases/download/wix-4.0.0.5512.2/wix-4.0.0.5512.2.7z" if (-not (Test-Path $archivePath)) { New-Item -ItemType Directory -Path $cacheRoot -Force | Out-Null Write-Host "Downloading WiX toolset..." Invoke-WebRequest -Uri $archiveUrl -OutFile $archivePath } $sevenZip = Find-SevenZip if (-not $sevenZip) { throw "Could not find 7-Zip. Install WiX Toolset or 7-Zip on the Windows build agent." } if (Test-Path $wixRoot) { Remove-Item $wixRoot -Recurse -Force } New-Item -ItemType Directory -Path $wixRoot -Force | Out-Null & $sevenZip x $archivePath "-o$wixRoot" -y | Out-Null $candleMatches = Get-ChildItem -Path $wixRoot -Filter candle.exe -Recurse -ErrorAction SilentlyContinue if ($candleMatches.Count -gt 0) { $candleDir = $candleMatches[0].DirectoryName $candle = Join-Path $candleDir "candle.exe" $light = Join-Path $candleDir "light.exe" } if (-not (Test-Path $candle) -or -not (Test-Path $light)) { throw "WiX download did not provide candle.exe/light.exe under $wixRoot" } return @{ Candle = $candle Light = $light } } function Find-WixToolset { $searchRoots = @( $env:WIX_TOOLSET_PATH, "${env:ProgramFiles(x86)}\WiX Toolset v3.11\bin", "${env:ProgramFiles}\WiX Toolset v3.11\bin" ) foreach ($root in $searchRoots) { if (-not $root) { continue } $candle = Join-Path $root "candle.exe" $light = Join-Path $root "light.exe" if ((Test-Path $candle) -and (Test-Path $light)) { return @{ Candle = $candle Light = $light } } } $cachedRoot = Join-Path $env:LOCALAPPDATA "farmcontrol-server-build\wix-4.0.0.5512.2" if (Test-Path $cachedRoot) { $cachedCandle = Get-ChildItem -Path $cachedRoot -Filter candle.exe -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if ($cachedCandle) { $candleDir = $cachedCandle.DirectoryName return @{ Candle = Join-Path $candleDir "candle.exe" Light = Join-Path $candleDir "light.exe" } } } $candleCommand = Get-Command candle.exe -ErrorAction SilentlyContinue $lightCommand = Get-Command light.exe -ErrorAction SilentlyContinue if ($candleCommand -and $lightCommand) { return @{ Candle = $candleCommand.Source Light = $lightCommand.Source } } return Ensure-WixToolset } $rootDir = Split-Path -Parent $PSScriptRoot $templatePath = Join-Path $rootDir "packaging/windows/msi-wrapped.wxs" $workDir = Join-Path $env:TEMP "farmcontrol-server-msi" if (Test-Path $workDir) { Remove-Item $workDir -Recurse -Force } New-Item -ItemType Directory -Path $workDir | Out-Null $setupExePath = (Resolve-Path -LiteralPath $SetupExe).Path $outputMsiPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputMsi) $outputDir = Split-Path $outputMsiPath -Parent if (-not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir | Out-Null } $msiVersion = Get-MsiVersion $Version $wxsContent = Get-Content -LiteralPath $templatePath -Raw $wxsContent = $wxsContent.Replace("__PRODUCT_ID__", $ProductId) $wxsContent = $wxsContent.Replace("__UPGRADE_CODE__", $UpgradeCode) $wxsContent = $wxsContent.Replace("__VERSION__", $msiVersion) $wxsContent = $wxsContent.Replace("__SETUP_EXE__", $setupExePath) $projectWxs = Join-Path $workDir "project.wxs" Set-Content -LiteralPath $projectWxs -Value $wxsContent -Encoding UTF8 $wix = Find-WixToolset $wixObj = Join-Path $workDir "project.wixobj" Push-Location $workDir try { & $wix.Candle "-arch" "x64" $projectWxs if ($LASTEXITCODE -ne 0) { throw "candle.exe failed with exit code $LASTEXITCODE" } & $wix.Light "-out" $outputMsiPath "-spdb" "-sw1076" $wixObj if ($LASTEXITCODE -ne 0) { throw "light.exe failed with exit code $LASTEXITCODE" } } finally { Pop-Location Remove-Item $workDir -Recurse -Force } if (-not (Test-Path $outputMsiPath)) { throw "MSI installer was not created at $outputMsiPath" } Write-Host "Created MSI installer at $outputMsiPath"