MegaBites-AI/Windows-powershell
0372
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3 4param(5 # Skips a check that prevents building PowerShell on unsupported Linux distributions.6 [parameter(Mandatory = $false)][switch]$SkipLinuxDistroCheck = $false7)8 9. "$PSScriptRoot\tools\buildCommon\startNativeExecution.ps1"10 11# CI runs with PowerShell 5.0, so don't use features like ?: && ||12Set-StrictMode -Version 3.013 14# On Unix paths is separated by colon.15# On Windows paths is separated by semicolon16$script:TestModulePathSeparator = [System.IO.Path]::PathSeparator17$script:Options = $null18 19$dotnetMetadata = Get-Content $PSScriptRoot/DotnetRuntimeMetadata.json | ConvertFrom-Json20$dotnetCLIChannel = $dotnetMetadata.Sdk.Channel21$dotnetCLIQuality = $dotnetMetadata.Sdk.Quality22# __DOTNET_RUNTIME_FEED and __DOTNET_RUNTIME_FEED_KEY are private variables used in release builds23$dotnetAzureFeed = if ([string]::IsNullOrWhiteSpace($env:__DOTNET_RUNTIME_FEED)) { $dotnetMetadata.Sdk.azureFeed } else { $env:__DOTNET_RUNTIME_FEED }24$dotnetAzureFeedSecret = $env:__DOTNET_RUNTIME_FEED_KEY25$dotnetSDKVersionOveride = $dotnetMetadata.Sdk.sdkImageOverride26$dotnetCLIRequiredVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version27 28# Track if tags have been sync'ed29$tagsUpToDate = $false30 31# Sync Tags32# When not using a branch in PowerShell/PowerShell, tags will not be fetched automatically33# Since code that uses Get-PSCommitID and Get-PSLatestTag assume that tags are fetched,34# This function can ensure that tags have been fetched.35# This function is used during the setup phase in tools/ci.psm136function Sync-PSTags37{38 <#39 .SYNOPSIS40 Syncs git tags from the PowerShell/PowerShell upstream remote.41 .DESCRIPTION42 Ensures that tags from the PowerShell/PowerShell upstream remote have been fetched.43 Functions like Get-PSCommitId and Get-PSLatestTag require tags to be current.44 This is called during the setup phase in tools/ci.psm1.45 .PARAMETER AddRemoteIfMissing46 If specified, adds the upstream remote automatically when it is not present.47 #>48 param(49 [Switch]50 $AddRemoteIfMissing51 )52 53 $powerShellRemoteUrls = @(54 'https://github.com/PowerShell/PowerShell'55 'git@github.com:PowerShell/PowerShell'56 )57 $defaultRemoteUrl = "$($powerShellRemoteUrls[0]).git"58 59 $upstreamRemoteDefaultName = 'upstream'60 $remotes = Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" remote}61 $upstreamRemote = $null62 foreach($remote in $remotes)63 {64 $url = Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" remote get-url $remote}65 if ($url.EndsWith('.git')) { $url = $url.Substring(0, $url.Length - 4) }66 67 if($url -in $powerShellRemoteUrls)68 {69 $upstreamRemote = $remote70 break71 }72 }73 74 if(!$upstreamRemote -and $AddRemoteIfMissing.IsPresent -and $remotes -notcontains $upstreamRemoteDefaultName)75 {76 $null = Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" remote add $upstreamRemoteDefaultName $defaultRemoteUrl}77 $upstreamRemote = $upstreamRemoteDefaultName78 }79 elseif(!$upstreamRemote)80 {81 Write-Error "Please add a remote to PowerShell\PowerShell. Example: git remote add $upstreamRemoteDefaultName $defaultRemoteUrl" -ErrorAction Stop82 }83 84 $null = Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" fetch --tags --quiet $upstreamRemote}85 $script:tagsUpToDate=$true86}87 88# Gets the latest tag for the current branch89function Get-PSLatestTag90{91 <#92 .SYNOPSIS93 Gets the latest git tag reachable from the current HEAD.94 .DESCRIPTION95 Returns the most recent annotated git tag. Run Sync-PSTags first to ensure tags96 are up to date; otherwise a warning is emitted.97 .OUTPUTS98 System.String. The latest tag string, e.g. 'v7.5.0'.99 #>100 [CmdletBinding()]101 param()102 # This function won't always return the correct value unless tags have been sync'ed103 # So, Write a warning to run Sync-PSTags104 if(!$tagsUpToDate)105 {106 Write-Warning "Run Sync-PSTags to update tags"107 }108 109 return (Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" describe --abbrev=0})110}111 112function Get-PSVersion113{114 <#115 .SYNOPSIS116 Returns the PowerShell version string for the current commit.117 .DESCRIPTION118 Derives the version from the latest git tag, optionally omitting the commit-ID suffix.119 .PARAMETER OmitCommitId120 When specified, returns only the bare version (e.g. '7.5.0') from the latest tag,121 without the commit-count and hash suffix appended by git describe.122 .OUTPUTS123 System.String. A version string such as '7.5.0' or '7.5.0-15-gabcdef1234'.124 #>125 [CmdletBinding()]126 param(127 [switch]128 $OmitCommitId129 )130 if($OmitCommitId.IsPresent)131 {132 return (Get-PSLatestTag) -replace '^v'133 }134 else135 {136 return (Get-PSCommitId) -replace '^v'137 }138}139 140function Get-PSCommitId141{142 <#143 .SYNOPSIS144 Returns the PowerShell commit-ID string produced by git describe.145 .DESCRIPTION146 Returns the full git describe string including the tag, number of commits since147 the tag, and the abbreviated commit hash (e.g. 'v7.5.0-15-gabcdef1234567890').148 Run Sync-PSTags first; otherwise a warning is emitted.149 .OUTPUTS150 System.String. A git describe string such as 'v7.5.0-15-gabcdef1234567890'.151 #>152 [CmdletBinding()]153 param()154 # This function won't always return the correct value unless tags have been sync'ed155 # So, Write a warning to run Sync-PSTags156 if(!$tagsUpToDate)157 {158 Write-Warning "Run Sync-PSTags to update tags"159 }160 161 return (Start-NativeExecution {git --git-dir="$PSScriptRoot/.git" describe --dirty --abbrev=60})162}163 164function Get-EnvironmentInformation165{166 <#167 .SYNOPSIS168 Collects information about the current operating environment.169 .DESCRIPTION170 Returns a PSCustomObject containing OS-identity flags, architecture, admin status,171 NuGet package root paths, and Linux distribution details. The object is used172 throughout the build module to make platform-conditional decisions.173 .OUTPUTS174 System.Management.Automation.PSCustomObject. An object with properties such as175 IsWindows, IsLinux, IsMacOS, IsAdmin, OSArchitecture, and distribution-specific flags176 (IsUbuntu, IsDebian, IsRedHatFamily, etc.).177 #>178 param()179 $environment = @{'IsWindows' = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT}180 # PowerShell will likely not be built on pre-1709 nanoserver181 if ('System.Management.Automation.Platform' -as [type]) {182 $environment += @{'IsCoreCLR' = [System.Management.Automation.Platform]::IsCoreCLR}183 $environment += @{'IsLinux' = [System.Management.Automation.Platform]::IsLinux}184 $environment += @{'IsMacOS' = [System.Management.Automation.Platform]::IsMacOS}185 } else {186 $environment += @{'IsCoreCLR' = $false}187 $environment += @{'IsLinux' = $false}188 $environment += @{'IsMacOS' = $false}189 }190 191 if ($environment.IsWindows)192 {193 $environment += @{'IsAdmin' = (New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)}194 $environment += @{'nugetPackagesRoot' = "${env:USERPROFILE}\.nuget\packages", "${env:NUGET_PACKAGES}"}195 $environment += @{ 'OSArchitecture' = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture }196 }197 else198 {199 $environment += @{'nugetPackagesRoot' = "${env:HOME}/.nuget/packages"}200 }201 202 if ($environment.IsMacOS) {203 $environment += @{'UsingHomebrew' = [bool](Get-Command brew -ErrorAction ignore)}204 $environment += @{'UsingMacports' = [bool](Get-Command port -ErrorAction ignore)}205 206 $environment += @{207 'OSArchitecture' = if ((uname -v) -match 'ARM64') { 'arm64' } else { 'x64' }208 }209 210 if (-not($environment.UsingHomebrew -or $environment.UsingMacports)) {211 throw "Neither Homebrew nor MacPorts is installed on this system, visit https://brew.sh/ or https://www.macports.org/ to continue"212 }213 }214 215 if ($environment.IsLinux) {216 $environment += @{ 'OSArchitecture' = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture }217 $LinuxInfo = Get-Content /etc/os-release -Raw | ConvertFrom-StringData218 $lsb_release = Get-Command lsb_release -Type Application -ErrorAction Ignore | Select-Object -First 1219 if ($lsb_release) {220 $LinuxID = & $lsb_release -is221 }222 else {223 $LinuxID = ""224 }225 226 $environment += @{'LinuxInfo' = $LinuxInfo}227 $environment += @{'IsDebian' = $LinuxInfo.ID -match 'debian' -or $LinuxInfo.ID -match 'kali'}228 $environment += @{'IsDebian9' = $environment.IsDebian -and $LinuxInfo.VERSION_ID -match '9'}229 $environment += @{'IsDebian10' = $environment.IsDebian -and $LinuxInfo.VERSION_ID -match '10'}230 $environment += @{'IsDebian11' = $environment.IsDebian -and $LinuxInfo.PRETTY_NAME -match 'bullseye'}231 $environment += @{'IsUbuntu' = $LinuxInfo.ID -match 'ubuntu' -or $LinuxID -match 'Ubuntu'}232 $environment += @{'IsUbuntu16' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '16.04'}233 $environment += @{'IsUbuntu18' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '18.04'}234 $environment += @{'IsUbuntu20' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '20.04'}235 $environment += @{'IsUbuntu22' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '22.04'}236 $environment += @{'IsUbuntu24' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '24.04'}237 $environment += @{'IsCentOS' = $LinuxInfo.ID -match 'centos' -and $LinuxInfo.VERSION_ID -match '7'}238 $environment += @{'IsFedora' = $LinuxInfo.ID -match 'fedora' -and $LinuxInfo.VERSION_ID -ge 24}239 $environment += @{'IsOpenSUSE' = $LinuxInfo.ID -match 'opensuse'}240 $environment += @{'IsSLES' = $LinuxInfo.ID -match 'sles'}241 $environment += @{'IsRedHat' = $LinuxInfo.ID -match 'rhel'}242 $environment += @{'IsRedHat7' = $environment.IsRedHat -and $LinuxInfo.VERSION_ID -match '7' }243 $environment += @{'IsOpenSUSE13' = $environment.IsOpenSUSE -and $LinuxInfo.VERSION_ID -match '13'}244 $environment += @{'IsOpenSUSE42.1' = $environment.IsOpenSUSE -and $LinuxInfo.VERSION_ID -match '42.1'}245 $environment += @{'IsDebianFamily' = $environment.IsDebian -or $environment.IsUbuntu}246 $environment += @{'IsRedHatFamily' = $environment.IsCentOS -or $environment.IsFedora -or $environment.IsRedHat}247 $environment += @{'IsSUSEFamily' = $environment.IsSLES -or $environment.IsOpenSUSE}248 $environment += @{'IsAlpine' = $LinuxInfo.ID -match 'alpine'}249 $environment += @{'IsMariner' = $LinuxInfo.ID -match 'mariner' -or $LinuxInfo.ID -match 'azurelinux'}250 251 # Workaround for temporary LD_LIBRARY_PATH hack for Fedora 24252 # https://github.com/PowerShell/PowerShell/issues/2511253 if ($environment.IsFedora -and (Test-Path ENV:\LD_LIBRARY_PATH)) {254 Remove-Item -Force ENV:\LD_LIBRARY_PATH255 Get-ChildItem ENV:256 }257 258 if( -not(259 $environment.IsDebian -or260 $environment.IsUbuntu -or261 $environment.IsRedHatFamily -or262 $environment.IsSUSEFamily -or263 $environment.IsAlpine -or264 $environment.IsMariner)265 ) {266 if ($SkipLinuxDistroCheck) {267 Write-Warning "The current OS : $($LinuxInfo.ID) is not supported for building PowerShell."268 } else {269 throw "The current OS : $($LinuxInfo.ID) is not supported for building PowerShell. Import this module with '-ArgumentList `$true' to bypass this check."270 }271 }272 }273 274 return [PSCustomObject] $environment275}276 277$environment = Get-EnvironmentInformation278 279# Autoload (in current session) temporary modules used in our tests280$TestModulePath = Join-Path $PSScriptRoot "test/tools/Modules"281if ( -not $env:PSModulePath.Contains($TestModulePath) ) {282 $env:PSModulePath = $TestModulePath+$TestModulePathSeparator+$($env:PSModulePath)283}284 285<#286 .Synopsis287 Tests if a version is preview288 .EXAMPLE289 Test-IsPreview -version '6.1.0-sometthing' # returns true290 Test-IsPreview -version '6.1.0' # returns false291#>292function Test-IsPreview293{294 param(295 [parameter(Mandatory)]296 [string]297 $Version,298 299 [switch]$IsLTS300 )301 302 if ($IsLTS.IsPresent) {303 ## If we are building a LTS package, then never consider it preview.304 return $false305 }306 307 return $Version -like '*-*'308}309 310<#311 .Synopsis312 Tests if a version is a Release Candidate313 .EXAMPLE314 Test-IsReleaseCandidate -version '6.1.0-sometthing' # returns false315 Test-IsReleaseCandidate -version '6.1.0-rc.1' # returns true316 Test-IsReleaseCandidate -version '6.1.0' # returns false317#>318function Test-IsReleaseCandidate319{320 param(321 [parameter(Mandatory)]322 [string]323 $Version324 )325 326 if ($Version -like '*-rc.*')327 {328 return $true329 }330 331 return $false332}333 334$optimizedFddRegex = 'fxdependent-(linux|win|win7|osx)-(x64|x86|arm64|arm)'335 336function Start-PSBuild {337 <#338 .SYNOPSIS339 Builds PowerShell from source using dotnet publish.340 .DESCRIPTION341 Compiles the PowerShell source tree for the specified runtime and configuration.342 Optionally restores NuGet packages, regenerates resources, generates the type catalog,343 and restores Gallery modules. Saves build options so subsequent commands can reuse them.344 .PARAMETER StopDevPowerShell345 Stops any running dev pwsh process before building to prevent file-in-use errors.346 .PARAMETER Restore347 Forces NuGet package restore even when packages already exist.348 .PARAMETER Output349 Path to the output directory. Defaults to the standard build location.350 .PARAMETER ResGen351 Regenerates C# bindings for resx resource files before building.352 .PARAMETER TypeGen353 Regenerates the CorePsTypeCatalog.cs type-catalog file before building.354 .PARAMETER Clean355 Runs 'git clean -fdX' to remove untracked and ignored files before building.356 .PARAMETER PSModuleRestore357 Restores PowerShell Gallery modules to the build output directory (legacy parameter set).358 .PARAMETER NoPSModuleRestore359 Skips restoring PowerShell Gallery modules to the build output directory.360 .PARAMETER CI361 Indicates a CI build; restores the Pester module to the output directory.362 .PARAMETER ForMinimalSize363 Produces a build optimized for minimal binary size (linux-x64, win7-x64, or osx-x64 only).364 .PARAMETER SkipExperimentalFeatureGeneration365 Skips the step that runs the built pwsh to produce the experimental-features list.366 .PARAMETER SMAOnly367 Rebuilds only System.Management.Automation.dll for rapid engine iteration.368 .PARAMETER UseNuGetOrg369 Uses nuget.org instead of the private PowerShell feed for package restore.370 .PARAMETER Runtime371 The .NET runtime identifier (RID) to target, e.g. 'win7-x64' or 'linux-x64'.372 .PARAMETER Configuration373 The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis.374 .PARAMETER ReleaseTag375 A git tag in 'vX.Y.Z[-preview.N|-rc.N]' format to embed as the release version.376 .PARAMETER Detailed377 Passes '--verbosity d' to dotnet for detailed build output.378 .PARAMETER InteractiveAuth379 Passes '--interactive' to dotnet restore for interactive feed authentication.380 .PARAMETER SkipRoslynAnalyzers381 Skips Roslyn analyzer execution during the build.382 .PARAMETER PSOptionsPath383 When supplied, saves the resolved build options to this JSON file path.384 #>385 [CmdletBinding(DefaultParameterSetName="Default")]386 param(387 # When specified this switch will stops running dev powershell388 # to help avoid compilation error, because file are in use.389 [switch]$StopDevPowerShell,390 391 [switch]$Restore,392 # Accept a path to the output directory393 # When specified, --output <path> will be passed to dotnet394 [string]$Output,395 [switch]$ResGen,396 [switch]$TypeGen,397 [switch]$Clean,398 [Parameter(ParameterSetName="Legacy")]399 [switch]$PSModuleRestore,400 [Parameter(ParameterSetName="Default")]401 [switch]$NoPSModuleRestore,402 [switch]$CI,403 [switch]$ForMinimalSize,404 405 # Skips the step where the pwsh that's been built is used to create a configuration406 # Useful when changing parsing/compilation, since bugs there can mean we can't get past this step407 [switch]$SkipExperimentalFeatureGeneration,408 409 # this switch will re-build only System.Management.Automation.dll410 # it's useful for development, to do a quick changes in the engine411 [switch]$SMAOnly,412 413 # Use nuget.org instead of the PowerShell specific feed414 [switch]$UseNuGetOrg,415 416 # These runtimes must match those in project.json417 # We do not use ValidateScript since we want tab completion418 # If this parameter is not provided it will get determined automatically.419 [ValidateSet("linux-musl-x64",420 "fxdependent",421 "fxdependent-noopt-linux-musl-x64",422 "fxdependent-linux-x64",423 "fxdependent-linux-arm64",424 "fxdependent-win-desktop",425 "linux-arm",426 "linux-arm64",427 "linux-x64",428 "osx-arm64",429 "osx-x64",430 "win-arm",431 "win-arm64",432 "win7-x64",433 "win7-x86")]434 [string]$Runtime,435 436 [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] # We might need "Checked" as well437 [string]$Configuration,438 439 [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")]440 [ValidateNotNullOrEmpty()]441 [string]$ReleaseTag,442 [switch]$Detailed,443 [switch]$InteractiveAuth,444 [switch]$SkipRoslynAnalyzers,445 [string]$PSOptionsPath446 )447 448 if ($ReleaseTag -and $ReleaseTag -notmatch "^v\d+\.\d+\.\d+(-(preview|rc)(\.\d{1,2})?)?$") {449 Write-Warning "Only preview or rc are supported for releasing pre-release version of PowerShell"450 }451 452 if ($PSCmdlet.ParameterSetName -eq "Default" -and !$NoPSModuleRestore)453 {454 $PSModuleRestore = $true455 }456 457 if ($Runtime -eq "linux-arm" -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) {458 throw "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment"459 }460 461 if ("win-arm","win-arm64" -contains $Runtime -and -not $environment.IsWindows) {462 throw "Cross compiling for win-arm or win-arm64 is only supported on Windows environment"463 }464 465 if ($ForMinimalSize) {466 if ($Runtime -and "linux-x64", "win7-x64", "osx-x64" -notcontains $Runtime) {467 throw "Build for the minimal size is enabled only for following runtimes: 'linux-x64', 'win7-x64', 'osx-x64'"468 }469 }470 471 if ($UseNuGetOrg) {472 Switch-PSNugetConfig -Source Public473 } else {474 Write-Verbose -Message "Using default feeds which are Microsoft, use `-UseNuGetOrg` to switch to Public feeds" -Verbose475 }476 477 function Stop-DevPowerShell {478 Get-Process pwsh* |479 Where-Object {480 $_.Modules |481 Where-Object {482 $_.FileName -eq (Resolve-Path $script:Options.Output).Path483 }484 } |485 Stop-Process -Verbose486 }487 488 if ($Clean) {489 Write-LogGroupStart -Title "Cleaning your working directory"490 Push-Location $PSScriptRoot491 try {492 # Excluded sqlite3 folder is due to this Roslyn issue: https://github.com/dotnet/roslyn/issues/23060493 # Excluded src/Modules/nuget.config as this is required for release build.494 # Excluded nuget.config as this is required for release build.495 git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3 --exclude src/Modules/nuget.config --exclude nuget.config496 } finally {497 Write-LogGroupEnd -Title "Cleaning your working directory"498 Pop-Location499 }500 }501 502 # Add .NET CLI tools to PATH503 Find-Dotnet504 505 # Verify we have git in place to do the build, and abort if the precheck failed506 $precheck = precheck 'git' "Build dependency 'git' not found in PATH. See <URL: https://docs.github.com/en/github/getting-started-with-github/set-up-git#setting-up-git >"507 if (-not $precheck) {508 return509 }510 511 # Verify we have .NET SDK in place to do the build, and abort if the precheck failed512 $precheck = precheck 'dotnet' "Build dependency 'dotnet' not found in PATH. Run Start-PSBootstrap. Also see <URL: https://dotnet.github.io/getting-started/ >"513 if (-not $precheck) {514 return515 }516 517 # Verify if the dotnet in-use is the required version518 $dotnetCLIInstalledVersion = Find-RequiredSDK $dotnetCLIRequiredVersion519 520 If ($dotnetCLIInstalledVersion -ne $dotnetCLIRequiredVersion) {521 Write-Warning @"522The currently installed .NET Command Line Tools is not the required version.523 524Installed version: $dotnetCLIInstalledVersion525Required version: $dotnetCLIRequiredVersion526 527Fix steps:528 5291. Remove the installed version from:530 - on windows '`$env:LOCALAPPDATA\Microsoft\dotnet'531 - on macOS and linux '`$env:HOME/.dotnet'5322. Run Start-PSBootstrap or Install-Dotnet5333. Start-PSBuild -Clean534`n535"@536 return537 }538 539 # set output options540 $OptionsArguments = @{541 Output=$Output542 Runtime=$Runtime543 Configuration=$Configuration544 Verbose=$true545 SMAOnly=[bool]$SMAOnly546 PSModuleRestore=$PSModuleRestore547 ForMinimalSize=$ForMinimalSize548 }549 550 $script:Options = New-PSOptions @OptionsArguments551 552 if ($StopDevPowerShell) {553 Stop-DevPowerShell554 }555 556 # setup arguments557 # adding ErrorOnDuplicatePublishOutputFiles=false due to .NET SDk issue: https://github.com/dotnet/sdk/issues/15748558 # removing --no-restore due to .NET SDK issue: https://github.com/dotnet/sdk/issues/18999559 # $Arguments = @("publish","--no-restore","/property:GenerateFullPaths=true", "/property:ErrorOnDuplicatePublishOutputFiles=false")560 $Arguments = @("publish","/property:GenerateFullPaths=true", "/property:ErrorOnDuplicatePublishOutputFiles=false")561 if ($Output -or $SMAOnly) {562 $Arguments += "--output", (Split-Path $Options.Output)563 }564 565 # Add --self-contained due to "warning NETSDK1179: One of '--self-contained' or '--no-self-contained' options are required when '--runtime' is used."566 if ($Options.Runtime -like 'fxdependent*') {567 $Arguments += "--no-self-contained"568 # The UseAppHost = true property creates ".exe" for the fxdependent packages.569 # We need this in the package as Start-Job needs it.570 $Arguments += "/property:UseAppHost=true"571 }572 else {573 $Arguments += "--self-contained"574 }575 576 if ($Options.Runtime -like 'win*') {577 # Starting in .NET 8, the .NET SDK won't recognize version-specific RIDs by default, such as win7-x64,578 # see https://learn.microsoft.com/dotnet/core/compatibility/sdk/8.0/rid-graph for details.579 # It will cause huge amount of changes in our build infrastructure because our building and packaging580 # scripts have the 'win7-xx' assumption regarding the target runtime.581 #582 # As a workaround, we use the old full RID graph during the build so that we can continue to use the583 # 'win7-x64' and 'win7-x86' RIDs.584 $Arguments += "/property:UseRidGraph=true"585 }586 587 if ($Options.Runtime -like 'win*' -or ($Options.Runtime -like 'fxdependent*' -and $environment.IsWindows)) {588 $Arguments += "/property:IsWindows=true"589 if(!$environment.IsWindows) {590 $Arguments += "/property:EnableWindowsTargeting=true"591 }592 }593 else {594 $Arguments += "/property:IsWindows=false"595 }596 597 # We pass in the AppDeployment property to indicate which type of deployment we are doing.598 # This allows the PowerShell.Common.props to set the correct properties for the build.599 $AppDeployment = if(($Options.Runtime -like 'fxdependent*' -or $ForMinimalSize) -and $Options.Runtime -notmatch $optimizedFddRegex) {600 # Global and zip files601 "FxDependent"602 }603 elseif($Options.Runtime -like 'fxdependent*' -and $Options.Runtime -match $optimizedFddRegex) {604 # These are Optimized and must come from the correct version of the runtime.605 # Global606 "FxDependentDeployment"607 }608 else {609 # The majority of our packages610 # AppLocal611 "SelfContained"612 }613 614 $Arguments += "/property:AppDeployment=$AppDeployment"615 $Arguments += "--configuration", $Options.Configuration616 $Arguments += "--framework", $Options.Framework617 618 if ($Detailed.IsPresent)619 {620 $Arguments += '--verbosity', 'd'621 }622 623 if (-not $SMAOnly -and $Options.Runtime -notlike 'fxdependent*') {624 # libraries should not have runtime625 $Arguments += "--runtime", $Options.Runtime626 } elseif ($Options.Runtime -match $optimizedFddRegex) {627 $runtime = $Options.Runtime -replace 'fxdependent-', ''628 $Arguments += "--runtime", $runtime629 }630 631 if ($ReleaseTag) {632 $ReleaseTagToUse = $ReleaseTag -Replace '^v'633 $Arguments += "/property:ReleaseTag=$ReleaseTagToUse"634 }635 636 if ($SkipRoslynAnalyzers) {637 $Arguments += "/property:RunAnalyzersDuringBuild=false"638 }639 640 # handle Restore641 Write-LogGroupStart -Title "Restore NuGet Packages"642 Restore-PSPackage -Options $Options -Force:$Restore -InteractiveAuth:$InteractiveAuth643 Write-LogGroupEnd -Title "Restore NuGet Packages"644 645 # handle ResGen646 # Heuristic to run ResGen on the fresh machine647 if ($ResGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.ConsoleHost/gen")) {648 Write-Log -message "Run ResGen (generating C# bindings for resx files)"649 Start-ResGen650 }651 652 # Handle TypeGen653 # .inc file name must be different for Windows and Linux to allow build on Windows and WSL.654 $runtime = $Options.Runtime655 if ($Options.Runtime -match $optimizedFddRegex) {656 $runtime = $Options.Runtime -replace 'fxdependent-', ''657 }658 659 $incFileName = "powershell_$runtime.inc"660 if ($TypeGen -or -not (Test-Path "$PSScriptRoot/src/TypeCatalogGen/$incFileName")) {661 Write-Log -message "Run TypeGen (generating CorePsTypeCatalog.cs)"662 Start-TypeGen -IncFileName $incFileName663 }664 665 # Get the folder path where pwsh.exe is located.666 if ((Split-Path $Options.Output -Leaf) -like "pwsh*") {667 $publishPath = Split-Path $Options.Output -Parent668 }669 else {670 $publishPath = $Options.Output671 }672 673 Write-LogGroupStart -Title "Build PowerShell"674 try {675 # Relative paths do not work well if cwd is not changed to project676 Push-Location $Options.Top677 678 if ($Options.Runtime -notlike 'fxdependent*' -or $Options.Runtime -match $optimizedFddRegex) {679 Write-Verbose "Building without shim" -Verbose680 $sdkToUse = 'Microsoft.NET.Sdk'681 if (($Options.Runtime -like 'win7-*' -or $Options.Runtime -eq 'win-arm64') -and !$ForMinimalSize) {682 ## WPF/WinForm and the PowerShell GraphicalHost assemblies are included683 ## when 'Microsoft.NET.Sdk.WindowsDesktop' is used.684 $sdkToUse = 'Microsoft.NET.Sdk.WindowsDesktop'685 }686 687 $Arguments += "/property:SDKToUse=$sdkToUse"688 689 Write-Log -message "Run dotnet $Arguments from $PWD"690 Start-NativeExecution { dotnet $Arguments }691 Write-Log -message "PowerShell output: $($Options.Output)"692 } else {693 Write-Verbose "Building with shim" -Verbose694 $globalToolSrcFolder = Resolve-Path (Join-Path $Options.Top "../Microsoft.PowerShell.GlobalTool.Shim") | Select-Object -ExpandProperty Path695 696 if ($Options.Runtime -eq 'fxdependent' -or $Options.Runtime -eq 'fxdependent-noopt-linux-musl-x64') {697 $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk"698 } elseif ($Options.Runtime -eq 'fxdependent-win-desktop') {699 $Arguments += "/property:SDKToUse=Microsoft.NET.Sdk.WindowsDesktop"700 }701 702 Write-Log -message "Run dotnet $Arguments from $PWD"703 Start-NativeExecution { dotnet $Arguments }704 Write-Log -message "PowerShell output: $($Options.Output)"705 706 try {707 Push-Location $globalToolSrcFolder708 709 if ($Options.Runtime -like 'fxdependent*') {710 if ($Arguments -contains '/property:UseAppHost=true') {711 $Arguments = @($Arguments | Where-Object { $_ -notlike '/property:UseAppHost=true' })712 }713 }714 715 if ($Arguments -notcontains '--output') {716 $Arguments += "--output", $publishPath717 }718 Write-Log -message "Run dotnet $Arguments from $PWD to build global tool entry point"719 Start-NativeExecution { dotnet $Arguments }720 }721 finally {722 Pop-Location723 }724 }725 } finally {726 Pop-Location727 }728 Write-LogGroupEnd -Title "Build PowerShell"729 730 # No extra post-building task will run if '-SMAOnly' is specified, because its purpose is for a quick update of S.M.A.dll after full build.731 if ($SMAOnly) {732 return733 }734 735 # publish reference assemblies736 Write-LogGroupStart -Title "Publish Reference Assemblies"737 try {738 Push-Location "$PSScriptRoot/src/TypeCatalogGen"739 $refAssemblies = Get-Content -Path $incFileName | Where-Object { $_ -like "*microsoft.netcore.app*" } | ForEach-Object { $_.TrimEnd(';') }740 $refDestFolder = Join-Path -Path $publishPath -ChildPath "ref"741 742 if (Test-Path $refDestFolder -PathType Container) {743 Remove-Item $refDestFolder -Force -Recurse -ErrorAction Stop744 }745 New-Item -Path $refDestFolder -ItemType Directory -Force -ErrorAction Stop > $null746 Copy-Item -Path $refAssemblies -Destination $refDestFolder -Force -ErrorAction Stop747 } finally {748 Pop-Location749 }750 Write-LogGroupEnd -Title "Publish Reference Assemblies"751 752 if ($ReleaseTag) {753 $psVersion = $ReleaseTag754 }755 else {756 $psVersion = git --git-dir="$PSScriptRoot/.git" describe757 }758 759 if ($environment.IsLinux) {760 if ($environment.IsRedHatFamily -or $environment.IsDebian) {761 # Symbolic links added here do NOT affect packaging as we do not build on Debian.762 # add two symbolic links to system shared libraries that libmi.so is dependent on to handle763 # platform specific changes. This is the only set of platforms needed for this currently764 # as Ubuntu has these specific library files in the platform and macOS builds for itself765 # against the correct versions.766 767 if ($environment.IsDebian10 -or $environment.IsDebian11){768 $sslTarget = "/usr/lib/x86_64-linux-gnu/libssl.so.1.1"769 $cryptoTarget = "/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1"770 }771 elseif ($environment.IsDebian9){772 # NOTE: Debian 8 doesn't need these symlinks773 $sslTarget = "/usr/lib/x86_64-linux-gnu/libssl.so.1.0.2"774 $cryptoTarget = "/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2"775 }776 else { #IsRedHatFamily777 $sslTarget = "/lib64/libssl.so.10"778 $cryptoTarget = "/lib64/libcrypto.so.10"779 }780 781 if ( ! (Test-Path "$publishPath/libssl.so.1.0.0")) {782 $null = New-Item -Force -ItemType SymbolicLink -Target $sslTarget -Path "$publishPath/libssl.so.1.0.0" -ErrorAction Stop783 }784 if ( ! (Test-Path "$publishPath/libcrypto.so.1.0.0")) {785 $null = New-Item -Force -ItemType SymbolicLink -Target $cryptoTarget -Path "$publishPath/libcrypto.so.1.0.0" -ErrorAction Stop786 }787 }788 }789 790 # download modules from powershell gallery.791 # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive792 if ($PSModuleRestore) {793 Write-LogGroupStart -Title "Restore PowerShell Modules"794 Restore-PSModuleToBuild -PublishPath $publishPath795 Write-LogGroupEnd -Title "Restore PowerShell Modules"796 }797 798 # publish powershell.config.json799 Write-LogGroupStart -Title "Generate PowerShell Configuration"800 $config = [ordered]@{}801 802 if ($Options.Runtime -like "*win*") {803 # Execution Policy and WinCompat feature are only supported on Windows.804 $config.Add("Microsoft.PowerShell:ExecutionPolicy", "RemoteSigned")805 $config.Add("WindowsPowerShellCompatibilityModuleDenyList", @("PSScheduledJob", "BestPractices", "UpdateServices"))806 }807 808 if (-not $SkipExperimentalFeatureGeneration -and809 (Test-IsPreview $psVersion) -and810 -not (Test-IsReleaseCandidate $psVersion)811 ) {812 if ((Test-ShouldGenerateExperimentalFeatures -Runtime $Options.Runtime)) {813 Write-Verbose "Build experimental feature list by running 'Get-ExperimentalFeature'" -Verbose814 $json = & $publishPath\pwsh -noprofile -command {815 $expFeatures = Get-ExperimentalFeature | ForEach-Object -MemberName Name816 ConvertTo-Json $expFeatures817 }818 } else {819 Write-Verbose "Build experimental feature list by using the pre-generated JSON files" -Verbose820 $ExperimentalFeatureJsonFilePath = if ($Options.Runtime -like "*win*") {821 "$PSScriptRoot/experimental-feature-windows.json"822 } else {823 "$PSScriptRoot/experimental-feature-linux.json"824 }825 826 if (-not (Test-Path $ExperimentalFeatureJsonFilePath)) {827 throw "ExperimentalFeatureJsonFilePath: $ExperimentalFeatureJsonFilePath does not exist"828 }829 830 $json = Get-Content -Raw $ExperimentalFeatureJsonFilePath831 }832 833 $config.Add('ExperimentalFeatures', [string[]]($json | ConvertFrom-Json));834 835 } else {836 Write-Warning -Message "Experimental features are not enabled in powershell.config.json file"837 }838 839 if ($config.Count -gt 0) {840 $configPublishPath = Join-Path -Path $publishPath -ChildPath "powershell.config.json"841 Set-Content -Path $configPublishPath -Value ($config | ConvertTo-Json) -Force -ErrorAction Stop842 } else {843 Write-Warning "No powershell.config.json generated for $publishPath"844 }845 Write-LogGroupEnd -Title "Generate PowerShell Configuration"846 847 # Restore the Pester module848 if ($CI) {849 Write-LogGroupStart -Title "Restore Pester Module"850 Restore-PSPester -Destination (Join-Path $publishPath "Modules")851 Write-LogGroupEnd -Title "Restore Pester Module"852 }853 854 Clear-NativeDependencies -PublishFolder $publishPath855 856 if ($PSOptionsPath) {857 $resolvedPSOptionsPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($PSOptionsPath)858 $parent = Split-Path -Path $resolvedPSOptionsPath859 if (!(Test-Path $parent)) {860 $null = New-Item -ItemType Directory -Path $parent861 }862 Save-PSOptions -PSOptionsPath $PSOptionsPath -Options $Options863 }864}865 866function Switch-PSNugetConfig {867 <#868 .SYNOPSIS869 Switches the NuGet configuration between public, private, and NuGet.org-only sources.870 .DESCRIPTION871 Regenerates nuget.config files in the repository root, src/Modules, and test/tools/Modules872 to point to the specified feed source. Optionally stores authenticated credentials.873 .PARAMETER Source874 The feed set to activate: 'Public' (nuget.org + dotnet feed), 'Private' (PowerShell ADO875 feed), or 'NuGetOnly' (nuget.org only).876 .PARAMETER UserName877 Username for authenticated private feed access.878 .PARAMETER ClearTextPAT879 Personal access token in clear text for authenticated private feed access.880 #>881 param(882 [Parameter(Mandatory = $true, ParameterSetName = 'user')]883 [Parameter(Mandatory = $true, ParameterSetName = 'nouser')]884 [ValidateSet('Public', 'Private', 'NuGetOnly')]885 [string] $Source,886 887 [Parameter(Mandatory = $true, ParameterSetName = 'user')]888 [string] $UserName,889 890 [Parameter(Mandatory = $true, ParameterSetName = 'user')]891 [string] $ClearTextPAT892 )893 894 Clear-PipelineNugetAuthentication895 896 $extraParams = @()897 if ($UserName) {898 $extraParams = @{899 UserName = $UserName900 ClearTextPAT = $ClearTextPAT901 }902 }903 904 $dotnetSdk = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v2'; Name = 'dotnet' }905 $gallery = [NugetPackageSource] @{Url = 'https://www.powershellgallery.com/api/v2/'; Name = 'psgallery' }906 $nugetorg = [NugetPackageSource] @{Url = 'https://api.nuget.org/v3/index.json'; Name = 'nuget.org' }907 if ( $Source -eq 'Public') {908 New-NugetConfigFile -NugetPackageSource $nugetorg, $dotnetSdk -Destination "$PSScriptRoot/" @extraParams909 New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams910 New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams911 } elseif ( $Source -eq 'NuGetOnly') {912 New-NugetConfigFile -NugetPackageSource $nugetorg -Destination "$PSScriptRoot/" @extraParams913 New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams914 New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams915 } elseif ( $Source -eq 'Private') {916 $powerShellPackages = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell/nuget/v3/index.json'; Name = 'powershell' }917 918 New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/" @extraParams919 New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/src/Modules/" @extraParams920 New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams921 } else {922 throw "Unknown source: $Source"923 }924 925 if ($UserName -or $ClearTextPAT) {926 Set-PipelineNugetAuthentication927 }928}929 930function Test-ShouldGenerateExperimentalFeatures931{932 <#933 .SYNOPSIS934 Determines whether experimental-feature JSON files should be generated on this host.935 .DESCRIPTION936 Returns $true only when the current runtime identifier matches the host OS and937 architecture, the build is not a release build (PS_RELEASE_BUILD not set), and the938 runtime is not fxdependent.939 .PARAMETER Runtime940 The .NET runtime identifier (RID) being targeted by the build.941 .OUTPUTS942 System.Boolean. $true if the experimental-feature list should be generated.943 #>944 param(945 [Parameter(Mandatory)]946 $Runtime947 )948 949 if ($env:PS_RELEASE_BUILD) {950 return $false951 }952 953 if ($Runtime -like 'fxdependent*') {954 return $false955 }956 957 $runtimePattern = 'unknown-'958 if ($environment.IsWindows) {959 $runtimePattern = '^win.*-'960 }961 962 if ($environment.IsMacOS) {963 $runtimePattern = '^osx.*-'964 }965 966 if ($environment.IsLinux) {967 $runtimePattern = '^linux.*-'968 }969 970 $runtimePattern += $environment.OSArchitecture.ToString()971 Write-Verbose "runtime pattern check: $Runtime -match $runtimePattern" -Verbose972 if ($Runtime -match $runtimePattern) {973 Write-Verbose "Generating experimental feature list" -Verbose974 return $true975 }976 977 Write-Verbose "Skipping generating experimental feature list" -Verbose978 return $false979}980 981function Restore-PSPackage982{983 <#984 .SYNOPSIS985 Restores NuGet packages for the PowerShell project directories.986 .DESCRIPTION987 Runs 'dotnet restore' on the main PowerShell project directories with up to five988 retries on transient failures. Honors the target runtime identifier and build verbosity.989 .PARAMETER ProjectDirs990 Explicit list of project directories to restore. Defaults to the standard PS project set.991 .PARAMETER Options992 PSOptions object specifying runtime and configuration. Defaults to Get-PSOptions.993 .PARAMETER Force994 Forces restore even when project.assets.json already exists.995 .PARAMETER InteractiveAuth996 Passes '--interactive' to dotnet restore for interactive feed authentication.997 .PARAMETER PSModule998 Restores in PSModule mode, omitting the runtime argument.999 #>1000 [CmdletBinding()]1001 param(1002 [ValidateNotNullOrEmpty()]1003 [Parameter()]1004 [string[]] $ProjectDirs,1005 1006 [ValidateNotNullOrEmpty()]1007 [Parameter()]1008 $Options = (Get-PSOptions -DefaultToNew),1009 1010 [switch] $Force,1011 1012 [switch] $InteractiveAuth,1013 1014 [switch] $PSModule1015 )1016 1017 if (-not $ProjectDirs)1018 {1019 $ProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules", "$PSScriptRoot/tools/wix")1020 1021 if ($Options.Runtime -like 'fxdependent*') {1022 $ProjectDirs += "$PSScriptRoot/src/Microsoft.PowerShell.GlobalTool.Shim"1023 }1024 }1025 1026 if ($Force -or (-not (Test-Path "$($Options.Top)/obj/project.assets.json"))) {1027 1028 if ($Options.Runtime -eq 'fxdependent-win-desktop') {1029 $sdkToUse = 'Microsoft.NET.Sdk.WindowsDesktop'1030 }1031 else {1032 $sdkToUse = 'Microsoft.NET.Sdk'1033 if (($Options.Runtime -like 'win7-*' -or $Options.Runtime -eq 'win-arm64') -and !$Options.ForMinimalSize) {1034 $sdkToUse = 'Microsoft.NET.Sdk.WindowsDesktop'1035 }1036 }1037 1038 if ($PSModule.IsPresent) {1039 $RestoreArguments = @("--verbosity")1040 }1041 elseif ($Options.Runtime -notlike 'fxdependent*') {1042 $RestoreArguments = @("--runtime", $Options.Runtime, "/property:SDKToUse=$sdkToUse", "--verbosity")1043 } else {1044 $RestoreArguments = @("/property:SDKToUse=$sdkToUse", "--verbosity")1045 }1046 1047 if ($VerbosePreference -eq 'Continue') {1048 $RestoreArguments += "detailed"1049 } else {1050 $RestoreArguments += "quiet"1051 }1052 1053 if ($Options.Runtime -like 'win*') {1054 $RestoreArguments += "/property:EnableWindowsTargeting=True"1055 $RestoreArguments += "/property:UseRidGraph=True"1056 }1057 1058 if ($InteractiveAuth) {1059 $RestoreArguments += "--interactive"1060 }1061 1062 if ($env:ENABLE_MSBUILD_BINLOGS -eq 'true') {1063 $RestoreArguments += '-bl'1064 }1065 1066 $ProjectDirs | ForEach-Object {1067 $project = $_1068 Write-Log -message "Run dotnet restore $project $RestoreArguments"1069 $retryCount = 01070 $maxTries = 51071 while($retryCount -lt $maxTries)1072 {1073 try1074 {1075 Start-NativeExecution { dotnet restore $project $RestoreArguments }1076 }1077 catch1078 {1079 Write-Log -message "Failed to restore $project, retrying..."1080 $retryCount++1081 if($retryCount -ge $maxTries)1082 {1083 if ($env:ENABLE_MSBUILD_BINLOGS -eq 'true') {1084 if ( Test-Path ./msbuild.binlog ) {1085 if (!(Test-Path $env:OB_OUTPUTDIRECTORY -PathType Container)) {1086 $null = New-Item -path $env:OB_OUTPUTDIRECTORY -ItemType Directory -Force -Verbose1087 }1088 1089 $projectName = Split-Path -Leaf -Path $project1090 $binlogFileName = "${projectName}.msbuild.binlog"1091 if ($IsMacOS) {1092 $resolvedPath = (Resolve-Path -Path ./msbuild.binlog).ProviderPath1093 Write-Host "##vso[artifact.upload containerfolder=$binLogFileName;artifactname=$binLogFileName]$resolvedPath"1094 } else {1095 Copy-Item -Path ./msbuild.binlog -Destination "$env:OB_OUTPUTDIRECTORY/${projectName}.msbuild.binlog" -Verbose1096 }1097 }1098 }1099 1100 throw1101 }1102 continue1103 }1104 1105 Write-Log -message "Done restoring $project"1106 break1107 }1108 }1109 }1110}1111 1112function Restore-PSModuleToBuild1113{1114 <#1115 .SYNOPSIS1116 Copies PowerShell Gallery modules from the NuGet cache into the build output Modules folder.1117 .DESCRIPTION1118 Resolves Gallery module packages referenced in PSGalleryModules.csproj and copies1119 them to the Modules subdirectory of the specified publish path. Also removes1120 .nupkg.metadata files left behind by the restore.1121 .PARAMETER PublishPath1122 The PowerShell build output directory whose Modules sub-folder receives the modules.1123 #>1124 param(1125 [Parameter(Mandatory)]1126 [string]1127 $PublishPath1128 )1129 1130 Write-Log -message "Restore PowerShell modules to $publishPath"1131 $modulesDir = Join-Path -Path $publishPath -ChildPath "Modules"1132 Copy-PSGalleryModules -Destination $modulesDir -CsProjPath "$PSScriptRoot\src\Modules\PSGalleryModules.csproj"1133 1134 # Remove .nupkg.metadata files1135 Get-ChildItem $PublishPath -Filter '.nupkg.metadata' -Recurse | ForEach-Object { Remove-Item $_.FullName -ErrorAction SilentlyContinue -Force }1136}1137 1138function Restore-PSPester1139{1140 <#1141 .SYNOPSIS1142 Downloads and saves the Pester module (v4.x) from the PowerShell Gallery.1143 .DESCRIPTION1144 Uses Save-Module to install Pester up to version 4.99 into the target directory.1145 .PARAMETER Destination1146 Directory to save Pester into. Defaults to the Modules folder of the current build output.1147 #>1148 param(1149 [ValidateNotNullOrEmpty()]1150 [string] $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules"))1151 )1152 Save-Module -Name Pester -Path $Destination -Repository PSGallery -MaximumVersion 4.991153}1154 1155function Compress-TestContent {1156 <#1157 .SYNOPSIS1158 Compresses the test directory into a zip archive for distribution.1159 .DESCRIPTION1160 Publishes PSTestTools and then zips the entire test/ directory to the given1161 destination path using System.IO.Compression.ZipFile.1162 .PARAMETER Destination1163 The path of the output zip file to create.1164 #>1165 [CmdletBinding()]1166 param(1167 $Destination1168 )1169 1170 $null = Publish-PSTestTools1171 $powerShellTestRoot = Join-Path $PSScriptRoot 'test'1172 Add-Type -AssemblyName System.IO.Compression.FileSystem1173 1174 $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Destination)1175 [System.IO.Compression.ZipFile]::CreateFromDirectory($powerShellTestRoot, $resolvedPath)1176}1177 1178function New-PSOptions {1179 <#1180 .SYNOPSIS1181 Creates a new PSOptions hashtable describing a PowerShell build configuration.1182 .DESCRIPTION1183 Computes the output path, project directory, and framework for a PowerShell build1184 based on the supplied runtime and configuration. The resulting hashtable is consumed1185 by Start-PSBuild, Restore-PSPackage, and related functions.1186 .PARAMETER Configuration1187 The build configuration: Debug (default), Release, CodeCoverage, or StaticAnalysis.1188 .PARAMETER Framework1189 The target .NET framework moniker. Defaults to 'net11.0'.1190 .PARAMETER Runtime1191 The .NET runtime identifier (RID). Detected automatically via 'dotnet --info' if omitted.1192 .PARAMETER Output1193 Optional path to the output directory. The executable name is appended automatically.1194 .PARAMETER SMAOnly1195 Targets only the System.Management.Automation project rather than the full host.1196 .PARAMETER PSModuleRestore1197 Indicates whether Start-PSBuild should restore PowerShell Gallery modules.1198 .PARAMETER ForMinimalSize1199 Produces a build targeting minimal binary size.1200 .OUTPUTS