diff --git a/tools/build/build-installer.ps1 b/tools/build/build-installer.ps1 index 28e6939760..2d2b12fa81 100644 --- a/tools/build/build-installer.ps1 +++ b/tools/build/build-installer.ps1 @@ -4,46 +4,74 @@ Build and package PowerToys (CmdPal and installer) for a specific platform and c .DESCRIPTION This script automates the end-to-end build and packaging process for PowerToys, including: -- Restoring and building all necessary solutions (CmdPal, BugReportTool, StylesReportTool, etc.) +- Restoring and building all necessary solutions (CmdPal, BugReportTool, etc.) - Cleaning up old output - Signing generated .msix packages - Building the WiX-based MSI and bootstrapper installers It is designed to work in local development. +The cert used to sign the packages is generated by .PARAMETER Platform -Specifies the target platform for the build (e.g., 'arm64', 'x64'). Default is 'arm64'. +Specifies the target platform for the build (e.g., 'arm64', 'x64'). Default is 'x64'. .PARAMETER Configuration Specifies the build configuration (e.g., 'Debug', 'Release'). Default is 'Release'. +.PARAMETER PerUser +Specifies whether to build a per-user installer (true) or machine-wide installer (false). Default is true (per-user). + .EXAMPLE .\build-installer.ps1 Runs the installer build pipeline for ARM64 Release (default). .EXAMPLE .\build-installer.ps1 -Platform x64 -Configuration Release -Runs the pipeline for x64 Debug. +Runs the pipeline for x64 Release. + +.EXAMPLE +.\build-installer.ps1 -Platform x64 -Configuration Release -PerUser false +Runs the pipeline for x64 Release with machine-wide installer. .NOTES -- Requires MSBuild, WiX Toolset, and Git to be installed and accessible from your environment. - Make sure to run this script from a Developer PowerShell (e.g., VS2022 Developer PowerShell). - Generated MSIX files will be signed using cert-sign-package.ps1. - This script will clean previous outputs under the build directories and installer directory (except *.exe files). - First time run need admin permission to trust the certificate. -- The built installer will be placed under: installer/PowerToysSetup/[Platform]/[Configuration]/UserSetup +- The built installer will be placed under: installer/PowerToysSetup/[Platform]/[Configuration]/User[Machine]Setup relative to the solution root directory. -- The installer can't be run right after the build, I need to copy it to another file before it can be run. +- To run the full installation in other machines, call "./cert-management.ps1" to export the cert used to sign the packages. + And trust the cert in the target machine. #> - param ( - [string]$Platform = 'arm64', - [string]$Configuration = 'Release' + [string]$Platform = 'x64', + [string]$Configuration = 'Release', + [string]$PerUser = 'true' ) -$repoRoot = Resolve-Path "$PSScriptRoot\..\.." -Set-Location $repoRoot +# Find the PowerToys repository root automatically +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition +$repoRoot = $scriptDir + +# Navigate up from the script location to find the repo root +# Script is typically in tools\build, so go up two levels +while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) { + $parentDir = Split-Path -Parent $repoRoot + if ($parentDir -eq $repoRoot) { + # Reached the root of the drive, PowerToys.sln not found + Write-Error "Could not find PowerToys repository root. Make sure this script is in the PowerToys repository." + exit 1 + } + $repoRoot = $parentDir +} + +if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) { + Write-Error "Could not locate PowerToys.sln. Please ensure this script is run from within the PowerToys repository." + exit 1 +} + +Write-Host "PowerToys repository root detected: $repoRoot" function RunMSBuild { param ( @@ -55,6 +83,7 @@ function RunMSBuild { $Solution "/p:Platform=`"$Platform`"" "/p:Configuration=$Configuration" + "/p:CIBuild=true" '/verbosity:normal' '/clp:Summary;PerformanceSummary;ErrorsOnly;WarningsOnly' '/nologo' @@ -62,13 +91,18 @@ function RunMSBuild { $cmd = $base + ($ExtraArgs -split ' ') Write-Host ("[MSBUILD] {0} {1}" -f $Solution, ($cmd -join ' ')) - & msbuild.exe @cmd - - if ($LASTEXITCODE -ne 0) { - Write-Error ("Build failed: {0} {1}" -f $Solution, $ExtraArgs) - exit $LASTEXITCODE + + # Run MSBuild from the repository root directory + Push-Location $repoRoot + try { + & msbuild.exe @cmd + if ($LASTEXITCODE -ne 0) { + Write-Error ("Build failed: {0} {1}" -f $Solution, $ExtraArgs) + exit $LASTEXITCODE + } + } finally { + Pop-Location } - } function RestoreThenBuild { @@ -81,9 +115,9 @@ function RestoreThenBuild { } Write-Host ("Make sure wix is installed and available") -& "$PSScriptRoot\ensure-wix.ps1" +& (Join-Path $PSScriptRoot "ensure-wix.ps1") -Write-Host ("[PIPELINE] Start | Platform={0} Configuration={1}" -f $Platform, $Configuration) +Write-Host ("[PIPELINE] Start | Platform={0} Configuration={1} PerUser={2}" -f $Platform, $Configuration, $PerUser) Write-Host '' $cmdpalOutputPath = Join-Path $repoRoot "$Platform\$Configuration\WinUI3Apps\CmdPal" @@ -93,7 +127,7 @@ if (Test-Path $cmdpalOutputPath) { Remove-Item $cmdpalOutputPath -Recurse -Force -ErrorAction Ignore } -RestoreThenBuild '.\PowerToys.sln' +RestoreThenBuild 'PowerToys.sln' $msixSearchRoot = Join-Path $repoRoot "$Platform\$Configuration" $msixFiles = Get-ChildItem -Path $msixSearchRoot -Recurse -Filter *.msix | @@ -101,22 +135,27 @@ Select-Object -ExpandProperty FullName if ($msixFiles.Count) { Write-Host ("[SIGN] .msix file(s): {0}" -f ($msixFiles -join '; ')) - & "$PSScriptRoot\cert-sign-package.ps1" -TargetPaths $msixFiles + & (Join-Path $PSScriptRoot "cert-sign-package.ps1") -TargetPaths $msixFiles } else { Write-Warning "[SIGN] No .msix files found in $msixSearchRoot" } -RestoreThenBuild '.\tools\BugReportTool\BugReportTool.sln' -RestoreThenBuild '.\tools\StylesReportTool\StylesReportTool.sln' +RestoreThenBuild 'tools\BugReportTool\BugReportTool.sln' +RestoreThenBuild 'tools\StylesReportTool\StylesReportTool.sln' Write-Host '[CLEAN] installer (keep *.exe)' -git clean -xfd -e '*.exe' -- .\installer\ | Out-Null +Push-Location $repoRoot +try { + git clean -xfd -e '*.exe' -- .\installer\ | Out-Null +} finally { + Pop-Location +} -RunMSBuild '.\installer\PowerToysSetup.sln' '/t:restore /p:RestorePackagesConfig=true' +RunMSBuild 'installer\PowerToysSetup.sln' '/t:restore /p:RestorePackagesConfig=true' -RunMSBuild '.\installer\PowerToysSetup.sln' '/m /t:PowerToysInstaller /p:PerUser=true' +RunMSBuild 'installer\PowerToysSetup.sln' "/m /t:PowerToysInstaller /p:PerUser=$PerUser" -RunMSBuild '.\installer\PowerToysSetup.sln' '/m /t:PowerToysBootstrapper /p:PerUser=true' +RunMSBuild 'installer\PowerToysSetup.sln' "/m /t:PowerToysBootstrapper /p:PerUser=$PerUser" Write-Host '[PIPELINE] Completed' \ No newline at end of file diff --git a/tools/build/cert-management.ps1 b/tools/build/cert-management.ps1 index ed7031c1e9..f92146f730 100644 --- a/tools/build/cert-management.ps1 +++ b/tools/build/cert-management.ps1 @@ -152,4 +152,37 @@ function Export-CertificateFiles { if (-not $CerPath -and -not $PfxPath) { Write-Warning "No output path specified. Nothing was exported." } +} + +# Main execution when script is run directly +if ($MyInvocation.InvocationName -ne '.') { + Write-Host "=== PowerToys Certificate Management ===" -ForegroundColor Green + Write-Host "" + + # Ensure certificate exists and is trusted + Write-Host "Checking for existing certificate or creating new one..." -ForegroundColor Yellow + $cert = EnsureCertificate + + if ($cert) { + # Export the certificate to a .cer file + $exportPath = Join-Path (Get-Location) "PowerToys-CodeSigning.cer" + Write-Host "" + Write-Host "Exporting certificate..." -ForegroundColor Yellow + Export-CertificateFiles -Certificate $cert -CerPath $exportPath + + Write-Host "" + Write-Host "=== IMPORTANT NOTES ===" -ForegroundColor Red + Write-Host "The certificate has been exported to: $exportPath" -ForegroundColor White + Write-Host "" + Write-Host "To use this certificate for code signing, you need to:" -ForegroundColor Yellow + Write-Host "1. Import this certificate into 'Trusted People' store" -ForegroundColor White + Write-Host "2. Import this certificate into 'Trusted Root Certification Authorities' store" -ForegroundColor White + Write-Host "Certificate Details:" -ForegroundColor Green + Write-Host "Subject: $($cert.Subject)" -ForegroundColor White + Write-Host "Thumbprint: $($cert.Thumbprint)" -ForegroundColor White + Write-Host "Valid Until: $($cert.NotAfter)" -ForegroundColor White + } else { + Write-Error "Failed to create or find certificate. Please check the error messages above." + exit 1 + } } \ No newline at end of file