#Requires -Version 5.0 $ErrorActionPreference = "Stop" $root = $PSScriptRoot Set-Location $root $exe = $null if (Get-Command dotnet -ErrorAction SilentlyContinue) { $exe = "dotnet" } else { foreach ($c in @( "$env:ProgramFiles\dotnet\dotnet.exe", "${env:ProgramFiles(x86)}\dotnet\dotnet.exe" )) { if (Test-Path $c) { $exe = $c break } } } if (-not $exe) { Write-Error "dotnet SDK not found. Install .NET 8 SDK: https://dotnet.microsoft.com/download" } # -frameworkDependent: no bundled runtime (fewer files, needs .NET 8 on target) # -multiFile: disable single-file (default is single exe to reduce DLL count) $frameworkDependent = $args -contains "-frameworkDependent" -or $args -contains "--frameworkDependent" $multiFile = $args -contains "-multiFile" -or $args -contains "--multiFile" $selfContained = if ($frameworkDependent) { "false" } else { "true" } $singleFile = -not $multiFile function Invoke-Dotnet { if ($exe -eq "dotnet") { dotnet @args } else { & $exe @args } } $doPublish = $args -contains "-publish" -or $args -contains "--publish" $doPublishGui = $args -contains "-publishGui" -or $args -contains "--publishGui" $doPublishSvc = $args -contains "-publishService" -or $args -contains "--publishService" # -publish without split = GUI + Service both if ($doPublish -and -not $doPublishGui -and -not $doPublishSvc) { $doPublishGui = $true $doPublishSvc = $true } $doPublishAny = $doPublishGui -or $doPublishSvc # -msi requires WiX; -publish only generates dist, MSI optional $doMsi = $args -contains "-msi" -or $args -contains "--msi" Write-Host ">> dotnet restore" if ($doPublishAny -or $doMsi) { Invoke-Dotnet restore "$root\ChromeboxFanControl.sln" -r win-x64 } else { Invoke-Dotnet restore "$root\ChromeboxFanControl.sln" } Write-Host ">> dotnet build Release" Invoke-Dotnet build "$root\ChromeboxFanControl.sln" -c Release --no-restore if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } if ($doPublishAny) { $out = Join-Path $root "dist" if ($doPublishGui -and $doPublishSvc) { if (Test-Path $out) { Remove-Item $out -Recurse -Force } New-Item -ItemType Directory -Path $out | Out-Null } elseif ($doPublishGui -and -not (Test-Path $out)) { New-Item -ItemType Directory -Path $out | Out-Null } if ($doPublishGui) { Write-Host ">> dotnet publish GUI -> $out" $guiArgs = @("-c", "Release", "-o", $out, "-r", "win-x64", "--self-contained", "false", "--no-restore") if ($singleFile) { $guiArgs += "-p:PublishSingleFile=true", "-p:IncludeNativeLibrariesForSelfExtract=true" } Invoke-Dotnet publish "$root\ChromeboxFanControl\ChromeboxFanControl.csproj" @guiArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } if ($doPublishSvc) { Write-Host ">> dotnet publish Service -> dist-svc" $svcOut = Join-Path $root "dist-svc" $svcArgs = @("-c", "Release", "-o", $svcOut, "-r", "win-x64", "--self-contained", $selfContained, "--no-restore") if ($singleFile) { $svcArgs += "-p:PublishSingleFile=true", "-p:IncludeNativeLibrariesForSelfExtract=true" } Invoke-Dotnet publish "$root\ChromeboxFanControlService\ChromeboxFanControlService.csproj" @svcArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } if (-not (Test-Path $out)) { New-Item -ItemType Directory -Path $out | Out-Null } Copy-Item "$svcOut\*" $out -Recurse -Force -Exclude "appsettings.json" if (-not $doMsi) { Remove-Item $svcOut -Recurse -Force } } if ($doPublishGui -and $doPublishSvc) { Write-Host "Done: $out\ChromeboxFanControl.exe (GUI), $out\ChromeboxFanControlService.exe (Service)" } elseif ($doPublishGui) { Write-Host "Done (GUI only): $out\ChromeboxFanControl.exe" } else { Write-Host "Done (Service only): $out\ChromeboxFanControlService.exe (merged into dist\)" } } if ($doMsi) { $dist = Join-Path $root "dist" $distSvc = Join-Path $root "dist-svc" if (-not (Test-Path $dist)) { Write-Error "dist\ not found. Run .\build.ps1 -publish first." } if (-not (Test-Path $distSvc)) { Write-Host ">> dist-svc missing, publishing Service for service MSI" $svcArgs = @("-c", "Release", "-o", $distSvc, "-r", "win-x64", "--self-contained", $selfContained, "--no-restore") if ($singleFile) { $svcArgs += "-p:PublishSingleFile=true", "-p:IncludeNativeLibrariesForSelfExtract=true" } Invoke-Dotnet publish "$root\ChromeboxFanControlService\ChromeboxFanControlService.csproj" @svcArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } $wixBin = $null foreach ($v in @("3.11", "3.14", "3.10")) { $p = "${env:ProgramFiles(x86)}\WiX Toolset v$v\bin" if (Test-Path "$p\candle.exe") { $wixBin = $p; break } } if (-not $wixBin) { Write-Warning "WiX Toolset not found. Skipping MSI. Install from https://wixtoolset.org/docs/wix3/ to build installers." } else { $wixDir = Join-Path $root "wix" $outMsi = Join-Path $root "dist-installer" if (-not (Test-Path $outMsi)) { New-Item -ItemType Directory -Path $outMsi | Out-Null } $objDir = Join-Path $root "wix\obj" if (-not (Test-Path $objDir)) { New-Item -ItemType Directory -Path $objDir | Out-Null } $ext = "-ext", "$wixBin\WixUtilExtension.dll", "-ext", "$wixBin\WixUIExtension.dll" Write-Host ">> WiX: Desktop MSI" $harvested = Join-Path $root "wix\Harvested.wxs" & "$wixBin\heat.exe" dir $dist -cg AppFiles -gg -sf -srd -sreg -scom -dr INSTALLFOLDER -out $harvested -t "$wixDir\exclude-service.xsl" -sw5151 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & "$wixBin\candle.exe" -arch x64 -out "$objDir\\" @ext "$wixDir\Product.wxs" $harvested if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & "$wixBin\light.exe" -out "$outMsi\ChromeboxFanControl-Setup.msi" -b $dist @ext "$objDir\Product.wixobj" "$objDir\Harvested.wixobj" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Remove-Item $harvested -Force -ErrorAction SilentlyContinue Write-Host ">> WiX: Service MSI" $harvestedSvc = Join-Path $root "wix\Harvested-Service.wxs" & "$wixBin\heat.exe" dir $distSvc -cg ServiceFiles -gg -sf -srd -sreg -scom -dr INSTALLFOLDER -out $harvestedSvc -t "$wixDir\exclude-service.xsl" -sw5151 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & "$wixBin\candle.exe" -arch x64 -out "$objDir\\" @ext "$wixDir\Product-Service.wxs" $harvestedSvc if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & "$wixBin\light.exe" -out "$outMsi\ChromeboxFanControlService-Setup.msi" -b $distSvc @ext "$objDir\Product-Service.wixobj" "$objDir\Harvested-Service.wixobj" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Remove-Item $harvestedSvc -Force -ErrorAction SilentlyContinue if (Test-Path $distSvc) { Remove-Item $distSvc -Recurse -Force } Write-Host "Done: $outMsi\ChromeboxFanControl-Setup.msi (Desktop), $outMsi\ChromeboxFanControlService-Setup.msi (Service)" } } if (-not $doPublishAny -and -not $doMsi) { Write-Host "Done: $root\ChromeboxFanControl\bin\Release\net8.0-windows\ChromeboxFanControl.exe" Write-Host " .\build.ps1 -publish -> dist\ GUI + Service (self-contained)" Write-Host " .\build.ps1 -publishGui -> GUI only" Write-Host " .\build.ps1 -publishService -> Service only (merge into dist\)" Write-Host " .\build.ps1 -publish -msi -> dist + two MSI (needs WiX)" Write-Host " .\build.ps1 -publish -frameworkDependent -> no bundled runtime (needs .NET 8)" Write-Host " .\build.ps1 -publish -multiFile -> keep multiple DLLs (default: single exe)" }