From 3f24ae61d22af8b8013510af33aa3fb44957408b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 20:49:42 -0700 Subject: [PATCH 001/378] Bump github/codeql-action from 3.29.7 to 3.29.9 (#25857) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 513db9cc487..4cdd9114345 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 + uses: github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 + uses: github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 451944eaee9..8ff37e43e45 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 + uses: github/codeql-action/upload-sarif@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 with: sarif_file: results.sarif From daacfe74e98b7f90fad22b281b4274e925840b3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 20:49:54 -0700 Subject: [PATCH 002/378] Bump actions/checkout from 4 to 5 (#25853) --- .github/workflows/dependency-review.yml | 2 +- .github/workflows/labels.yml | 2 +- .github/workflows/linux-ci.yml | 18 +++++++++--------- .github/workflows/macos-ci.yml | 16 ++++++++-------- .github/workflows/markdownLink.yml | 4 ++-- .github/workflows/markdownLinkDaily.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-ci.yml | 14 +++++++------- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index b85021ab000..1b090f2cab8 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index befb416aeaf..2a3ee69799b 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Verify PR has label starting with 'cl-' id: verify-labels diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 4cdd9114345..ec77ee4d9a9 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -52,7 +52,7 @@ jobs: source: ${{ steps.filter.outputs.source }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -69,7 +69,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Linux Unelevated CI @@ -101,7 +101,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Linux Elevated CI @@ -118,7 +118,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Linux Unelevated Others @@ -135,7 +135,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Linux Elevated Others @@ -152,7 +152,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Verify xUnit test results @@ -179,7 +179,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: '0' @@ -242,7 +242,7 @@ jobs: # runs-on: ubuntu-20.04 # steps: # - name: checkout - # uses: actions/checkout@v4 + # uses: actions/checkout@v5 # with: # fetch-depth: 1000 # - name: Verify xUnit test results diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 18a684de2d9..172a09250c7 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -52,7 +52,7 @@ jobs: source: ${{ steps.filter.outputs.source }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Change Detection id: filter @@ -67,7 +67,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Build @@ -81,7 +81,7 @@ jobs: runs-on: macos-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -98,7 +98,7 @@ jobs: runs-on: macos-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -115,7 +115,7 @@ jobs: runs-on: macos-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -132,7 +132,7 @@ jobs: runs-on: macos-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -149,7 +149,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Verify xUnit test results @@ -163,7 +163,7 @@ jobs: - macos-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Bootstrap packaging if: success() || failure() run: |- diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml index 26ea99cc2ef..dbc5ccf139f 100644 --- a/.github/workflows/markdownLink.yml +++ b/.github/workflows/markdownLink.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'PowerShell' steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 with: use-quiet-mode: 'yes' @@ -27,7 +27,7 @@ jobs: statuses: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: # Full git history is needed to get a proper # list of changed files within `super-linter` diff --git a/.github/workflows/markdownLinkDaily.yml b/.github/workflows/markdownLinkDaily.yml index 87cdbdfd122..7f5789ed96d 100644 --- a/.github/workflows/markdownLinkDaily.yml +++ b/.github/workflows/markdownLinkDaily.yml @@ -18,7 +18,7 @@ jobs: if: github.repository == 'PowerShell/PowerShell' steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Check Links uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 with: diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 8ff37e43e45..fd59c0d0193 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 3aaa19fcdf6..94e1102a31d 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -53,7 +53,7 @@ jobs: source: ${{ steps.filter.outputs.source }} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Change Detection id: filter @@ -68,7 +68,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Build @@ -82,7 +82,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Windows Unelevated CI @@ -99,7 +99,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Windows Elevated CI @@ -116,7 +116,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Windows Unelevated Others @@ -133,7 +133,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Windows Elevated Others @@ -150,7 +150,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 - name: Verify xUnit test results From b90f3821000ae74384d856a11bebc2459e2e003b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 15 Aug 2025 13:10:14 -0700 Subject: [PATCH 003/378] Change the macos runner image to macos 15 large (#25867) --- .github/workflows/macos-ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 172a09250c7..83ab691b1bc 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -62,7 +62,7 @@ jobs: ci_build: name: Build PowerShell - runs-on: macos-latest + runs-on: macos-15-large needs: changes if: ${{ needs.changes.outputs.source == 'true' }} steps: @@ -78,7 +78,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v5 @@ -95,7 +95,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v5 @@ -112,7 +112,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v5 @@ -129,7 +129,7 @@ jobs: - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: macos-latest + runs-on: macos-15-large steps: - name: checkout uses: actions/checkout@v5 @@ -160,7 +160,7 @@ jobs: - changes if: ${{ needs.changes.outputs.source == 'true' }} runs-on: - - macos-latest + - macos-15-large steps: - name: checkout uses: actions/checkout@v5 From c5f2446e69ebfd52300efa69d36477f47979a2ca Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Tue, 19 Aug 2025 02:51:38 -0400 Subject: [PATCH 004/378] Suppress false positive PSScriptAnalyzer warnings in tests and build scripts (#25864) --- ....Cmdlets.LocalAccounts.LocalUser.Tests.ps1 | 4 +- .../Set-Service.Tests.ps1 | 4 ++ .../CmsMessage.Tests.ps1 | 4 ++ .../GetCredential.Tests.ps1 | 4 ++ .../UserConfigProviderModVersion1.psm1 | 60 ++++++++--------- .../UserConfigProviderModVersion2.psm1 | 66 +++++++++---------- .../UserConfigProviderModVersion3.psm1 | 58 ++++++++-------- .../certificateCommon.psm1 | 3 + .../ConvertTo-SecureString.Tests.ps1 | 4 ++ .../ConfigProvider.Tests.ps1 | 3 + .../engine/Api/Serialization.Tests.ps1 | 5 +- .../engine/Remoting/PSSession.Tests.ps1 | 3 + .../Remoting/RemoteSession.Basic.Tests.ps1 | 3 + .../Modules/WebListener/WebListener.psm1 | 4 ++ tools/WindowsCI.psm1 | 2 + tools/ci.psm1 | 3 + 16 files changed, 127 insertions(+), 103 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 index e6e5ebb8d4f..2e56df87256 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.LocalAccounts/Pester.Command.Cmdlets.LocalAccounts.LocalUser.Tests.ps1 @@ -4,6 +4,9 @@ # Module removed due to #4272 # disabling tests +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + return Set-Variable dateInFuture -Option Constant -Value "12/12/2036 09:00" @@ -1557,4 +1560,3 @@ try { finally { $global:PSDefaultParameterValues = $originalDefaultParameterValues } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 index 2c5f0fed3ee..bcb7a56ccde 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Service.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module (Join-Path -Path $PSScriptRoot '..\Microsoft.PowerShell.Security\certificateCommon.psm1') Describe "Set/New/Remove-Service cmdlet tests" -Tags "Feature", "RequireAdminOnWindows" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index 50cbdebab69..a40dfc8cfcd 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module (Join-Path -Path $PSScriptRoot 'certificateCommon.psm1') -Force Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 index cb9d0ee70ed..fad8285aab3 100755 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/GetCredential.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "Get-Credential Test" -Tag "CI" { BeforeAll { $th = New-TestHost diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 index fd85fef1552..45188075fbc 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion1/UserConfigProviderModVersion1.psm1 @@ -5,56 +5,50 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; + Text = "Hello from Get!" + } + + $result } # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $path = "$env:SystemDrive\dscTestPath\hello1.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $path = "$env:SystemDrive\dscTestPath\hello1.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) - $false + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 index d2f6a9ac719..05dbdcec7e1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion2/UserConfigProviderModVersion2.psm1 @@ -5,57 +5,51 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; - } + Text = "Hello from Get!" + } + + $result +} # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) - $path = "$env:SystemDrive\dscTestPath\hello2.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + $path = "$env:SystemDrive\dscTestPath\hello2.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $false + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 index 45987a71f76..134158d62a9 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/TestData/CatalogTestData/UserConfigProv/DSCResources/UserConfigProviderModVersion3/UserConfigProviderModVersion3.psm1 @@ -5,57 +5,51 @@ # This cmdlet executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution is in the form of a hashtable containing all the information # gathered from the GetScript execution. -function Get-TargetResource -{ +function Get-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) + $Text + ) $result = @{ - Text = "Hello from Get!"; - } - $result; - } + Text = "Hello from Get!" + } + + $result +} # The Set-TargetResource cmdlet is used to Set the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). If the DSC managed node requires a restart either during or after the execution of the SetScript, # the SetScript notifies the PS Infrastructure by setting the variable $DSCMachineStatus.IsRestartRequired to $true. -function Set-TargetResource -{ +function Set-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] + param( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $text - ) + $Text + ) - $path = "$env:SystemDrive\dscTestPath\hello3.txt" - New-Item -Path $path -Type File -Force - Add-Content -Path $path -Value $text + $path = "$env:SystemDrive\dscTestPath\hello3.txt" + New-Item -Path $path -Type File -Force + Add-Content -Path $path -Value $text } # The Test-TargetResource cmdlet is used to validate the desired state of the DSC managed node through a powershell script. # The method executes the user supplied script (i.e., the script is responsible for validating the desired state of the # DSC managed node). The result of the script execution should be true if the DSC managed machine is in the desired state # or else false should be returned. -function Test-TargetResource -{ +function Test-TargetResource { [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $text - ) - $false + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Text + ) + $false } - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 index 5601767a120..46092386fe3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Function New-GoodCertificate { <# diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 index e58a227fbcf..5a2660ed621 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-SecureString.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "ConvertTo--SecureString" -Tags "CI" { Context "Checking return types of ConvertTo--SecureString" { diff --git a/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 b/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 index 49d60cd1283..1845933e8f4 100644 --- a/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.WSMan.Management/ConfigProvider.Tests.ps1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "WSMan Config Provider" -Tag Feature,RequireAdminOnWindows { BeforeAll { #skip all tests on non-windows platform diff --git a/test/powershell/engine/Api/Serialization.Tests.ps1 b/test/powershell/engine/Api/Serialization.Tests.ps1 index 6b011ffc6ab..317a0907ca5 100644 --- a/test/powershell/engine/Api/Serialization.Tests.ps1 +++ b/test/powershell/engine/Api/Serialization.Tests.ps1 @@ -1,5 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Describe "Serialization Tests" -tags "CI" { BeforeAll { $testfileName="SerializationTest.txt" @@ -99,4 +103,3 @@ Describe "Serialization Tests" -tags "CI" { SerializeAndDeserialize($versionObject).TestScriptProperty | Should -Be $versionObject.TestScriptProperty } } - diff --git a/test/powershell/engine/Remoting/PSSession.Tests.ps1 b/test/powershell/engine/Remoting/PSSession.Tests.ps1 index cbf7313eed0..689e587ddb1 100644 --- a/test/powershell/engine/Remoting/PSSession.Tests.ps1 +++ b/test/powershell/engine/Remoting/PSSession.Tests.ps1 @@ -5,6 +5,9 @@ # PSSession tests for non-Windows platforms # +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + function GetRandomString() { return [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName()) diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index 43f92cef295..a5d49b75005 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Import-Module HelpersCommon function GetRandomString() diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 15ce1d8fe38..7f590b79b76 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -1,6 +1,10 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] +param() + Class WebListener { [int]$HttpPort diff --git a/tools/WindowsCI.psm1 b/tools/WindowsCI.psm1 index 57d506bda8b..685882546c2 100644 --- a/tools/WindowsCI.psm1 +++ b/tools/WindowsCI.psm1 @@ -15,6 +15,8 @@ function New-LocalUser .OUTPUTS .NOTES #> + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams', '')] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')] param( [Parameter(Mandatory=$true)] [string] $username, diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 317f05effd0..7b13ded1811 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param() + Set-StrictMode -Version 3.0 $ErrorActionPreference = 'continue' From d68c15e743bb0de2251d953646afba0fd93352ec Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 20 Aug 2025 12:53:59 -0700 Subject: [PATCH 005/378] Update PATH environment variable for package manager executable on Windows (#25847) Implementation for PowerShell/PowerShell-RFC#391. A few implementation decisions: 1. Check the package manager list only once per process (**same as CMD**). So, changing the package manager list in registry doesn't affect a PowerShell session that is already running. 2. When detecting user/system PATH value changes, only check new items PREPENDED or APPENDED to the original string (**same as CMD**). The detection is made simple, which is not intended to detect complex changes to the user/system PATH. 3. The PATH update feature is disabled when the `Environment` provider is not available, or when the current session is restricted. - Both `Environment` provider and `IsSessionRestricted` are checked only once per PowerShell session. - Use `ConditionalWeakTable` to cache whether the feature is enabled or not for a given session. - We cannot use `thread-static` variable for the caching because it's possible for Runspace to reuse threads. --- .../engine/NativeCommandProcessor.cs | 250 ++++++++++-- .../engine/Utils.cs | 16 +- .../NativeCommandPathUpdate.Tests.ps1 | 373 ++++++++++++++++++ test/tools/TestExe/TestExe.cs | 74 +++- 4 files changed, 681 insertions(+), 32 deletions(-) create mode 100644 test/powershell/Language/Scripting/NativeExecution/NativeCommandPathUpdate.Tests.ps1 diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 714bf8f2d4f..3626b0268e9 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -11,15 +11,17 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Linq; using System.Management.Automation.Internal; -using System.Management.Automation.Runspaces; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; +using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.Telemetry; +using Microsoft.Win32; using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation @@ -194,27 +196,211 @@ internal NativeCommandExitException(string path, int exitCode, int processId, st /// internal class NativeCommandProcessor : CommandProcessorBase { - // This is the list of files which will trigger Legacy behavior if - // PSNativeCommandArgumentPassing is set to "Windows". - private static readonly IReadOnlySet s_legacyFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) + /// + /// This is the list of files which will trigger Legacy behavior if 'PSNativeCommandArgumentPassing' is set to "Windows". + /// + private static readonly HashSet s_legacyFileExtensions = new(StringComparer.OrdinalIgnoreCase) + { + ".js", + ".wsf", + ".cmd", + ".bat", + ".vbs", + }; + + /// + /// This is the list of native commands that have non-standard behavior with regard to argument passing. + /// We use Legacy argument parsing for them when 'PSNativeCommandArgumentPassing' is set to "Windows". + /// + private static readonly HashSet s_legacyCommands = new(StringComparer.OrdinalIgnoreCase) + { + "cmd", + "cscript", + "find", + "sqlcmd", + "wscript", + }; + +#if !UNIX + /// + /// List of known package managers pulled from the registry. + /// + private static readonly HashSet s_knownPackageManagers = GetPackageManagerListFromRegistry(); + + /// + /// Indicates whether the Path Update feature is enabled in a given session. + /// PowerShell sessions could reuse the same thread, so we cannot cache the value with a thread static variable. + /// + private static readonly ConditionalWeakTable s_pathUpdateFeatureEnabled = new(); + + private readonly bool _isPackageManager; + private string _originalUserEnvPath; + private string _originalSystemEnvPath; + + /// + /// Gets the known package managers from the registry. + /// + private static HashSet GetPackageManagerListFromRegistry() + { + // We only account for the first 8 package managers. This is the same behavior as in CMD. + const int MaxPackageManagerCount = 8; + const string RegKeyPath = @"Software\Microsoft\Command Processor\KnownPackageManagers"; + + string[] subKeyNames = null; + HashSet retSet = null; + + try + { + using RegistryKey key = Registry.LocalMachine.OpenSubKey(RegKeyPath); + subKeyNames = key?.GetSubKeyNames(); + } + catch + { + return null; + } + + if (subKeyNames is { Length: > 0 }) + { + IEnumerable names = subKeyNames.Length <= MaxPackageManagerCount + ? subKeyNames + : subKeyNames.Take(MaxPackageManagerCount); + + retSet = new(names, StringComparer.OrdinalIgnoreCase); + } + + return retSet; + } + + /// + /// Check if the given name is a known package manager from the registry list. + /// + private static bool IsKnownPackageManager(string name) { - ".js", - ".wsf", - ".cmd", - ".bat", - ".vbs", - }; - - // The following native commands have non-standard behavior with regard to argument passing, - // so we use Legacy argument parsing for them when PSNativeCommandArgumentPassing is set to Windows. - private static readonly IReadOnlySet s_legacyCommands = new HashSet(StringComparer.OrdinalIgnoreCase) + if (s_knownPackageManagers is null) + { + return false; + } + + if (s_knownPackageManagers.Contains(name)) + { + return true; + } + + int lastDotIndex = name.LastIndexOf('.'); + if (lastDotIndex > 0) + { + string nameWithoutExt = name[..lastDotIndex]; + if (s_knownPackageManagers.Contains(nameWithoutExt)) + { + return true; + } + } + + return false; + } + + /// + /// Check if the Path Update feature is enabled for the given session. + /// + private static bool IsPathUpdateFeatureEnabled(ExecutionContext context) { - "cmd", - "cscript", - "find", - "sqlcmd", - "wscript", - }; + // We check only once per session. + if (s_pathUpdateFeatureEnabled.TryGetValue(context, out string value)) + { + // The feature is enabled if the value is not null. + return value is { }; + } + + // Disable Path Update if 'EnvironmentProvider' is disabled in the current session, or the current session is restricted. + bool enabled = context.EngineSessionState.Providers.ContainsKey(EnvironmentProvider.ProviderName) + && !Utils.IsSessionRestricted(context); + + // - Use the static empty string instance to indicate that the feature is enabled. + // - Use the null value to indicate that the feature is disabled. + s_pathUpdateFeatureEnabled.TryAdd(context, enabled ? string.Empty : null); + return enabled; + } + + /// + /// Gets the added part of the new string compared to the old string. + /// + private static ReadOnlySpan GetAddedPartOfString(string oldString, string newString) + { + if (oldString.Length >= newString.Length) + { + // Nothing added or something removed. + return ReadOnlySpan.Empty; + } + + int index = newString.IndexOf(oldString); + if (index is -1) + { + // The new and old strings are drastically different. Stop trying in this case. + return ReadOnlySpan.Empty; + } + + if (index > 0) + { + // Found the old string at non-zero offset, so something was prepended to the old string. + return newString.AsSpan(0, index); + } + else + { + // Found the old string at the beginning of the new string, so something was appended to the old string. + return newString.AsSpan(oldString.Length); + } + } + + /// + /// Update the process-scope environment variable Path based on the changes in the user-scope and system-scope Path. + /// + /// The old value of the user-scope Path retrieved from registry. + /// The old value of the system-scope Path retrieved from registry. + private static void UpdateProcessEnvPath(string oldUserPath, string oldSystemPath) + { + string newUserEnvPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User); + string newSystemEnvPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); + string procEnvPath = Environment.GetEnvironmentVariable("Path"); + + ReadOnlySpan userPathChange = GetAddedPartOfString(oldUserPath, newUserEnvPath).Trim(';'); + ReadOnlySpan systemPathChange = GetAddedPartOfString(oldSystemPath, newSystemEnvPath).Trim(';'); + + // Add 2 to account for the path separators we may need to add. + int maxLength = procEnvPath.Length + userPathChange.Length + systemPathChange.Length + 2; + StringBuilder newPath = null; + + if (userPathChange.Length > 0) + { + CreateNewProcEnvPath(userPathChange); + } + + if (systemPathChange.Length > 0) + { + CreateNewProcEnvPath(systemPathChange); + } + + if (newPath is { Length: > 0 }) + { + // Update the process env Path. + Environment.SetEnvironmentVariable("Path", newPath.ToString()); + } + + // Helper method to create a new env Path string. + void CreateNewProcEnvPath(ReadOnlySpan newChange) + { + newPath ??= new StringBuilder(procEnvPath, capacity: maxLength); + + if (newPath.Length is 0 || newPath[^1] is ';') + { + newPath.Append(newChange); + } + else + { + newPath.Append(';').Append(newChange); + } + } + } +#endif #region ctor/native command properties @@ -262,7 +448,11 @@ internal NativeCommandProcessor(ApplicationInfo applicationInfo, ExecutionContex // Create input writer for providing input to the process. _inputWriter = new ProcessInputWriter(Command); - _isTranscribing = this.Command.Context.EngineHostInterface.UI.IsTranscribing; + _isTranscribing = context.EngineHostInterface.UI.IsTranscribing; + +#if !UNIX + _isPackageManager = IsKnownPackageManager(_applicationInfo.Name) && IsPathUpdateFeatureEnabled(context); +#endif } /// @@ -418,7 +608,7 @@ internal override void ProcessRecord() /// /// Process object for the invoked application. /// - private System.Diagnostics.Process _nativeProcess; + private Process _nativeProcess; /// /// This is used for writing input to the process. @@ -560,6 +750,12 @@ private void InitNativeProcess() // must set UseShellExecute to false if we modify the environment block startInfo.UseShellExecute = false; } + + if (_isPackageManager) + { + _originalUserEnvPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User); + _originalSystemEnvPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); + } #endif if (this.Command.Context.CurrentPipelineStopping) @@ -898,6 +1094,13 @@ internal override void Complete() ConsumeAvailableNativeProcessOutput(blocking: true); _nativeProcess.WaitForExit(); +#if !UNIX + if (_isPackageManager) + { + UpdateProcessEnvPath(_originalUserEnvPath, _originalSystemEnvPath); + } +#endif + // Capture screen output if we are transcribing and running stand alone if (_isTranscribing && (s_supportScreenScrape == true) && _runStandAlone) { @@ -1717,6 +1920,7 @@ private bool IsExecutable(string path) #region Minishell Interop private bool _isMiniShell = false; + /// /// Returns true if native command being invoked is mini-shell. /// diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 2a2091af31a..ba43bc521ce 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1539,14 +1539,14 @@ internal static string DisplayHumanReadableFileSize(long bytes) /// True if the session is restricted. internal static bool IsSessionRestricted(ExecutionContext context) { - CmdletInfo cmdletInfo = context.SessionState.InvokeCommand.GetCmdlet("Microsoft.PowerShell.Core\\Import-Module"); - // if import-module is visible, then the session is not restricted, - // because the user can load arbitrary code. - if (cmdletInfo != null && cmdletInfo.Visibility == SessionStateEntryVisibility.Public) - { - return false; - } - return true; + CmdletInfo cmdletInfo = context.SessionState.InvokeCommand.GetCmdlet("Microsoft.PowerShell.Core\\Import-Module"); + // if import-module is visible, then the session is not restricted, + // because the user can load arbitrary code. + if (cmdletInfo != null && cmdletInfo.Visibility == SessionStateEntryVisibility.Public) + { + return false; + } + return true; } } } diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandPathUpdate.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandPathUpdate.Tests.ps1 new file mode 100644 index 00000000000..ff90500ac83 --- /dev/null +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandPathUpdate.Tests.ps1 @@ -0,0 +1,373 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +## The "Path Update" feature is only available on Windows. +## Skip the test suite on Unix platforms. +if (-not $IsWindows) { + return; +} + +function GetEnvPathLiteralValue { + param( + [System.EnvironmentVariableTarget] $Target + ) + + if ($Target -eq 'User') { + $regKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment') + } elseif ($Target -eq 'Machine') { + $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment') + } else { + return [PSCustomObject]@{ Kind = $null; Value = $env:Path } + } + + try { + $kind = $regKey.GetValueKind('Path') + $value = $regKey.GetValue('Path', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) + + return [PSCustomObject]@{ + Kind = $kind + Value = $value + } + } + finally { + ${regKey}?.Dispose() + } +} + +function RestoreEnvPath { + param( + [System.EnvironmentVariableTarget] $Target, + [Microsoft.Win32.RegistryValueKind] $ValueKind, + [string] $LiteralValue + ) + + ## Open the registry key with 'write' access. + if ($Target -eq 'User') { + $regKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $true) + } elseif ($Target -eq 'Machine') { + $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', $true) + } else { + ## Ignore value kind when restoring the in-proc env Path. + $env:Path = $LiteralValue + return + } + + try { + $regKey.SetValue('Path', $LiteralValue, $ValueKind) + } finally { + ${regKey}?.Dispose() + } +} + +function UpdatePackageManager { + param( + [Parameter(ParameterSetName = 'Add')] + [switch] $Add, + + [Parameter(ParameterSetName = 'Remove')] + [switch] $Remove, + + [string] $Name + ) + + $regKeyPath = 'HKLM:\Software\Microsoft\Command Processor\KnownPackageManagers' + $keyExists = Test-Path -Path $regKeyPath + if (-not $keyExists) { + Write-Host -ForegroundColor Cyan "The registry key 'KnownPackageManagers' doesn't exist." + } + + $subKeyPath = "$regKeyPath\$Name" + if ($Add) { + $null = New-Item $subKeyPath -Force -ErrorAction Stop + } + elseif ($Remove -and $keyExists) { + Remove-Item $subKeyPath -Recurse -Force -ErrorAction Stop + } +} + +Describe "Path update for package managers" -tags @('CI', 'RequireAdminOnWindows') { + + It "Path update is off for an executable that is not registered" { + try { + $oldUserPath = GetEnvPathLiteralValue -Target 'User' + $oldSysPath = GetEnvPathLiteralValue -Target 'Machine' + $oldProcPath = $env:Path + + testexe -updateuserandsystempath + + $newUserPath = GetEnvPathLiteralValue -Target 'User' + $newUserPath.Kind | Should -Be $oldUserPath.Kind -Because "Value kind should not be changed" + $newUserPath.Value | Should -BeLike "$($oldUserPath.Value)*X:\not-exist-user-path" -Because "'testexe -updateuserandsystempath' should append 'X:\not-exist-user-path' to the User Path." + + $newSysPath = GetEnvPathLiteralValue -Target 'Machine' + $newSysPath.Kind | Should -Be $oldSysPath.Kind -Because "Value kind should not be changed" + $newSysPath.Value | Should -BeLike "X:\not-exist-sys-path*$($oldSysPath.Value)" -Because "'testexe -updateuserandsystempath' should prepend 'X:\not-exist-sys-path' to the System Path." + + $newProcPath = $env:Path + $newProcPath | Should -Be $oldProcPath -Because "'testexe -updateuserpath' doesn't change the Process Path and the executable 'testexe' is not in the package manager list." + } + finally { + if ($oldUserPath -ne $null) { + RestoreEnvPath -Target 'User' -ValueKind $oldUserPath.Kind -LiteralValue $oldUserPath.Value + } + + if ($oldSysPath -ne $null) { + RestoreEnvPath -Target 'Machine' -ValueKind $oldSysPath.Kind -LiteralValue $oldSysPath.Value + } + } + } + + ## Add the executable name without extension to the list of package managers. + Context "Add 'testexe' to the list and test 'Path Update'" { + BeforeAll { + UpdatePackageManager -Add -Name 'testexe' + } + + AfterAll { + UpdatePackageManager -Remove -Name 'testexe' + } + + It "Test when only User Path is changed" { + try { + $oldUserPath = GetEnvPathLiteralValue -Target 'User' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-user-path' will be appended to User Path. + testexe -updateuserpath + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path item added to 'User Path' should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path item added to 'User Path' should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-user-path' + } + else { + $newItem | Should -Be ';X:\not-exist-user-path' + } + } + finally { + if ($oldUserPath -ne $null) { + RestoreEnvPath -Target 'User' -ValueKind $oldUserPath.Kind -LiteralValue $oldUserPath.Value + } + } + } + + It "Test when only System Path is changed" { + try { + $oldSysPath = GetEnvPathLiteralValue -Target 'Machine' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-sys-path' will be prepended to System Path. + testexe -updatesystempath > $null + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path item added to 'System Path' should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path item added to 'System Path' should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-sys-path' + } + else { + $newItem | Should -Be ';X:\not-exist-sys-path' + } + } + finally { + if ($oldSysPath -ne $null) { + RestoreEnvPath -Target 'Machine' -ValueKind $oldSysPath.Kind -LiteralValue $oldSysPath.Value + } + } + } + + It "Test when both User and System Paths are changed" { + try { + $oldUserPath = GetEnvPathLiteralValue -Target 'User' + $oldSysPath = GetEnvPathLiteralValue -Target 'Machine' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-user-path' will be appended to User Path. + ## New item 'X:\not-exist-sys-path' will be prepended to System Path. + $null = testexe -updateuserandsystempath + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path items should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path items should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-user-path;X:\not-exist-sys-path' + } + else { + $newItem | Should -Be ';X:\not-exist-user-path;X:\not-exist-sys-path' + } + } + finally { + if ($oldUserPath -ne $null) { + RestoreEnvPath -Target 'User' -ValueKind $oldUserPath.Kind -LiteralValue $oldUserPath.Value + } + + if ($oldSysPath -ne $null) { + RestoreEnvPath -Target 'Machine' -ValueKind $oldSysPath.Kind -LiteralValue $oldSysPath.Value + } + } + } + + It "Test when neither User nor System Path is changed" { + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## Print help message and exit. + testexe -h > $null + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath | Should -Be $oldProcPath -Because "'testexe -h' doesn't change the env Path." + } + } + + ## Add the executable name with extension to the list of package managers. + Context "Add 'testexe.exe' to the list and test 'Path Update'" { + BeforeAll { + UpdatePackageManager -Add -Name 'testexe.exe' + } + + AfterAll { + UpdatePackageManager -Remove -Name 'testexe.exe' + } + + It "Test when only User Path is changed" { + try { + $oldUserPath = GetEnvPathLiteralValue -Target 'User' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-user-path' will be appended to User Path. + testexe -updateuserpath + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path item added to 'User Path' should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path item added to 'User Path' should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-user-path' + } + else { + $newItem | Should -Be ';X:\not-exist-user-path' + } + } + finally { + if ($oldUserPath -ne $null) { + RestoreEnvPath -Target 'User' -ValueKind $oldUserPath.Kind -LiteralValue $oldUserPath.Value + } + } + } + + It "Test when only System Path is changed" { + try { + $oldSysPath = GetEnvPathLiteralValue -Target 'Machine' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-sys-path' will be prepended to System Path. + testexe -updatesystempath > $null + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path item added to 'System Path' should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path item added to 'System Path' should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-sys-path' + } + else { + $newItem | Should -Be ';X:\not-exist-sys-path' + } + } + finally { + if ($oldSysPath -ne $null) { + RestoreEnvPath -Target 'Machine' -ValueKind $oldSysPath.Kind -LiteralValue $oldSysPath.Value + } + } + } + + It "Test when both User and System Paths are changed" { + try { + $oldUserPath = GetEnvPathLiteralValue -Target 'User' + $oldSysPath = GetEnvPathLiteralValue -Target 'Machine' + + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## New item 'X:\not-exist-user-path' will be appended to User Path. + ## New item 'X:\not-exist-sys-path' will be prepended to System Path. + $null = testexe -updateuserandsystempath + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath.Length | Should -BeGreaterThan $oldProcPath.Length -Because "Path should be updated. The new path items should be appended to 'Process Path'." + $newProcPath.IndexOf($oldProcPath) | Should -Be 0 -Because "Path should be updated. The new path items should be appended to 'Process Path'." + + $newItem = $newProcPath.SubString($oldProcPath.Length) + if ($oldProcPath.EndsWith(';')) { + $newItem | Should -Be 'X:\not-exist-user-path;X:\not-exist-sys-path' + } + else { + $newItem | Should -Be ';X:\not-exist-user-path;X:\not-exist-sys-path' + } + } + finally { + if ($oldUserPath -ne $null) { + RestoreEnvPath -Target 'User' -ValueKind $oldUserPath.Kind -LiteralValue $oldUserPath.Value + } + + if ($oldSysPath -ne $null) { + RestoreEnvPath -Target 'Machine' -ValueKind $oldSysPath.Kind -LiteralValue $oldSysPath.Value + } + } + } + + It "Test when neither User nor System Path is changed" { + $oldProcPath, $newProcPath = pwsh -noprofile -c { + $oldPath = $env:Path + + ## Print help message and exit. + testexe -h > $null + + $newPath = $env:Path + $oldPath, $newPath + } + + $newProcPath | Should -Be $oldProcPath -Because "'testexe -h' doesn't change the env Path." + } + } +} diff --git a/test/tools/TestExe/TestExe.cs b/test/tools/TestExe/TestExe.cs index 39c1d2b2ecb..a9b3d834261 100644 --- a/test/tools/TestExe/TestExe.cs +++ b/test/tools/TestExe/TestExe.cs @@ -9,9 +9,17 @@ using System.IO; using System.Globalization; using System.Linq; +using Microsoft.Win32; namespace TestExe { + [Flags] + internal enum EnvTarget + { + User = 1, + System = 2, + } + internal class TestExe { private static int Main(string[] args) @@ -47,6 +55,15 @@ private static int Main(string[] args) case "-writebytes": WriteBytes(args.AsSpan()[1..]); break; + case "-updateuserpath": + UpdateEnvPath(EnvTarget.User); + break; + case "-updatesystempath": + UpdateEnvPath(EnvTarget.System); + break; + case "-updateuserandsystempath": + UpdateEnvPath(EnvTarget.User | EnvTarget.System); + break; case "--help": case "-h": PrintHelp(); @@ -154,7 +171,7 @@ private static void CreateChildProcess(string[] args) { if (args.Length > 1) { - uint num = UInt32.Parse(args[1]); + uint num = uint.Parse(args[1]); for (uint i = 0; i < num; i++) { Process child = new Process(); @@ -166,6 +183,61 @@ private static void CreateChildProcess(string[] args) // sleep is needed so the process doesn't exit before the test case kill it Thread.Sleep(100000); } + + private static void UpdateEnvPath(EnvTarget target) + { + if (!OperatingSystem.IsWindows()) + { + return; + } + + const string EnvVarName = "Path"; + const string UserEnvRegPath = "Environment"; + const string SysEnvRegPath = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; + + if (target.HasFlag(EnvTarget.User)) + { + // Append to the User Path. + using RegistryKey reg = Registry.CurrentUser.OpenSubKey(UserEnvRegPath, writable: true); + UpdateEnvPathImpl(reg, append: true, @"X:\not-exist-user-path"); + } + + if (target.HasFlag(EnvTarget.System)) + { + // Prepend to the System Path. + using RegistryKey reg = Registry.LocalMachine.OpenSubKey(SysEnvRegPath, writable: true); + UpdateEnvPathImpl(reg, append: false, @"X:\not-exist-sys-path"); + } + + static void UpdateEnvPathImpl(RegistryKey regKey, bool append, string newPathItem) + { + // Get the registry value kind. + RegistryValueKind kind = regKey.GetValueKind(EnvVarName); + + // Get the literal registry value (not expanded) for the env var. + string oldValue = (string)regKey.GetValue( + EnvVarName, + defaultValue: string.Empty, + RegistryValueOptions.DoNotExpandEnvironmentNames); + + string newValue; + if (append) + { + // Append to the old value. + string separator = (oldValue is "" || oldValue.EndsWith(';')) ? string.Empty : ";"; + newValue = $"{oldValue}{separator}{newPathItem}"; + } + else + { + // Prepend to the old value. + string separator = (oldValue is "" || oldValue.StartsWith(';')) ? string.Empty : ";"; + newValue = $"{newPathItem}{separator}{oldValue}"; + } + + // Set the new value and preserve the original value kind. + regKey.SetValue(EnvVarName, newValue, kind); + } + } } internal static partial class Interop From b993074fc45e7eea97fb1121b6cf72635db3bb53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:32:36 -0700 Subject: [PATCH 006/378] Bump github/codeql-action from 3.29.9 to 3.29.10 (#25881) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index ec77ee4d9a9..44d03268972 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 + uses: github/codeql-action/init@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 + uses: github/codeql-action/analyze@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index fd59c0d0193..b8b45af778b 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.5 + uses: github/codeql-action/upload-sarif@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 with: sarif_file: results.sarif From cae1dc2c5b6e2bc5177fa3d20a166035056a1dd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:32:57 -0700 Subject: [PATCH 007/378] Bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#25882) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 1b090f2cab8..2044eea6ffc 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 + uses: actions/dependency-review-action@bc41886e18ea39df68b1b1245f4184881938e050 # v4.7.2 From 2fb12a31f30b4917ce6332363f698ceee791e96b Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:38:09 -0700 Subject: [PATCH 008/378] Update PowerShell to use .NET SDK v10-preview.7 (#25876) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/packaging/boms/windows.json | 2652 +++++++++++------ 13 files changed, 1792 insertions(+), 904 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 5c5d2190864..eec6d6685f7 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100-preview.6.25358.103", + "sdkImageVersion": "10.0.100-preview.7.25380.108", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index ec0599543c4..f81c7d1c0cd 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-preview.6.25358.103" + "version": "10.0.100-preview.7.25380.108" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 95c3c8b5390..4a87006b68f 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 5813d5d4d3e..8c67a116c3c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index d76b31d7170..11be5d04b81 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 896e517b074..47189a24778 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index e20cb27c38d..630e110cc68 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,13 +16,13 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index c466ac677fa..2c962d9528e 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 15465ab323f..4c7872bcf67 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,17 +32,17 @@ - - + + - + - + - - + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 8777dd056de..6007608a979 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index c04e4df08bf..b6417c011c4 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 543233d751e..15c379ed016 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -25,7 +25,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 6edb2da4598..81054967e65 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -1,3531 +1,4419 @@ [ { "Pattern": "_manifest\\spdx_2.2\\bsi.json", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "_manifest\\spdx_2.2\\manifest.cat", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Accessibility.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "clretwrc.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "clrgc.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "clrgcexp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "clrjit.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "coreclr.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "createdump.exe", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "cs/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "D3DCompiler_47_cor3.dll", "FileType": "NonProduct", - "Architecture": ["x64, x86"] + "Architecture": [ + "x64, x86" + ] }, { "Pattern": "de/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "de/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "DirectWriteForwarder.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "en-US/default.help.txt", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "es/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "fr/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "getfilesiginforedist.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "getfilesiginforedistwrapper.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "hostfxr.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "hostpolicy.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Humanizer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "it/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ja/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Json.More.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "JsonPointer.Net.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "JsonSchema.Net.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ko/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Markdig.Signed.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.ApplicationInsights.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Bcl.AsyncInterfaces.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.CodeAnalysis.CSharp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.CodeAnalysis.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.CSharp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Extensions.ObjectPool.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Management.Infrastructure.CimCmdlets.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Management.Infrastructure.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Management.Infrastructure.Native.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Management.Infrastructure.Native.Unmanaged.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Diagnostics.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Management.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Utility.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.ConsoleHost.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.CoreCLR.Eventing.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.GraphicalHost.dll.config", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.GraphicalHost.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.MarkdownRender.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.SDK.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Security.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.VisualBasic.Core.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.VisualBasic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.VisualBasic.Forms.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Win32.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Win32.Registry.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Win32.Registry.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.Win32.SystemEvents.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.WSMan.Management.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Microsoft.WSMan.Runtime.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Archive/*.cat", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Archive/*.ps?1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/dependencies/*.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/LICENSE", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.psd1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.psm1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/Notice.txt", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/PSGet.Format.ps1xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PackageManagement/*.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PackageManagement/*.mof", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PackageManagement/*.ps?1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PackageManagement/*.ps1xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PowerShellGet/*.mfl", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PowerShellGet/*.mof", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PowerShellGet/*.ps?1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PowerShellGet/*.ps1xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PSReadLine/*.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PSReadLine/*.ps?1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PSReadLine/*.ps1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PSReadLine/*.ps1xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/PSReadLine/*.txt", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules/ThreadJob/*.psd1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.adml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.admx", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\.signature.p7s", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\en-us\\Microsoft.PowerShell.ThreadJob.dll-Help.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\LICENSE", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\ThirdPartyNotices.txt", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\PSReadLine\\.signature.p7s", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\ThreadJob\\.signature.p7s", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Modules\\ThreadJob\\ThreadJob.psm1", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "mscordaccore_*.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "mscordaccore.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "mscordbi.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "mscorlib.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "mscorrc.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "msquic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "netstandard.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Newtonsoft.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PenImc_cor3.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pl/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "powershell.config.json", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PowerShell.Core.Instrumentation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PowerShell.Core.Instrumentation.man", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PowerShellCoreExecutionPolicy.adml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PowerShellCoreExecutionPolicy.admx", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationCore.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework-SystemCore.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework-SystemData.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework-SystemDrawing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework-SystemXml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework-SystemXmlLinq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Aero.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Aero2.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.AeroLite.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Classic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Fluent.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Luna.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationFramework.Royale.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationNative_cor3.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "PresentationUI.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "preview/pwsh-preview.cmd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "psoptions.json", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pt-BR/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pwrshplugin.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pwsh.deps.json", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pwsh.runtimeconfig.json", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "pwsh.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ReachFramework.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/Microsoft.CSharp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/Microsoft.VisualBasic.Core.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/Microsoft.VisualBasic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/Microsoft.Win32.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/Microsoft.Win32.Registry.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/mscorlib.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/netstandard.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.AppContext.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Buffers.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Collections.Concurrent.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Collections.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Collections.Immutable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Collections.NonGeneric.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Collections.Specialized.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.Annotations.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.DataAnnotations.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.EventBasedAsync.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ComponentModel.TypeConverter.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Configuration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Console.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Core.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Data.Common.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Data.DataSetExtensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Data.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.Contracts.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.Debug.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.DiagnosticSource.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.FileVersionInfo.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.Process.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.StackTrace.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.TextWriterTraceListener.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.Tools.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.TraceSource.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Diagnostics.Tracing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Drawing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Drawing.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Dynamic.Runtime.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Formats.Asn1.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Formats.Tar.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Globalization.Calendars.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Globalization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Globalization.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Compression.Brotli.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Compression.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Compression.FileSystem.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Compression.ZipFile.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.FileSystem.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.FileSystem.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.FileSystem.DriveInfo.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.FileSystem.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.FileSystem.Watcher.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.IsolatedStorage.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.MemoryMappedFiles.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Pipes.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.Pipes.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.IO.UnmanagedMemoryStream.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Linq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Linq.Expressions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Linq.Parallel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Linq.Queryable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Memory.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Http.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Http.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.HttpListener.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Mail.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.NameResolution.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.NetworkInformation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Ping.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Quic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Requests.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Security.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.ServicePoint.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.Sockets.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.WebClient.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.WebHeaderCollection.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.WebProxy.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.WebSockets.Client.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Net.WebSockets.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Numerics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Numerics.Vectors.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ObjectModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.DispatchProxy.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Emit.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Emit.ILGeneration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Emit.Lightweight.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Metadata.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Reflection.TypeExtensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Resources.Reader.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Resources.ResourceManager.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Resources.Writer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.CompilerServices.Unsafe.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.CompilerServices.VisualC.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Handles.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.InteropServices.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.InteropServices.JavaScript.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.InteropServices.RuntimeInformation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Intrinsics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Loader.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Numerics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Serialization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Serialization.Formatters.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Serialization.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Serialization.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Runtime.Serialization.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Claims.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.Algorithms.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.Cng.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.Csp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.Encoding.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.OpenSsl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Cryptography.X509Certificates.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Principal.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.Principal.Windows.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Security.SecureString.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ServiceModel.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ServiceProcess.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.Encoding.CodePages.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.Encoding.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.Encoding.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.Encodings.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Text.RegularExpressions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Channels.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Overlapped.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Tasks.Dataflow.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Tasks.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Tasks.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Tasks.Parallel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Thread.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.ThreadPool.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Threading.Timer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Transactions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Transactions.Local.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.ValueTuple.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Web.HttpUtility.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Windows.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.Linq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.ReaderWriter.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.Serialization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.XDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.XmlDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.XmlSerializer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.XPath.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/System.Xml.XPath.XDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref/WindowsBase.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref\\System.IO.Pipelines.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref\\System.Linq.AsyncEnumerable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ref\\System.Net.ServerSentEvents.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ref\\System.Threading.AccessControl.dll", + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ru/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/base.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/baseConditional.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/block.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/blockCommon.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/blockSoftware.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/command.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/conditionSet.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developer.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerCommand.rld", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerCommand.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerDscResource.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManaged.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedClass.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedConstructor.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedDelegate.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedEnumeration.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedEvent.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedField.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedInterface.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedMethod.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedNamespace.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedOperator.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedOverload.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedProperty.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerManagedStructure.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerReference.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerStructure.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/developerXaml.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/endUser.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/hierarchy.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/inline.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/inlineCommon.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/inlineSoftware.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/inlineUi.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/ITPro.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml_HTML_Style.xsl", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml_HTML.xsl", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml.rld", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml.tbr", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/Maml.xsx", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/ManagedDeveloper.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/ManagedDeveloperStructure.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/ProviderHelp.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/shellExecute.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structure.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structureGlossary.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structureList.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structureProcedure.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structureTable.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/structureTaskExecution.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/task.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "Schemas/PSMaml/troubleshooting.xsd", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "sni.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.AppContext.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Buffers.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.CodeDom.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Collections.Concurrent.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Collections.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Collections.Immutable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Collections.NonGeneric.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Collections.Specialized.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.Annotations.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.Composition.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.Composition.Registration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.DataAnnotations.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.EventBasedAsync.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ComponentModel.TypeConverter.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Configuration.ConfigurationManager.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Configuration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Console.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Core.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.Common.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.DataSetExtensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.Odbc.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.OleDb.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Data.SqlClient.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Design.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.Contracts.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.Debug.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.DiagnosticSource.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.EventLog.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.EventLog.Messages.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.FileVersionInfo.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.PerformanceCounter.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.Process.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.StackTrace.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.TextWriterTraceListener.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.Tools.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.TraceSource.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Diagnostics.Tracing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.DirectoryServices.AccountManagement.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.DirectoryServices.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.DirectoryServices.Protocols.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Drawing.Common.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Drawing.Design.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Drawing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Drawing.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Dynamic.Runtime.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Formats.Asn1.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Formats.Nrbf.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Formats.Tar.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Globalization.Calendars.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Globalization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Globalization.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Compression.Brotli.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Compression.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Compression.FileSystem.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Compression.Native.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Compression.ZipFile.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.FileSystem.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.FileSystem.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.FileSystem.DriveInfo.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.FileSystem.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.FileSystem.Watcher.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.IsolatedStorage.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.MemoryMappedFiles.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Packaging.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Pipelines.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Pipes.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Pipes.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.Ports.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.IO.UnmanagedMemoryStream.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Linq.AsyncEnumerable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Linq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Linq.Expressions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Linq.Parallel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Linq.Queryable.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Management.Automation.xml", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Management.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Memory.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Http.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Http.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Http.WinHttpHandler.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.HttpListener.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Mail.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.NameResolution.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.NetworkInformation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Ping.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Quic.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Requests.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Security.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.ServerSentEvents.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.ServicePoint.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.Sockets.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.WebClient.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.WebHeaderCollection.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.WebProxy.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.WebSockets.Client.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Net.WebSockets.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Numerics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Numerics.Vectors.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ObjectModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Printing.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.CoreLib.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.DataContractSerialization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.ServiceModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.Uri.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.Windows.Core.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.Windows.GdiPlus.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Private.Xml.Linq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Context.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.DispatchProxy.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Emit.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Emit.ILGeneration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Emit.Lightweight.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Metadata.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Reflection.TypeExtensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Resources.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Resources.Reader.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Resources.ResourceManager.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Resources.Writer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Caching.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.CompilerServices.Unsafe.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.CompilerServices.VisualC.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Handles.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.InteropServices.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.InteropServices.JavaScript.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.InteropServices.RuntimeInformation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Intrinsics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Loader.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Numerics.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Serialization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Serialization.Formatters.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Serialization.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Serialization.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Runtime.Serialization.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Claims.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Algorithms.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Cng.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Csp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Encoding.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.OpenSsl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Pkcs.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.ProtectedData.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.X509Certificates.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Cryptography.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Permissions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Principal.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.Principal.Windows.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Security.SecureString.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Duplex.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Http.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.NetTcp.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Security.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Syndication.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceModel.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceProcess.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ServiceProcess.ServiceController.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Speech.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.Encoding.CodePages.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.Encoding.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.Encoding.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.Encodings.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.Json.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Text.RegularExpressions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.AccessControl.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Channels.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Overlapped.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Tasks.Dataflow.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Tasks.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Tasks.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Tasks.Parallel.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Thread.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.ThreadPool.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Threading.Timer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Transactions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Transactions.Local.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.ValueTuple.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Web.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Web.HttpUtility.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Web.Services.Description.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Controls.Ribbon.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Extensions.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Forms.Design.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Forms.Design.Editors.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Forms.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Forms.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Input.Manipulations.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Presentation.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Windows.Primitives.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xaml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.Linq.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.ReaderWriter.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.Serialization.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.XDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.XmlDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.XmlSerializer.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.XPath.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "System.Xml.XPath.XDocument.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "ThirdPartyNotices.txt", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "tr/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "UIAutomationClient.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "UIAutomationClientSideProviders.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "UIAutomationProvider.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "UIAutomationTypes.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "vcruntime140_cor3.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "WindowsBase.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "WindowsFormsIntegration.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "wpfgfx_cor3.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hans/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/Microsoft.CodeAnalysis.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/Microsoft.VisualBasic.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/PresentationCore.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/PresentationFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/PresentationUI.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/ReachFramework.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Web.Services.Description.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Windows.Controls.Ribbon.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Windows.Forms.Design.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Windows.Forms.Primitives.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Windows.Forms.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Windows.Input.Manipulations.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/System.Xaml.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/UIAutomationClient.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/UIAutomationClientSideProviders.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/UIAutomationProvider.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/UIAutomationTypes.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/WindowsBase.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "zh-Hant/WindowsFormsIntegration.resources.dll", - "FileType": "NonProduct" + "FileType": "NonProduct", + "Architecture": null }, { "Pattern": "_manifest/spdx_2.2/manifest.spdx.json", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "_manifest/spdx_2.2/manifest.spdx.json.sha256", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "assets/Powershell_av_colors.ico", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "assets/Powershell_avatar.ico", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "assets/Powershell_black.ico", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "assets/ps_black_32x32.ico", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Install-PowerShellRemoting.ps1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "InstallPSCorePolicyDefinitions.ps1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "LICENSE.txt", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.Management.Infrastructure.CimCmdlets.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Diagnostics.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Management.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Commands.Utility.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.ConsoleHost.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.CoreCLR.Eventing.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.GraphicalHost.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.SDK.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.PowerShell.Security.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.WSMan.Management.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Microsoft.WSMan.Runtime.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/CimCmdlets/CimCmdlets.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.PowerShell.Security/Security.types.ps1xml", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/Microsoft.WSMan.Management/WSMan.format.ps1xml", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/PSDiagnostics/PSDiagnostics.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules/PSDiagnostics/PSDiagnostics.psm1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\InstallPSResourceGetPolicyDefinitions.ps1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\Microsoft.PowerShell.ThreadJob.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "Modules\\Microsoft.PowerShell.ThreadJob\\Microsoft.PowerShell.ThreadJob.psd1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "pwsh.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "pwsh.exe", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "RegisterManifest.ps1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "RegisterMicrosoftUpdate.ps1", - "FileType": "Product" + "FileType": "Product", + "Architecture": null }, { "Pattern": "System.Management.Automation.dll", - "FileType": "Product" + "FileType": "Product", + "Architecture": null } ] From 111a8e4b61aecbd9a82b77d977da99109f1aa763 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 21 Aug 2025 10:20:17 -0500 Subject: [PATCH 009/378] Specify .NET Search by Build Type (#25837) Co-authored-by: Travis Plunk (HE/HIM) Co-authored-by: Travis Plunk --- PowerShell.Common.props | 21 +++++++++++++++++++++ build.psm1 | 21 ++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 5dce6eac9a5..a6568573379 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -176,6 +176,27 @@ portable + + + + EnvironmentVariable;Global + + + + + Global + + + + AppLocal + + true diff --git a/build.psm1 b/build.psm1 index 34d79670fb4..7390bb183f7 100644 --- a/build.psm1 +++ b/build.psm1 @@ -492,13 +492,24 @@ Fix steps: $Arguments += "/property:IsWindows=false" } - # Framework Dependent builds do not support ReadyToRun as it needs a specific runtime to optimize for. - # The property is set in Powershell.Common.props file. - # We override the property through the build command line. - if(($Options.Runtime -like 'fxdependent*' -or $ForMinimalSize) -and $Options.Runtime -notmatch $optimizedFddRegex) { - $Arguments += "/property:PublishReadyToRun=false" + # We pass in the AppDeployment property to indicate which type of deployment we are doing. + # This allows the PowerShell.Common.props to set the correct properties for the build. + $AppDeployment = if(($Options.Runtime -like 'fxdependent*' -or $ForMinimalSize) -and $Options.Runtime -notmatch $optimizedFddRegex) { + # Global and zip files + "FxDependent" + } + elseif($Options.Runtime -like 'fxdependent*' -and $Options.Runtime -match $optimizedFddRegex) { + # These are Optimized and must come from the correct version of the runtime. + # Global + "FxDependentDeployment" + } + else { + # The majority of our packages + # AppLocal + "SelfContained" } + $Arguments += "/property:AppDeployment=$AppDeployment" $Arguments += "--configuration", $Options.Configuration $Arguments += "--framework", $Options.Framework From 781c9a545377092439bf881d9d9954517809465b Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 22 Aug 2025 06:01:07 +0100 Subject: [PATCH 010/378] Seal internal types in `Microsoft.PowerShell.Commands.Management` (#25849) --- .../cimSupport/cmdletization/cim/CreateInstanceJob.cs | 2 +- .../cimSupport/cmdletization/cim/DeleteInstanceJob.cs | 2 +- .../cim/EnumerateAssociatedInstancesJob.cs | 2 +- .../cmdletization/cim/InstanceMethodInvocationJob.cs | 2 +- .../cimSupport/cmdletization/cim/ModifyInstanceJob.cs | 2 +- .../cimSupport/cmdletization/cim/QueryJob.cs | 2 +- .../cmdletization/cim/StaticMethodInvocationJob.cs | 2 +- .../cmdletization/cim/cimCmdletDefinitionContext.cs | 2 +- .../cmdletization/cim/cimCmdletInvocationContext.cs | 2 +- .../cimSupport/cmdletization/cim/cimConverter.cs | 2 +- .../cimSupport/cmdletization/cim/cimJobContext.cs | 2 +- .../cimSupport/cmdletization/cim/cimQuery.cs | 2 +- .../cimSupport/cmdletization/cim/clientSideQuery.cs | 10 +++++----- .../commands/management/ContentCommandBase.cs | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs index d8a1bdd44ea..eb594dd4eea 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CreateInstanceJob.cs @@ -12,7 +12,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job wrapping invocation of a CreateInstance intrinsic CIM method. /// - internal class CreateInstanceJob : PropertySettingJob + internal sealed class CreateInstanceJob : PropertySettingJob { private CimInstance _resultFromCreateInstance; private CimInstance _resultFromGetInstance; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs index 327fb83affa..0432c6c9a8f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/DeleteInstanceJob.cs @@ -12,7 +12,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job wrapping invocation of a DeleteInstance intrinsic CIM method. /// - internal class DeleteInstanceJob : MethodInvocationJobBase + internal sealed class DeleteInstanceJob : MethodInvocationJobBase { private readonly CimInstance _objectToDelete; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs index bd024b7d76a..569740d0d1b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/EnumerateAssociatedInstancesJob.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server. /// - internal class EnumerateAssociatedInstancesJob : QueryJobBase + internal sealed class EnumerateAssociatedInstancesJob : QueryJobBase { private readonly CimInstance _associatedObject; private readonly string _associationName; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs index cd1eb78d81c..06a45933522 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/InstanceMethodInvocationJob.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job wrapping invocation of an extrinsic CIM method. /// - internal class InstanceMethodInvocationJob : ExtrinsicMethodInvocationJob + internal sealed class InstanceMethodInvocationJob : ExtrinsicMethodInvocationJob { private readonly CimInstance _targetInstance; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ModifyInstanceJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ModifyInstanceJob.cs index f0d07fc201d..869002a55f4 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ModifyInstanceJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/ModifyInstanceJob.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job wrapping invocation of a ModifyInstance intrinsic CIM method. /// - internal class ModifyInstanceJob : PropertySettingJob + internal sealed class ModifyInstanceJob : PropertySettingJob { private CimInstance _resultFromModifyInstance; private bool _resultFromModifyInstanceHasBeenPassedThru; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs index 7c7a82ee9ca..7bd2bd17531 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/QueryJob.cs @@ -14,7 +14,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job that handles executing a WQL (in the future CQL?) query on a remote CIM server. /// - internal class QueryInstancesJob : QueryJobBase + internal sealed class QueryInstancesJob : QueryJobBase { private readonly string _wqlQuery; private readonly bool _useEnumerateInstances; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs index 5a25206fe94..3bc376ab3d5 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/StaticMethodInvocationJob.cs @@ -11,7 +11,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// Job wrapping invocation of a static CIM method. /// - internal class StaticMethodInvocationJob : ExtrinsicMethodInvocationJob + internal sealed class StaticMethodInvocationJob : ExtrinsicMethodInvocationJob { internal StaticMethodInvocationJob(CimJobContext jobContext, MethodInvocationInfo methodInvocationInfo) : base(jobContext, false /* passThru */, jobContext.CmdletizationClassName, methodInvocationInfo) diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs index c334ff29601..8a4e4272561 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletDefinitionContext.cs @@ -10,7 +10,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim { - internal class CimCmdletDefinitionContext + internal sealed class CimCmdletDefinitionContext { internal CimCmdletDefinitionContext( string cmdletizationClassName, diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs index c876184c141..3bee74526fc 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimCmdletInvocationContext.cs @@ -10,7 +10,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim { - internal class CimCmdletInvocationContext + internal sealed class CimCmdletInvocationContext { internal CimCmdletInvocationContext( CimCmdletDefinitionContext cmdletDefinitionContext, diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs index 17a085b7ce5..da075286c34 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs @@ -24,7 +24,7 @@ namespace Microsoft.PowerShell.Cim { - internal class CimSensitiveValueConverter : IDisposable + internal sealed class CimSensitiveValueConverter : IDisposable { private sealed class SensitiveString : IDisposable { diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs index 5f01d472554..27d48ccab9a 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimJobContext.cs @@ -9,7 +9,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim { - internal class CimJobContext + internal sealed class CimJobContext { internal CimJobContext( CimCmdletInvocationContext cmdletInvocationContext, diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs index a065f79204f..c9f1cc5cafa 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs @@ -18,7 +18,7 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// /// CimQuery supports building of queries against CIM object model. /// - internal class CimQuery : QueryBuilder, ISessionBoundQueryBuilder + internal sealed class CimQuery : QueryBuilder, ISessionBoundQueryBuilder { private readonly StringBuilder _wqlCondition; diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs index e8e4d46e075..c8cee5d0111 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs @@ -20,9 +20,9 @@ namespace Microsoft.PowerShell.Cmdletization.Cim /// 1) filtering that cannot be translated into a server-side query (i.e. when CimQuery.WildcardToWqlLikeOperand reports that it cannot translate into WQL) /// 2) detecting if all expected results have been received and giving friendly user errors otherwise (i.e. could not find process with name='foo'; details in Windows 8 Bugs: #60926) /// - internal class ClientSideQuery : QueryBuilder + internal sealed class ClientSideQuery : QueryBuilder { - internal class NotFoundError + internal sealed class NotFoundError { public NotFoundError() { @@ -530,7 +530,7 @@ private static bool WildcardEqual(string propertyName, object actualPropertyValu } } - internal class PropertyValueExcludeFilter : PropertyValueRegularFilter + internal sealed class PropertyValueExcludeFilter : PropertyValueRegularFilter { public PropertyValueExcludeFilter(string propertyName, object expectedPropertyValue, bool wildcardsEnabled, BehaviorOnNoMatch behaviorOnNoMatch) : base(propertyName, expectedPropertyValue, wildcardsEnabled, behaviorOnNoMatch) @@ -548,7 +548,7 @@ protected override bool IsMatchingValue(object actualPropertyValue) } } - internal class PropertyValueMinFilter : PropertyValueFilter + internal sealed class PropertyValueMinFilter : PropertyValueFilter { public PropertyValueMinFilter(string propertyName, object expectedPropertyValue, BehaviorOnNoMatch behaviorOnNoMatch) : base(propertyName, expectedPropertyValue, behaviorOnNoMatch) @@ -583,7 +583,7 @@ private static bool ActualValueGreaterThanOrEqualToExpectedValue(string property } } - internal class PropertyValueMaxFilter : PropertyValueFilter + internal sealed class PropertyValueMaxFilter : PropertyValueFilter { public PropertyValueMaxFilter(string propertyName, object expectedPropertyValue, BehaviorOnNoMatch behaviorOnNoMatch) : base(propertyName, expectedPropertyValue, behaviorOnNoMatch) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs index 87c7731ed70..e7b3ada4ebb 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ContentCommandBase.cs @@ -244,7 +244,7 @@ internal void WriteContentObject(object content, long readCount, PathInfo pathIn /// as they get written to the pipeline. An instance of this cache class is /// only valid for a single path. /// - internal class ContentPathsCache + internal sealed class ContentPathsCache { /// /// Constructs a content cache item. From 5b72eb520087cc3df04c5dd86f2ff1d7231e3eb1 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 25 Aug 2025 06:22:20 +0100 Subject: [PATCH 011/378] Seal internal types in `Microsoft.PowerShell.Commands.Utility` (#25892) --- .../commands/utility/ConvertTo-Html.cs | 2 +- .../commands/utility/Csv.cs | 2 +- .../commands/utility/CsvCommands.cs | 4 ++-- .../commands/utility/CustomSerialization.cs | 5 ++--- .../FormatAndOutput/OutGridView/ExpressionColumnInfo.cs | 2 +- .../utility/FormatAndOutput/OutGridView/HeaderInfo.cs | 2 +- .../FormatAndOutput/OutGridView/OriginalColumnInfo.cs | 2 +- .../FormatAndOutput/OutGridView/OutGridViewCommand.cs | 6 +++--- .../utility/FormatAndOutput/OutGridView/OutWindowProxy.cs | 2 +- .../FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs | 8 ++++---- .../utility/FormatAndOutput/OutGridView/TableView.cs | 2 +- .../commands/utility/GetRandomCommandBase.cs | 2 +- .../commands/utility/ImplicitRemotingCommands.cs | 2 +- .../utility/JsonSchemaReferenceResolutionException.cs | 2 +- .../commands/utility/ObjectCommandComparer.cs | 4 ++-- .../commands/utility/OrderObjectBase.cs | 8 ++++---- .../commands/utility/Select-Object.cs | 4 ++-- .../commands/utility/ShowCommand/ShowCommandProxy.cs | 2 +- .../WebCmdlet/Common/InvokeRestMethodCommand.Common.cs | 2 +- .../commands/utility/WebCmdlet/CoreCLR/WebProxy.cs | 2 +- .../commands/utility/WebCmdlet/StreamHelper.cs | 2 +- .../commands/utility/XmlCommands.cs | 2 +- .../commands/utility/trace/MshHostTraceListener.cs | 2 +- .../commands/utility/trace/TraceExpressionCommand.cs | 2 +- 24 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs index 2c530a8ab93..41dd159a3ba 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertTo-Html.cs @@ -321,7 +321,7 @@ internal static class ConvertHTMLParameterDefinitionKeys /// /// This allows for @{e='foo';label='bar';alignment='center';width='20'}. /// - internal class ConvertHTMLExpressionParameterDefinition : CommandParameterDefinition + internal sealed class ConvertHTMLExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs index 9590cd7c771..d0b9f91e7f7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Csv.cs @@ -8,7 +8,7 @@ namespace Microsoft.PowerShell.Commands /// /// This class is used to parse CSV text. /// - internal class CSVHelper + internal sealed class CSVHelper { internal CSVHelper(char delimiter) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 6297d9b1f38..414b472e640 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -885,7 +885,7 @@ protected override void ProcessRecord() /// /// Helper class for Export-Csv and ConvertTo-Csv. /// - internal class ExportCsvHelper : IDisposable + internal sealed class ExportCsvHelper : IDisposable { private readonly char _delimiter; private readonly BaseCsvWritingCommand.QuoteKind _quoteKind; @@ -1224,7 +1224,7 @@ public void Dispose() /// /// Helper class to import single CSV file. /// - internal class ImportCsvHelper + internal sealed class ImportCsvHelper { #region constructor diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs index da4e4a1262a..f8a39cce096 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs @@ -14,7 +14,7 @@ namespace System.Management.Automation /// /// This class provides functionality for serializing a PSObject. /// - internal class CustomSerialization + internal sealed class CustomSerialization { #region constructor /// @@ -179,8 +179,7 @@ internal void Stop() /// /// This internal helper class provides methods for serializing mshObject. /// - internal class - CustomInternalSerializer + internal sealed class CustomInternalSerializer { #region constructor diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs index e905f5d64b6..4d0c8af875c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ExpressionColumnInfo.cs @@ -6,7 +6,7 @@ namespace Microsoft.PowerShell.Commands { - internal class ExpressionColumnInfo : ColumnInfo + internal sealed class ExpressionColumnInfo : ColumnInfo { private readonly PSPropertyExpression _expression; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs index d811ce32303..4f4e84a1569 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/HeaderInfo.cs @@ -7,7 +7,7 @@ namespace Microsoft.PowerShell.Commands { - internal class HeaderInfo + internal sealed class HeaderInfo { private readonly List _columns = new(); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs index 974188c2f74..4ec5e2240fa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OriginalColumnInfo.cs @@ -9,7 +9,7 @@ namespace Microsoft.PowerShell.Commands { - internal class OriginalColumnInfo : ColumnInfo + internal sealed class OriginalColumnInfo : ColumnInfo { private readonly string _liveObjectPropertyName; private readonly OutGridViewCommand _parentCmdlet; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs index 43e24e8b5b6..574ca39426d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutGridViewCommand.cs @@ -323,7 +323,7 @@ internal static GridHeader ConstructGridHeader(PSObject input, OutGridViewComman internal abstract void ProcessInputObject(PSObject input); } - internal class ScalarTypeHeader : GridHeader + internal sealed class ScalarTypeHeader : GridHeader { private readonly Type _originalScalarType; @@ -349,7 +349,7 @@ internal override void ProcessInputObject(PSObject input) } } - internal class NonscalarTypeHeader : GridHeader + internal sealed class NonscalarTypeHeader : GridHeader { private readonly AppliesTo _appliesTo = null; @@ -453,7 +453,7 @@ internal override void ProcessInputObject(PSObject input) } } - internal class HeteroTypeHeader : GridHeader + internal sealed class HeteroTypeHeader : GridHeader { internal HeteroTypeHeader(OutGridViewCommand parentCmd, PSObject input) : base(parentCmd) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs index b406c2bc78c..ef9b0528c75 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/OutWindowProxy.cs @@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.Commands { - internal class OutWindowProxy : IDisposable + internal sealed class OutWindowProxy : IDisposable { private const string OutGridViewWindowClassName = "Microsoft.Management.UI.Internal.OutGridViewWindow"; private const string OriginalTypePropertyName = "OriginalType"; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs index 77f80c269a3..38cc9668856 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ScalarTypeColumnInfo.cs @@ -6,7 +6,7 @@ namespace Microsoft.PowerShell.Commands { - internal class ScalarTypeColumnInfo : ColumnInfo + internal sealed class ScalarTypeColumnInfo : ColumnInfo { private readonly Type _type; @@ -29,7 +29,7 @@ internal override object GetValue(PSObject liveObject) } } - internal class TypeNameColumnInfo : ColumnInfo + internal sealed class TypeNameColumnInfo : ColumnInfo { internal TypeNameColumnInfo(string staleObjectPropertyName, string displayName) : base(staleObjectPropertyName, displayName) @@ -43,7 +43,7 @@ internal override object GetValue(PSObject liveObject) } } - internal class ToStringColumnInfo : ColumnInfo + internal sealed class ToStringColumnInfo : ColumnInfo { private readonly OutGridViewCommand _parentCmdlet; @@ -60,7 +60,7 @@ internal override object GetValue(PSObject liveObject) } } - internal class IndexColumnInfo : ColumnInfo + internal sealed class IndexColumnInfo : ColumnInfo { private int _index = 0; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs index 9213484d332..e152bb7c973 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/TableView.cs @@ -12,7 +12,7 @@ namespace Microsoft.PowerShell.Commands { - internal class TableView + internal sealed class TableView { private PSPropertyExpressionFactory _expressionFactory; private TypeInfoDataBase _typeInfoDatabase; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs index 7d6e4e71e67..fef7764c5b8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs @@ -561,7 +561,7 @@ protected override void EndProcessing() /// methods using the NextBytes() primitive based on the CLR implementation: /// https://referencesource.microsoft.com/#mscorlib/system/random.cs. /// - internal class PolymorphicRandomNumberGenerator + internal sealed class PolymorphicRandomNumberGenerator { /// /// Initializes a new instance of the class. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs index 8142f682b36..16b7db47d41 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs @@ -1916,7 +1916,7 @@ internal List GenerateProxyModule( #endregion } - internal class ImplicitRemotingCodeGenerator + internal sealed class ImplicitRemotingCodeGenerator { internal static readonly Version VersionOfScriptWriter = new(1, 0); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs index ba664ccef1b..7c2a7ac65f4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/JsonSchemaReferenceResolutionException.cs @@ -11,7 +11,7 @@ namespace Microsoft.PowerShell.Commands; /// Thrown during evaluation of when an attempt /// to resolve a $ref or $dynamicRef fails. /// -internal class JsonSchemaReferenceResolutionException : Exception +internal sealed class JsonSchemaReferenceResolutionException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs index bb71dfdbe1c..fd01768d5a8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs @@ -19,7 +19,7 @@ namespace Microsoft.PowerShell.Commands /// isExistingProperty is needed to distinguish whether a property exists and its value is null or /// the property does not exist at all. /// - internal class ObjectCommandPropertyValue + internal sealed class ObjectCommandPropertyValue { private ObjectCommandPropertyValue() { } @@ -136,7 +136,7 @@ public override int GetHashCode() /// /// ObjectCommandComparer class. /// - internal class ObjectCommandComparer : IComparer + internal sealed class ObjectCommandComparer : IComparer { /// /// Initializes a new instance of the class. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs index 519b472620b..178eaa12f62 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs @@ -24,7 +24,7 @@ internal static class SortObjectParameterDefinitionKeys /// /// - internal class SortObjectExpressionParameterDefinition : CommandParameterDefinition + internal sealed class SortObjectExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() { @@ -36,7 +36,7 @@ protected override void SetEntries() /// /// - internal class GroupObjectExpressionParameterDefinition : CommandParameterDefinition + internal sealed class GroupObjectExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() { @@ -630,7 +630,7 @@ internal sealed class OrderByPropertyEntry internal bool comparable = false; } - internal class OrderByPropertyComparer : IComparer + internal sealed class OrderByPropertyComparer : IComparer { internal OrderByPropertyComparer(bool[] ascending, CultureInfo cultureInfo, bool caseSensitive) { @@ -699,7 +699,7 @@ internal static OrderByPropertyComparer CreateComparer(List + internal sealed class IndexedOrderByPropertyComparer : IComparer { internal IndexedOrderByPropertyComparer(OrderByPropertyComparer orderByPropertyComparer) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs index efd7007e131..9db27335da5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs @@ -53,7 +53,7 @@ internal bool IsMatch(PSPropertyExpression expression) private readonly WildcardPattern[] _wildcardPatterns; } - internal class SelectObjectExpressionParameterDefinition : CommandParameterDefinition + internal sealed class SelectObjectExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() { @@ -866,7 +866,7 @@ protected override void EndProcessing() [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "This exception is internal and never thrown by any public API")] [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception is internal and never thrown by any public API")] [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic", Justification = "This exception is internal and never thrown by any public API")] - internal class SelectObjectException : SystemException + internal sealed class SelectObjectException : SystemException { internal ErrorRecord ErrorRecord { get; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs index a8a9c8f194d..ab8909bb590 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ShowCommand/ShowCommandProxy.cs @@ -16,7 +16,7 @@ namespace Microsoft.PowerShell.Commands /// Help show-command create WPF object and invoke WPF windows with the /// Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelperhelp type defined in Microsoft.PowerShell.GraphicalHost.dll. /// - internal class ShowCommandProxy + internal sealed class ShowCommandProxy { private const string ShowCommandHelperName = "Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelper"; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs index eafdaadbede..22ffaef288c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs @@ -354,7 +354,7 @@ public enum RestReturnType Xml, } - internal class BufferingStreamReader : Stream + internal sealed class BufferingStreamReader : Stream { internal BufferingStreamReader(Stream baseStream, TimeSpan perReadTimeout, CancellationToken cancellationToken) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs index 6e9f6bdf98e..c7400e75f9d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs @@ -8,7 +8,7 @@ namespace Microsoft.PowerShell.Commands { - internal class WebProxy : IWebProxy, IEquatable + internal sealed class WebProxy : IWebProxy, IEquatable { private ICredentials? _credentials; private readonly Uri _proxyAddress; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 52ff515b0b2..d24961834b6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -22,7 +22,7 @@ namespace Microsoft.PowerShell.Commands /// this class as a wrapper to MemoryStream to lazily initialize. Otherwise, the /// content will unnecessarily be read even if there are no consumers for it. /// - internal class WebResponseContentMemoryStream : MemoryStream + internal sealed class WebResponseContentMemoryStream : MemoryStream { #region Data diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs index 6157849eeec..6473d6d4fae 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs @@ -715,7 +715,7 @@ protected override void ProcessRecord() /// /// Helper class to import single XML file. /// - internal class ImportXmlHelper : IDisposable + internal sealed class ImportXmlHelper : IDisposable { #region constructor diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs index 357e0222b6d..b7e4ed279aa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/MshHostTraceListener.cs @@ -17,7 +17,7 @@ namespace Microsoft.PowerShell.Commands /// This trace listener cannot be specified in the app.config file. /// It must be added through the add-tracelistener cmdlet. /// - internal class PSHostTraceListener + internal sealed class PSHostTraceListener : System.Diagnostics.TraceListener { #region TraceListener constructors and disposer diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs index 91cb0d46abc..2bf7045cbed 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs @@ -323,7 +323,7 @@ public void Dispose() /// cmdlet. It gets attached to the sub-pipelines success or error pipeline and redirects /// all objects written to these pipelines to trace-command pipeline. /// - internal class TracePipelineWriter : PipelineWriter + internal sealed class TracePipelineWriter : PipelineWriter { internal TracePipelineWriter( TraceListenerCommandBase cmdlet, From 10a8226f869723c77df76c8b2ac3154e319b6ea9 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:29:54 -0500 Subject: [PATCH 012/378] Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25885) --- .pipelines/MSIXBundle-vPack-Official.yml | 3 +- ...werShell-Coordinated_Packages-Official.yml | 37 +++++++++++-------- .pipelines/PowerShell-Packages-Official.yml | 31 ++++++++-------- .../PowerShell-Release-Official-Azure.yml | 13 +++++-- .pipelines/PowerShell-Release-Official.yml | 19 +++++++--- .pipelines/PowerShell-vPack-Official.yml | 3 +- 6 files changed, 63 insertions(+), 43 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index f20e8a31114..ef96f63f045 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -68,11 +68,10 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: enabled: false + exactToolVersion: 4.4.2 # APIScan requires a non-Ready-To-Run build apiscan: enabled: false - asyncSDL: - enabled: false tsaOptionsFile: .config/tsaoptions.json stages: diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 902c31f8a96..efc28942fcc 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -30,6 +30,10 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false + - name: OfficialBuild + type: boolean + default: false + resources: repositories: @@ -87,10 +91,18 @@ variables: value: true ${{ else }}: value: false - + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true + # Disable BinSkim at job level to override NonOfficial template defaults + - name: ob_sdl_binskim_enabled + value: false + extends: - template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates + template: ${{ variables.templateFile }} parameters: customTags: 'ES365AIMigrationTooling' featureFlags: @@ -98,6 +110,7 @@ extends: Network: KS3 WindowsHostVersion: Network: KS3 + incrementalSDLBinaryAnalysis: true globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. @@ -116,19 +129,13 @@ extends: cg: enabled: true ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' - asyncSdl: - enabled: true - forStages: [prep, macos, linux, windows, test_and_release_artifacts] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory) - suppressionsFile: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - binskim: - enabled: false - # APIScan requires a non-Ready-To-Run build - apiscan: - enabled: false - tsaOptionsFile: .config\tsaoptions.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 487e8cb9c6a..f0d428bf1d6 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,7 +24,10 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - + - name: OfficialBuild + type: boolean + default: false + name: pkgs-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) variables: @@ -61,6 +64,9 @@ variables: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: MSIXSigningProfile + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + resources: pipelines: @@ -79,7 +85,7 @@ resources: ref: refs/heads/main extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: cloudvault: enabled: false @@ -88,6 +94,7 @@ extends: Version: 2022 Network: KS3 linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. @@ -104,19 +111,13 @@ extends: cg: enabled: true ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' - asyncSdl: - enabled: true - forStages: ['build'] - credscan: - enabled: true - scanFolder: $(Build.SourcesDirectory) - suppressionsFile: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - binskim: - enabled: false - # APIScan requires a non-Ready-To-Run build - apiscan: - enabled: false - tsaOptionsFile: .config\tsaoptions.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep jobs: diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 2d644c7a5dd..8e144f1ee55 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -13,6 +13,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' + - name: OfficialBuild + type: boolean + default: false name: ev2-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) @@ -46,6 +49,9 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 - group: PoolNames + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + resources: repositories: @@ -67,13 +73,14 @@ resources: - releases/* extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: featureFlags: WindowsHostVersion: Version: 2022 Network: Netlock linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true cloudvault: enabled: false globalSdl: @@ -81,9 +88,6 @@ extends: # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. armory: enabled: false - asyncSdl: - enabled: true - tsaOptionsFile: .config/tsaoptions.json tsa: enabled: true credscan: @@ -92,6 +96,7 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' tsaOptionsFile: .config\tsaoptions.json diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 0c41442da9f..8c3e8728533 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -25,6 +25,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location type: boolean default: false + - name: OfficialBuild + type: boolean + default: false name: release-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) @@ -58,6 +61,13 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + - name: releaseEnvironment + value: ${{ iif ( parameters.OfficialBuild, 'Production', 'Test' ) }} + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true resources: repositories: @@ -83,7 +93,7 @@ resources: - releases/* extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates + template: ${{ variables.templateFile }} parameters: release: category: NonAzure @@ -91,6 +101,7 @@ extends: WindowsHostVersion: Version: 2022 Network: KS3 + incrementalSDLBinaryAnalysis: true cloudvault: enabled: false globalSdl: @@ -98,9 +109,6 @@ extends: # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. armory: enabled: false - asyncSdl: - enabled: true - tsaOptionsFile: .config/tsaoptions.json tsa: enabled: true credscan: @@ -109,6 +117,7 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' # suppression: @@ -279,7 +288,7 @@ extends: - setReleaseTagAndChangelog - UpdateChangeLog variables: - ob_release_environment: Production + ob_release_environment: ${{ parameters.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-githubNuget.yml@self parameters: diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 36b6505dd04..a1bb28c0e19 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -93,11 +93,10 @@ extends: suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json binskim: enabled: false + exactToolVersion: 4.4.2 # APIScan requires a non-Ready-To-Run build apiscan: enabled: false - asyncSDL: - enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - stage: main From b6e207b75f68123ee6f1ef812d9ae072b7ba5416 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:36:57 -0700 Subject: [PATCH 013/378] Bump github/codeql-action from 3.29.10 to 3.29.11 (#25889) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 44d03268972..fac55a45df5 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 + uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 + uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index b8b45af778b..b8d5abb5957 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@96f518a34f7a870018057716cc4d7a5c014bd61c # v3.29.5 + uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 with: sarif_file: results.sarif From 16aeaba68f998b2558b056e633785a54402c5bf9 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 26 Aug 2025 13:37:40 -0700 Subject: [PATCH 014/378] Fix stderr output of console host to respect NO_COLOR (#24391) Co-authored-by: Patrick Meinecke --- .../host/msh/ConsoleHostUserInterface.cs | 1 + test/powershell/Host/ConsoleHost.Tests.ps1 | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs index 9587d6cd553..51fe8203d80 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs @@ -1396,6 +1396,7 @@ public override void WriteErrorLine(string value) } else { + value = GetOutputString(value, SupportsVirtualTerminal); Console.Error.WriteLine(value); } } diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index ec0e80de5c5..12da91bf19e 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -1203,4 +1203,19 @@ Describe 'TERM env var' -Tag CI { $env:NO_COLOR = $null } } + + It 'No_COLOR should be respected for redirected output' { + $psi = [System.Diagnostics.ProcessStartInfo] @{ + FileName = 'pwsh' + # Pass a command that succeeds and normally produces colored output, and one that produces error output. + Arguments = '-NoProfile -Command Get-Item .; Get-Content \nosuch123' + # Redirect (capture) both stdout and stderr. + RedirectStandardOutput = $true + RedirectStandardError = $true + } + $psi.Environment.Add('NO_COLOR', 1) + ($ps = [System.Diagnostics.Process]::Start($psi)).WaitForExit() + $ps.StandardOutput.ReadToEnd() | Should -Not -Contain '\e' + $ps.StandardError.ReadToEnd() | Should -Not -Contain '\e' + } } From 44e34f0044c604e569511cd2bc0f2eac3b99ba88 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 26 Aug 2025 16:06:23 -0700 Subject: [PATCH 015/378] Change the default feedback provider timeout from 300ms to 1000ms (#25910) --- .../engine/Subsystem/FeedbackSubsystem/FeedbackHub.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/FeedbackHub.cs b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/FeedbackHub.cs index 588cf086d42..b1aa781fea7 100644 --- a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/FeedbackHub.cs +++ b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/FeedbackHub.cs @@ -52,7 +52,7 @@ public static class FeedbackHub /// public static List? GetFeedback(Runspace runspace) { - return GetFeedback(runspace, millisecondsTimeout: 300); + return GetFeedback(runspace, millisecondsTimeout: 1000); } /// From cf2d7021ab58d758507cdd493c9254e888b302f1 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 28 Aug 2025 06:54:18 +0100 Subject: [PATCH 016/378] Remove redundant `System.Runtime.Versioning` attributes (#25926) --- .../namespaces/TransactedRegistry.cs | 5 --- .../namespaces/TransactedRegistryKey.cs | 32 ------------------- .../namespaces/Win32Native.cs | 4 --- 3 files changed, 41 deletions(-) diff --git a/src/System.Management.Automation/namespaces/TransactedRegistry.cs b/src/System.Management.Automation/namespaces/TransactedRegistry.cs index 56062e6de6c..6465ea1819c 100644 --- a/src/System.Management.Automation/namespaces/TransactedRegistry.cs +++ b/src/System.Management.Automation/namespaces/TransactedRegistry.cs @@ -42,7 +42,6 @@ internal static class TransactedRegistry /// subkeys, there must be a Transaction.Current and the resulting TransactedRegistryKey from those operations ARE associated with /// the transaction. /// - [ResourceExposure(ResourceScope.Machine)] // The TransactedRegistryKey's members cannot be changed. [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly TransactedRegistryKey CurrentUser = TransactedRegistryKey.GetBaseKey(BaseRegistryKeys.HKEY_CURRENT_USER); @@ -61,7 +60,6 @@ internal static class TransactedRegistry /// subkeys, there must be a Transaction.Current and the resulting TransactedRegistryKey from those operations ARE associated with /// the transaction. /// - [ResourceExposure(ResourceScope.Machine)] // The TransactedRegistryKey's members cannot be changed. [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly TransactedRegistryKey LocalMachine = TransactedRegistryKey.GetBaseKey(BaseRegistryKeys.HKEY_LOCAL_MACHINE); @@ -80,7 +78,6 @@ internal static class TransactedRegistry /// subkeys, there must be a Transaction.Current and the resulting TransactedRegistryKey from those operations ARE associated with /// the transaction. /// - [ResourceExposure(ResourceScope.Machine)] // The TransactedRegistryKey's members cannot be changed. [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly TransactedRegistryKey ClassesRoot = TransactedRegistryKey.GetBaseKey(BaseRegistryKeys.HKEY_CLASSES_ROOT); @@ -99,7 +96,6 @@ internal static class TransactedRegistry /// subkeys, there must be a Transaction.Current and the resulting TransactedRegistryKey from those operations ARE associated with /// the transaction. /// - [ResourceExposure(ResourceScope.Machine)] // The TransactedRegistryKey's members cannot be changed. [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly TransactedRegistryKey Users = TransactedRegistryKey.GetBaseKey(BaseRegistryKeys.HKEY_USERS); @@ -118,7 +114,6 @@ internal static class TransactedRegistry /// subkeys, there must be a Transaction.Current and the resulting TransactedRegistryKey from those operations ARE associated with /// the transaction. /// - [ResourceExposure(ResourceScope.Machine)] // The TransactedRegistryKey's members cannot be changed. [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly TransactedRegistryKey CurrentConfig = TransactedRegistryKey.GetBaseKey(BaseRegistryKeys.HKEY_CURRENT_CONFIG); diff --git a/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs b/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs index 23316a31724..0460ba690dc 100644 --- a/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs +++ b/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs @@ -346,8 +346,6 @@ public void Dispose() /// otherwise an ArgumentException is thrown. /// A TransactedRegistryKey object for the subkey, which is associated with Transaction.Current. /// returns null if the operation failed. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey CreateSubKey(string subkey) @@ -366,8 +364,6 @@ public TransactedRegistryKey CreateSubKey(string subkey) /// One of the Microsoft.Win32.RegistryKeyPermissionCheck values that /// specifies whether the key is opened for read or read/write access. [ComVisible(false)] - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck) @@ -387,8 +383,6 @@ public TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCh /// specifies whether the key is opened for read or read/write access. /// A TransactedRegistrySecurity object that specifies the access control security for the new key. [ComVisible(false)] - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public unsafe TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck, TransactedRegistrySecurity registrySecurity) @@ -397,8 +391,6 @@ public unsafe TransactedRegistryKey CreateSubKey(string subkey, RegistryKeyPermi } [ComVisible(false)] - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] private unsafe TransactedRegistryKey CreateSubKeyInternal(string subkey, RegistryKeyPermissionCheck permissionCheck, object registrySecurityObj) @@ -489,8 +481,6 @@ private unsafe TransactedRegistryKey CreateSubKeyInternal(string subkey, Registr /// Thrown if the subkey as child subkeys. /// /// The subkey to delete. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public void DeleteSubKey(string subkey) @@ -510,8 +500,6 @@ public void DeleteSubKey(string subkey) /// Specify true if an ArgumentException should be thrown if /// the specified subkey does not exist. If false is specified, a missing subkey does not throw /// an exception. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public void DeleteSubKey(string subkey, bool throwOnMissingSubKey) @@ -569,8 +557,6 @@ public void DeleteSubKey(string subkey, bool throwOnMissingSubKey) /// Utilizes Transaction.Current for its transaction. /// /// The subkey to delete. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public void DeleteSubKeyTree(string subkey) @@ -626,8 +612,6 @@ public void DeleteSubKeyTree(string subkey) // An internal version which does no security checks or argument checking. Skipping the // security checks should give us a slight perf gain on large trees. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] private void DeleteSubKeyTreeInternal(string subkey) @@ -672,8 +656,6 @@ private void DeleteSubKeyTreeInternal(string subkey) /// Utilizes Transaction.Current for its transaction. /// /// Name of the value to delete. - [ResourceExposure(ResourceScope.None)] - [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public void DeleteValue(string name) { DeleteValue(name, true); @@ -687,8 +669,6 @@ public void DeleteValue(string name) /// Specify true if an ArgumentException should be thrown if /// the specified value does not exist. If false is specified, a missing value does not throw /// an exception. - [ResourceExposure(ResourceScope.None)] - [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public void DeleteValue(string name, bool throwOnMissingValue) { EnsureWriteable(); @@ -758,8 +738,6 @@ internal static TransactedRegistryKey GetBaseKey(IntPtr hKey) /// The subkey requested or null if the operation failed. /// Name or path of the subkey to open. /// Set to true of you only need readonly access. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey OpenSubKey(string name, bool writable) @@ -803,8 +781,6 @@ public TransactedRegistryKey OpenSubKey(string name, bool writable) /// One of the Microsoft.Win32.RegistryKeyPermissionCheck values that specifies /// whether the key is opened for read or read/write access. [ComVisible(false)] - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck) @@ -823,8 +799,6 @@ public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck /// whether the key is opened for read or read/write access. /// A bitwise combination of Microsoft.Win32.RegistryRights values that specifies the desired security access. [ComVisible(false)] - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights) @@ -832,8 +806,6 @@ public TransactedRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck return InternalOpenSubKey(name, permissionCheck, (int)rights); } - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] private TransactedRegistryKey InternalOpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, int rights) @@ -874,8 +846,6 @@ private TransactedRegistryKey InternalOpenSubKey(string name, RegistryKeyPermiss // This required no security checks. This is to get around the Deleting SubKeys which only require // write permission. They call OpenSubKey which required read. Now instead call this function w/o security checks - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] internal TransactedRegistryKey InternalOpenSubKey(string name, bool writable) @@ -906,8 +876,6 @@ internal TransactedRegistryKey InternalOpenSubKey(string name, bool writable) /// /// The subkey requested or null if the operation failed. /// Name or path of the subkey to open. - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] // Suppressed to be consistent with naming in Microsoft.Win32.RegistryKey [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] public TransactedRegistryKey OpenSubKey(string name) diff --git a/src/System.Management.Automation/namespaces/Win32Native.cs b/src/System.Management.Automation/namespaces/Win32Native.cs index b785cd5fbb8..f42951602eb 100644 --- a/src/System.Management.Automation/namespaces/Win32Native.cs +++ b/src/System.Management.Automation/namespaces/Win32Native.cs @@ -106,7 +106,6 @@ internal struct TOKEN_USER /// /// [DllImport(PinvokeDllNames.LookupAccountSidDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [ResourceExposure(ResourceScope.Machine)] [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] private static extern unsafe bool LookupAccountSid(string lpSystemName, @@ -139,7 +138,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, } [DllImport(PinvokeDllNames.CloseHandleDllName, SetLastError = true)] - [ResourceExposure(ResourceScope.Machine)] [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); @@ -152,7 +150,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, /// Process token. /// The current process token. [DllImport(PinvokeDllNames.OpenProcessTokenDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [ResourceExposure(ResourceScope.Machine)] [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle); @@ -168,7 +165,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, /// /// [DllImport(PinvokeDllNames.GetTokenInformationDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [ResourceExposure(ResourceScope.Machine)] [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetTokenInformation(IntPtr tokenHandle, From 8d524adf7f3d44a6ac28b0082fddbbfbe7bb21a8 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 29 Aug 2025 06:57:40 +0100 Subject: [PATCH 017/378] Remove obsolete `CA2118` rule suppression (#25924) --- .../namespaces/TransactedRegistryKey.cs | 3 --- src/System.Management.Automation/namespaces/Win32Native.cs | 4 ---- src/System.Management.Automation/utils/PlatformInvokes.cs | 6 ------ 3 files changed, 13 deletions(-) diff --git a/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs b/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs index 0460ba690dc..d899d9257b4 100644 --- a/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs +++ b/src/System.Management.Automation/namespaces/TransactedRegistryKey.cs @@ -141,9 +141,6 @@ public sealed class TransactedRegistryKey : MarshalByRefObject, IDisposable // If that call fails with ERROR_INVALID_TRANSACTION, we have possibly run into bug 181242. To workaround // this, we open the key without a transaction and then open it again with // a transaction and return THAT hkey. - - // Suppressed because there is no way for arbitrary data to be passed. - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] private int RegOpenKeyTransactedWrapper(SafeRegistryHandle hKey, string lpSubKey, int ulOptions, int samDesired, out SafeRegistryHandle hkResult, SafeTransactionHandle hTransaction, IntPtr pExtendedParameter) diff --git a/src/System.Management.Automation/namespaces/Win32Native.cs b/src/System.Management.Automation/namespaces/Win32Native.cs index f42951602eb..5c668fd471f 100644 --- a/src/System.Management.Automation/namespaces/Win32Native.cs +++ b/src/System.Management.Automation/namespaces/Win32Native.cs @@ -106,7 +106,6 @@ internal struct TOKEN_USER /// /// [DllImport(PinvokeDllNames.LookupAccountSidDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] private static extern unsafe bool LookupAccountSid(string lpSystemName, IntPtr sid, @@ -138,7 +137,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, } [DllImport(PinvokeDllNames.CloseHandleDllName, SetLastError = true)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); @@ -150,7 +148,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, /// Process token. /// The current process token. [DllImport(PinvokeDllNames.OpenProcessTokenDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle); @@ -165,7 +162,6 @@ internal static unsafe bool LookupAccountSid(string lpSystemName, /// /// [DllImport(PinvokeDllNames.GetTokenInformationDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetTokenInformation(IntPtr tokenHandle, TOKEN_INFORMATION_CLASS tokenInformationClass, diff --git a/src/System.Management.Automation/utils/PlatformInvokes.cs b/src/System.Management.Automation/utils/PlatformInvokes.cs index 0993a9c1348..fbd4117e844 100644 --- a/src/System.Management.Automation/utils/PlatformInvokes.cs +++ b/src/System.Management.Automation/utils/PlatformInvokes.cs @@ -235,7 +235,6 @@ internal static extern IntPtr CreateFile( /// [DllImport(PinvokeDllNames.CloseHandleDllName, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - // [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] internal static extern bool CloseHandle(IntPtr handle); [DllImport(PinvokeDllNames.DosDateTimeToFileTimeDllName, SetLastError = false)] @@ -412,7 +411,6 @@ internal static bool RestoreTokenPrivilege(string privilegeName, ref TOKEN_PRIVI /// /// [DllImport(PinvokeDllNames.LookupPrivilegeValueDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid); @@ -424,7 +422,6 @@ internal static bool RestoreTokenPrivilege(string privilegeName, ref TOKEN_PRIVI /// /// [DllImport(PinvokeDllNames.PrivilegeCheckDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool PrivilegeCheck(IntPtr tokenHandler, ref PRIVILEGE_SET requiredPrivileges, out bool pfResult); @@ -441,7 +438,6 @@ internal static bool RestoreTokenPrivilege(string privilegeName, ref TOKEN_PRIVI /// /// [DllImport(PinvokeDllNames.AdjustTokenPrivilegesDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool AdjustTokenPrivileges(IntPtr tokenHandler, bool disableAllPrivilege, ref TOKEN_PRIVILEGE newPrivilegeState, int bufferLength, @@ -482,7 +478,6 @@ internal struct PRIVILEGE_SET /// /// [DllImport(PinvokeDllNames.GetCurrentProcessDllName)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] internal static extern IntPtr GetCurrentProcess(); /// @@ -494,7 +489,6 @@ internal struct PRIVILEGE_SET /// Process token. /// The current process token. [DllImport(PinvokeDllNames.OpenProcessTokenDllName, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle); From 53805fb426d4e60601c9013287cbc2690aaef1e0 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 29 Aug 2025 15:50:02 -0700 Subject: [PATCH 018/378] Add the parameter `Register-ArgumentCompleter -NativeFallback` to support registering a cover-all completer for native commands (#25230) --- .../CommandCompletion/CompletionCompleters.cs | 12 ++- .../CommandCompletion/ExtensibleCompletion.cs | 96 ++++++++++++++----- .../engine/hostifaces/LocalPipeline.cs | 4 +- .../engine/lang/scriptblock.cs | 2 +- .../TabCompletion/TabCompletion.Tests.ps1 | 52 +++++++++- 5 files changed, 133 insertions(+), 33 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 880aedb04ce..10ce5c851e6 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -2638,9 +2638,8 @@ private static ScriptBlock GetCustomArgumentCompleter( } } - var registeredCompleters = optionKey.Equals("NativeArgumentCompleters", StringComparison.OrdinalIgnoreCase) - ? context.NativeArgumentCompleters - : context.CustomArgumentCompleters; + bool isNative = optionKey.Equals("NativeArgumentCompleters", StringComparison.OrdinalIgnoreCase); + var registeredCompleters = isNative ? context.NativeArgumentCompleters : context.CustomArgumentCompleters; if (registeredCompleters != null) { @@ -2651,6 +2650,13 @@ private static ScriptBlock GetCustomArgumentCompleter( return scriptBlock; } } + + // For a native command, if a fallback completer is registered, then return it. + // For example, the 'Microsoft.PowerShell.UnixTabCompletion' module. + if (isNative && registeredCompleters.TryGetValue(RegisterArgumentCompleterCommand.FallbackCompleterKey, out scriptBlock)) + { + return scriptBlock; + } } return null; diff --git a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs index 2b5281a8f26..c63a8e7f92d 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs @@ -172,66 +172,110 @@ public abstract class ArgumentCompleterFactoryAttribute : ArgumentCompleterAttri [Cmdlet(VerbsLifecycle.Register, "ArgumentCompleter", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528576")] public class RegisterArgumentCompleterCommand : PSCmdlet { + private const string PowerShellSetName = "PowerShellSet"; + private const string NativeCommandSetName = "NativeCommandSet"; + private const string NativeFallbackSetName = "NativeFallbackSet"; + + // Use a key that is unlikely to be a file name or path to indicate the fallback completer for native commands. + internal const string FallbackCompleterKey = "___ps::@@___"; + /// + /// Gets or sets the command names for which the argument completer is registered. /// - [Parameter(ParameterSetName = "NativeSet", Mandatory = true)] - [Parameter(ParameterSetName = "PowerShellSet")] + [Parameter(ParameterSetName = NativeCommandSetName, Mandatory = true)] + [Parameter(ParameterSetName = PowerShellSetName)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] CommandName { get; set; } /// + /// Gets or sets the name of the parameter for which the argument completer is registered. /// - [Parameter(ParameterSetName = "PowerShellSet", Mandatory = true)] + [Parameter(ParameterSetName = PowerShellSetName, Mandatory = true)] public string ParameterName { get; set; } /// + /// Gets or sets the script block that will be executed to provide argument completions. /// [Parameter(Mandatory = true)] [AllowNull()] public ScriptBlock ScriptBlock { get; set; } /// + /// Indicates the argument completer is for native commands. /// - [Parameter(ParameterSetName = "NativeSet")] + [Parameter(ParameterSetName = NativeCommandSetName)] public SwitchParameter Native { get; set; } + /// + /// Indicates the argument completer is a fallback for any native commands that don't have a completer registered. + /// + [Parameter(ParameterSetName = NativeFallbackSetName)] + public SwitchParameter NativeFallback { get; set; } + /// /// protected override void EndProcessing() { Dictionary completerDictionary; - if (ParameterName != null) + + if (ParameterSetName is NativeFallbackSetName) { - completerDictionary = Context.CustomArgumentCompleters ?? - (Context.CustomArgumentCompleters = new Dictionary(StringComparer.OrdinalIgnoreCase)); + completerDictionary = Context.NativeArgumentCompleters ??= new(StringComparer.OrdinalIgnoreCase); + + SetKeyValue(completerDictionary, FallbackCompleterKey, ScriptBlock); } - else + else if (ParameterSetName is NativeCommandSetName) { - completerDictionary = Context.NativeArgumentCompleters ?? - (Context.NativeArgumentCompleters = new Dictionary(StringComparer.OrdinalIgnoreCase)); - } + completerDictionary = Context.NativeArgumentCompleters ??= new(StringComparer.OrdinalIgnoreCase); - if (CommandName == null || CommandName.Length == 0) + foreach (string command in CommandName) + { + var key = command?.Trim(); + if (string.IsNullOrEmpty(key)) + { + continue; + } + + SetKeyValue(completerDictionary, key, ScriptBlock); + } + } + else if (ParameterSetName is PowerShellSetName) { - CommandName = new[] { string.Empty }; + completerDictionary = Context.CustomArgumentCompleters ??= new(StringComparer.OrdinalIgnoreCase); + + string paramName = ParameterName.Trim(); + if (paramName.Length is 0) + { + return; + } + + if (CommandName is null || CommandName.Length is 0) + { + SetKeyValue(completerDictionary, paramName, ScriptBlock); + return; + } + + foreach (string command in CommandName) + { + var key = command?.Trim(); + key = string.IsNullOrEmpty(key) + ? paramName + : $"{key}:{paramName}"; + + SetKeyValue(completerDictionary, key, ScriptBlock); + } } - for (int i = 0; i < CommandName.Length; i++) + static void SetKeyValue(Dictionary table, string key, ScriptBlock value) { - var key = CommandName[i]; - if (!string.IsNullOrWhiteSpace(ParameterName)) + if (value is null) { - if (!string.IsNullOrWhiteSpace(key)) - { - key = key + ":" + ParameterName; - } - else - { - key = ParameterName; - } + table.Remove(key); + } + else + { + table[key] = value; } - - completerDictionary[key] = ScriptBlock; } } } diff --git a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs index 93cb65f3f07..a9a3a66b859 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs @@ -1067,9 +1067,9 @@ internal override void SetHistoryString(string historyString) /// ExecutionContext, if it available in TLS /// Null, if ExecutionContext is not available in TLS /// - internal static System.Management.Automation.ExecutionContext GetExecutionContextFromTLS() + internal static ExecutionContext GetExecutionContextFromTLS() { - System.Management.Automation.Runspaces.Runspace runspace = Runspace.DefaultRunspace; + Runspace runspace = Runspace.DefaultRunspace; if (runspace == null) { return null; diff --git a/src/System.Management.Automation/engine/lang/scriptblock.cs b/src/System.Management.Automation/engine/lang/scriptblock.cs index 7bbd33c9cfd..06fa66d0f7c 100644 --- a/src/System.Management.Automation/engine/lang/scriptblock.cs +++ b/src/System.Management.Automation/engine/lang/scriptblock.cs @@ -104,7 +104,7 @@ internal static ScriptBlock Create(ExecutionContext context, string script) /// /// The string to compile. public static ScriptBlock Create(string script) => Create( - parser: new Language.Parser(), + parser: new Parser(), fileName: null, fileContents: script); diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index 8e4fdd9d660..046d00b442f 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -1929,8 +1929,12 @@ param([ValidatePattern( Context NativeCommand { BeforeAll { - $nativeCommand = (Get-Command -CommandType Application -TotalCount 1).Name + ## Find a native command that is not 'pwsh'. We will use 'pwsh' for fallback completer tests later. + $nativeCommand = Get-Command -CommandType Application -TotalCount 2 | + Where-Object Name -NotLike pwsh* | + Select-Object -First 1 } + It 'Completes native commands with -' { Register-ArgumentCompleter -Native -CommandName $nativeCommand -ScriptBlock { param($wordToComplete, $ast, $cursorColumn) @@ -1994,6 +1998,52 @@ param([ValidatePattern( $res.CompletionMatches | Should -HaveCount 1 $res.CompletionMatches.CompletionText | Should -BeExactly "-option" } + + It 'Covers an arbitrary unbound native command with -t' { + ## Register a completer for $nativeCommand. + Register-ArgumentCompleter -Native -CommandName $nativeCommand -ScriptBlock { + param($wordToComplete, $ast, $cursorColumn) + if ($wordToComplete -eq '-t') { + return "-terminal" + } + } + + ## Register a fallback native command completer. + Register-ArgumentCompleter -NativeFallback -ScriptBlock { + param($wordToComplete, $ast, $cursorColumn) + if ($wordToComplete -eq '-t') { + return "-testing" + } + } + + ## The specific completer will be used if it exists. + $line = "$nativeCommand -t" + $res = TabExpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches | Should -HaveCount 1 + $res.CompletionMatches.CompletionText | Should -BeExactly "-terminal" + + ## Otherwise, the fallback completer will kick in. + $line = "pwsh -t" + $res = TabExpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches | Should -HaveCount 1 + $res.CompletionMatches.CompletionText | Should -BeExactly "-testing" + + ## Remove the completer for $nativeCommand. + Register-ArgumentCompleter -Native -CommandName $nativeCommand -ScriptBlock $null + + ## The fallback completer will be used for $nativeCommand. + $line = "$nativeCommand -t" + $res = TabExpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches | Should -HaveCount 1 + $res.CompletionMatches.CompletionText | Should -BeExactly "-testing" + + ## Remove the fallback completer for $nativeCommand. + Register-ArgumentCompleter -NativeFallback -ScriptBlock $null + + ## The fallback completer will be used for $nativeCommand. + $res = TabExpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches | Should -HaveCount 0 + } } It 'Should complete "Export-Counter -FileFormat" with available output formats' -Pending { From 32e877ba40f0312ec59db6de7b0dedf0007e9044 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:45:09 -0700 Subject: [PATCH 019/378] Bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#25930) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 2044eea6ffc..c0f2e6e0092 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@bc41886e18ea39df68b1b1245f4184881938e050 # v4.7.2 + uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3 From 41ecc6847cd80c49dbf4f0a2a546a2f931fecf1f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sat, 30 Aug 2025 20:12:14 +0100 Subject: [PATCH 020/378] Remove obsolete `CA1059` rule suppression (#25940) --- .../GetEventCommand.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs index 3aec30c9e4c..c7a07bab6ec 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs @@ -225,10 +225,6 @@ public sealed class GetWinEventCommand : PSCmdlet ValueFromPipelineByPropertyName = false, ParameterSetName = "XmlQuerySet", HelpMessageBaseName = "GetEventResources")] - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", - Scope = "member", - Target = "Microsoft.PowerShell.Commands.GetEvent.FilterXml", - Justification = "An XmlDocument is required here because that is the type Powershell supports")] public XmlDocument FilterXml { get; set; } /// From eda56e282e5f9f17e7553348dccec8d544ce8685 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 31 Aug 2025 19:20:07 +0100 Subject: [PATCH 021/378] Remove obsolete `CA1026` rule suppression (#25934) --- .../engine/CommandCompletion/CompletionCompleters.cs | 1 - .../utils/perfCounters/CounterSetRegistrarBase.cs | 2 -- .../utils/perfCounters/PSPerfCountersMgr.cs | 8 -------- 3 files changed, 11 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 10ce5c851e6..8ca133cf1c2 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -64,7 +64,6 @@ public static IEnumerable CompleteCommand(string commandName) /// /// /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public static IEnumerable CompleteCommand(string commandName, string moduleName, CommandTypes commandTypes = CommandTypes.All) { var runspace = Runspace.DefaultRunspace; diff --git a/src/System.Management.Automation/utils/perfCounters/CounterSetRegistrarBase.cs b/src/System.Management.Automation/utils/perfCounters/CounterSetRegistrarBase.cs index f9a08b76a87..1ea57a16912 100644 --- a/src/System.Management.Automation/utils/perfCounters/CounterSetRegistrarBase.cs +++ b/src/System.Management.Automation/utils/perfCounters/CounterSetRegistrarBase.cs @@ -95,7 +95,6 @@ public abstract class CounterSetRegistrarBase /// based on Provider Id, counterSetId, counterSetInstanceType, a collection /// with counters information and an optional counterSetName. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] protected CounterSetRegistrarBase( Guid providerId, Guid counterSetId, @@ -220,7 +219,6 @@ public class PSCounterSetRegistrar : CounterSetRegistrarBase /// /// Constructor that creates an instance of PSCounterSetRegistrar. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public PSCounterSetRegistrar( Guid providerId, Guid counterSetId, diff --git a/src/System.Management.Automation/utils/perfCounters/PSPerfCountersMgr.cs b/src/System.Management.Automation/utils/perfCounters/PSPerfCountersMgr.cs index 761de0c6360..7a49a5c6f9f 100644 --- a/src/System.Management.Automation/utils/perfCounters/PSPerfCountersMgr.cs +++ b/src/System.Management.Automation/utils/perfCounters/PSPerfCountersMgr.cs @@ -162,7 +162,6 @@ public bool AddCounterSetInstance(CounterSetRegistrarBase counterSetRegistrarIns /// by 'stepAmount'. /// Otherwise, updates the denominator component by 'stepAmount'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool UpdateCounterByValue( Guid counterSetId, int counterId, @@ -193,7 +192,6 @@ public bool UpdateCounterByValue( /// by 'stepAmount'. /// Otherwise, updates the denominator component by 'stepAmount'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool UpdateCounterByValue( Guid counterSetId, string counterName, @@ -224,7 +222,6 @@ public bool UpdateCounterByValue( /// by 'stepAmount'. /// Otherwise, updates the denominator component by 'stepAmount'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool UpdateCounterByValue( string counterSetName, int counterId, @@ -264,7 +261,6 @@ public bool UpdateCounterByValue( /// by 'stepAmount'. /// Otherwise, updates the denominator component by 'stepAmount'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool UpdateCounterByValue( string counterSetName, string counterName, @@ -303,7 +299,6 @@ public bool UpdateCounterByValue( /// to 'counterValue'. /// Otherwise, updates the denominator component to 'counterValue'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool SetCounterValue( Guid counterSetId, int counterId, @@ -334,7 +329,6 @@ public bool SetCounterValue( /// to 'counterValue'. /// Otherwise, updates the denominator component to 'counterValue'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool SetCounterValue( Guid counterSetId, string counterName, @@ -365,7 +359,6 @@ public bool SetCounterValue( /// to 'counterValue'. /// Otherwise, updates the denominator component to 'counterValue'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool SetCounterValue( string counterSetName, int counterId, @@ -404,7 +397,6 @@ public bool SetCounterValue( /// to 'counterValue'. /// Otherwise, updates the denominator component to 'counterValue'. /// - [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")] public bool SetCounterValue( string counterSetName, string counterName, From 3b6f267e199c4e8ab80a811636e5d1ad7962d57d Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 1 Sep 2025 04:56:16 +0100 Subject: [PATCH 022/378] Remove obsolete `CA2233` rule suppression (#25951) --- .../utils/perfCounters/CounterSetInstanceBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/System.Management.Automation/utils/perfCounters/CounterSetInstanceBase.cs b/src/System.Management.Automation/utils/perfCounters/CounterSetInstanceBase.cs index fc3f048b828..995b41fcda1 100644 --- a/src/System.Management.Automation/utils/perfCounters/CounterSetInstanceBase.cs +++ b/src/System.Management.Automation/utils/perfCounters/CounterSetInstanceBase.cs @@ -74,7 +74,6 @@ protected CounterSetInstanceBase(CounterSetRegistrarBase counterSetRegistrarInst /// But, if isNumerator is false, then a check is made on the input /// counter's type to ensure that denominator is indeed value for such a counter. /// - [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", Justification = "countId is validated as known denominator before it is incremented.")] protected bool RetrieveTargetCounterIdIfValid(int counterId, bool isNumerator, out int targetCounterId) { targetCounterId = counterId; From f455b3b123a9df6975b28e1f8cef8704cc7a5b54 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 1 Sep 2025 05:00:22 +0100 Subject: [PATCH 023/378] Remove obsolete `CA1701` rule suppression (#25948) --- .../commands/management/Computer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs index 3b791d37a1a..f2aa1bb74d2 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs @@ -26,7 +26,6 @@ // FxCop suppressions for resource strings: [module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "ComputerResources.resources", MessageId = "unjoined")] -[module: SuppressMessage("Microsoft.Naming", "CA1701:ResourceStringCompoundWordsShouldBeCasedCorrectly", Scope = "resource", Target = "ComputerResources.resources", MessageId = "UpTime")] namespace Microsoft.PowerShell.Commands { From 06ff422d2ac2a6bf99d00c6c0cdd8cdef8fab389 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 2 Sep 2025 04:26:45 +0100 Subject: [PATCH 024/378] Remove obsolete `CA2240` rule suppression (#25957) --- .../engine/NativeCommandProcessor.cs | 1 - src/System.Management.Automation/utils/MetadataExceptions.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 3626b0268e9..8b5b6af93a2 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -2505,7 +2505,6 @@ internal static bool AllocateHiddenConsole() /// This remote instance of PowerShell can be in a separate process, /// appdomain or machine. /// - [SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly")] public class RemoteException : RuntimeException { /// diff --git a/src/System.Management.Automation/utils/MetadataExceptions.cs b/src/System.Management.Automation/utils/MetadataExceptions.cs index f2c4ace8647..24660d348e7 100644 --- a/src/System.Management.Automation/utils/MetadataExceptions.cs +++ b/src/System.Management.Automation/utils/MetadataExceptions.cs @@ -71,7 +71,6 @@ internal MetadataException( /// /// Defines the exception thrown for all Validate attributes. /// - [SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly")] public class ValidationMetadataException : MetadataException { internal const string ValidateRangeElementType = "ValidateRangeElementType"; From 44d366adb254b41a10d50aeb4256f70dd3af39ca Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 2 Sep 2025 04:31:08 +0100 Subject: [PATCH 025/378] Remove obsolete `CA1703` rule suppression (#25955) --- .../commands/management/Computer.cs | 3 --- src/System.Management.Automation/engine/Credential.cs | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs index f2aa1bb74d2..0ea1c91aae6 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs @@ -24,9 +24,6 @@ using Microsoft.Win32; using Dbg = System.Management.Automation; -// FxCop suppressions for resource strings: -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "ComputerResources.resources", MessageId = "unjoined")] - namespace Microsoft.PowerShell.Commands { #region Restart-Computer diff --git a/src/System.Management.Automation/engine/Credential.cs b/src/System.Management.Automation/engine/Credential.cs index b2be0dbfd2e..c921b9a084d 100644 --- a/src/System.Management.Automation/engine/Credential.cs +++ b/src/System.Management.Automation/engine/Credential.cs @@ -10,9 +10,6 @@ using System.Security.Cryptography; using Microsoft.PowerShell; -// FxCop suppressions for resource strings: -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "Credential.resources", MessageId = "Cred")] - namespace System.Management.Automation { /// From 89af9edb18bfa641c7b8729396129d8b03c2cf83 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 2 Sep 2025 14:29:42 -0700 Subject: [PATCH 026/378] Fix typo in CHANGELOG for script filename suggestion (#25962) --- CHANGELOG/7.5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 8cf3dba6282..d2071727790 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -10,7 +10,7 @@ - Set standard handles explicitly when starting a process with `-NoNewWindow` (#25324) - Make inherited protected internal instance members accessible in class scope. (#25547) (Thanks @mawosoft!) -- Remove the old fuzzy suggestion and fix the local script file name suggestion (#25330) +- Remove the old fuzzy suggestion and fix the local script filename suggestion (#25330) - Fix `PSMethodInvocationConstraints.GetHashCode` method (#25306) (Thanks @crazyjncsu!) ### Build and Packaging Improvements From 176e29ac3a46b7689592d748c00961551217b1eb Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 3 Sep 2025 04:44:43 +0100 Subject: [PATCH 027/378] Replace `DOTNET_SKIP_FIRST_TIME_EXPERIENCE` with `DOTNET_NOLOGO` (#25946) --- .github/workflows/linux-ci.yml | 2 +- .github/workflows/macos-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- .pipelines/templates/linux.yml | 4 ++-- .pipelines/templates/release-symbols.yml | 2 +- .pipelines/templates/release-upload-buildinfo.yml | 2 +- .pipelines/templates/release-validate-fxdpackages.yml | 2 +- .pipelines/templates/release-validate-sdk.yml | 2 +- .pipelines/templates/uploadToAzure.yml | 2 +- .pipelines/templates/variable/release-shared.yml | 2 +- .pipelines/templates/windows-hosted-build.yml | 2 +- .vsts-ci/linux-daily.yml | 3 +-- .vsts-ci/linux-internal.yml | 3 +-- .vsts-ci/linux.yml | 3 +-- .vsts-ci/mac.yml | 3 +-- .vsts-ci/psresourceget-acr.yml | 3 +-- .vsts-ci/sshremoting-tests.yml | 3 +-- .vsts-ci/windows-arm64.yml | 3 +-- .vsts-ci/windows-daily.yml | 3 +-- .vsts-ci/windows.yml | 3 +-- .vsts-ci/windows/windows-packaging.yml | 3 +-- 21 files changed, 22 insertions(+), 32 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index fac55a45df5..4eba9eeab6f 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -29,7 +29,7 @@ concurrency: env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 FORCE_FEATURE: 'False' FORCE_PACKAGE: 'False' NUGET_KEY: none diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 83ab691b1bc..8e5f1620bb5 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -27,7 +27,7 @@ concurrency: env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 FORCE_FEATURE: 'False' FORCE_PACKAGE: 'False' HOMEBREW_NO_ANALYTICS: 1 diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 94e1102a31d..1bc6ebe0a1f 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -32,7 +32,7 @@ run-name: "${{ github.ref_name }} - ${{ github.run_number }}" env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" NugetSecurityAnalysisWarningLevel: none POWERSHELL_TELEMETRY_OPTOUT: 1 diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index 398e8fe5fef..6c47fd8abfd 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -14,7 +14,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - group: DotNetPrivateBuildAccess - name: ob_outputDirectory @@ -148,7 +148,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml index 9bfa7b870d4..1023dcf5259 100644 --- a/.pipelines/templates/release-symbols.yml +++ b/.pipelines/templates/release-symbols.yml @@ -14,7 +14,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c8693228847..c18c96fc646 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -18,7 +18,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml index 30a2ab13905..9de8c7dad33 100644 --- a/.pipelines/templates/release-validate-fxdpackages.yml +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -98,7 +98,7 @@ jobs: $artifactName = '$(artifactName)' $rootPath = "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + $env:DOTNET_NOLOGO=1 Import-Module "$repoRoot/build.psm1" -Force Find-Dotnet -SetDotnetRoot Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 6eb800f6326..cdd818f9dc2 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -56,7 +56,7 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + $env:DOTNET_NOLOGO=1 $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" $xmlElement = @" diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index e698a7041da..b330a2eef10 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -11,7 +11,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml index f944639a908..325f72224f5 100644 --- a/.pipelines/templates/variable/release-shared.yml +++ b/.pipelines/templates/variable/release-shared.yml @@ -19,7 +19,7 @@ variables: value: ${{ parameters.SBOM }} - name: runCodesignValidationInjection value: false - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - group: 'mscodehub-code-read-akv' - group: 'Azure Blob variable group' diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 929aa54b8a7..35dadbb839c 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -14,7 +14,7 @@ jobs: value: false - name: NugetSecurityAnalysisWarningLevel value: none - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual diff --git a/.vsts-ci/linux-daily.yml b/.vsts-ci/linux-daily.yml index c1dd96fd0b4..10effadd1e3 100644 --- a/.vsts-ci/linux-daily.yml +++ b/.vsts-ci/linux-daily.yml @@ -25,8 +25,7 @@ pr: variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 resources: diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml index 6286a03fb52..c1c8bcef62d 100644 --- a/.vsts-ci/linux-internal.yml +++ b/.vsts-ci/linux-internal.yml @@ -48,8 +48,7 @@ pr: variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index b386b9c7eb3..5d9dc663e1c 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -48,8 +48,7 @@ pr: variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 05d6d71ea71..4d3681edca1 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -48,8 +48,7 @@ pr: variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 # Turn off Homebrew analytics HOMEBREW_NO_ANALYTICS: 1 __SuppressAnsiEscapeSequences: 1 diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index 1a24983b5b5..ca3334ff271 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -49,8 +49,7 @@ variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 NugetSecurityAnalysisWarningLevel: none nugetMultiFeedWarnLevel: none diff --git a/.vsts-ci/sshremoting-tests.yml b/.vsts-ci/sshremoting-tests.yml index 2eda2a18276..72c5710016b 100644 --- a/.vsts-ci/sshremoting-tests.yml +++ b/.vsts-ci/sshremoting-tests.yml @@ -27,8 +27,7 @@ variables: value: 1 - name: POWERSHELL_TELEMETRY_OPTOUT value: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: __SuppressAnsiEscapeSequences value: 1 diff --git a/.vsts-ci/windows-arm64.yml b/.vsts-ci/windows-arm64.yml index be4cfcbaf4c..4c75c1d31e0 100644 --- a/.vsts-ci/windows-arm64.yml +++ b/.vsts-ci/windows-arm64.yml @@ -45,8 +45,7 @@ variables: value: 1 - name: POWERSHELL_TELEMETRY_OPTOUT value: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: __SuppressAnsiEscapeSequences value: 1 diff --git a/.vsts-ci/windows-daily.yml b/.vsts-ci/windows-daily.yml index 59dd3ba2f36..1e9306e9dd1 100644 --- a/.vsts-ci/windows-daily.yml +++ b/.vsts-ci/windows-daily.yml @@ -32,8 +32,7 @@ variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 resources: diff --git a/.vsts-ci/windows.yml b/.vsts-ci/windows.yml index c0f08f54a41..4171d09643d 100644 --- a/.vsts-ci/windows.yml +++ b/.vsts-ci/windows.yml @@ -42,8 +42,7 @@ variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 __SuppressAnsiEscapeSequences: 1 NugetSecurityAnalysisWarningLevel: none nugetMultiFeedWarnLevel: none diff --git a/.vsts-ci/windows/windows-packaging.yml b/.vsts-ci/windows/windows-packaging.yml index 05f69400719..6b73ca05723 100644 --- a/.vsts-ci/windows/windows-packaging.yml +++ b/.vsts-ci/windows/windows-packaging.yml @@ -47,8 +47,7 @@ variables: value: 1 - name: POWERSHELL_TELEMETRY_OPTOUT value: 1 - # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + - name: DOTNET_NOLOGO value: 1 - name: __SuppressAnsiEscapeSequences value: 1 From 7ef03a14ae3b71f94bae38cce0a0ad086626574b Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 3 Sep 2025 04:45:41 +0100 Subject: [PATCH 028/378] Remove obsolete `CA2105` rule suppression (#25938) --- .../engine/interpreter/InterpretedFrame.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/System.Management.Automation/engine/interpreter/InterpretedFrame.cs b/src/System.Management.Automation/engine/interpreter/InterpretedFrame.cs index 4b084ba72a8..977fee85803 100644 --- a/src/System.Management.Automation/engine/interpreter/InterpretedFrame.cs +++ b/src/System.Management.Automation/engine/interpreter/InterpretedFrame.cs @@ -27,23 +27,19 @@ namespace System.Management.Automation.Interpreter { internal sealed class InterpretedFrame { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly ThreadLocal CurrentFrame = new ThreadLocal(); internal readonly Interpreter Interpreter; internal InterpretedFrame _parent; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] private readonly int[] _continuations; private int _continuationIndex; private int _pendingContinuation; private object _pendingValue; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] public readonly object[] Data; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] public readonly StrongBox[] Closure; public int StackIndex; From e2b2d1ea59d27f6ac1f0bdef6155ba6a9479068f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:09:34 +0100 Subject: [PATCH 029/378] Ensure `.cs` files end with exactly one newline (#25968) --- .../CounterFileInfo.cs | 1 - .../ImportCounterCommand.cs | 1 - .../commands/management/CommitTransactionCommand.cs | 1 - .../commands/management/Eventlog.cs | 1 - .../commands/management/GetTransactionCommand.cs | 1 - .../commands/management/GetWMIObjectCommand.cs | 1 - .../commands/management/RollbackTransactionCommand.cs | 1 - .../commands/management/StartTransactionCommand.cs | 1 - .../commands/management/UseTransactionCommand.cs | 1 - .../LocalAccounts/Commands/AddLocalGroupMemberCommand.cs | 1 - .../LocalAccounts/Commands/DisableLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/EnableLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/GetLocalGroupCommand.cs | 1 - .../LocalAccounts/Commands/GetLocalGroupMemberCommand.cs | 1 - .../LocalAccounts/Commands/GetLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/NewLocalGroupCommand.cs | 1 - .../LocalAccounts/Commands/NewLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/RemoveLocalGroupCommand.cs | 1 - .../LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs | 1 - .../LocalAccounts/Commands/RemoveLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/RenameLocalGroupCommand.cs | 1 - .../LocalAccounts/Commands/RenameLocalUserCommand.cs | 1 - .../LocalAccounts/Commands/SetLocalGroupCommand.cs | 1 - .../LocalAccounts/Commands/SetLocalUserCommand.cs | 1 - .../xml/cmdlets-over-objects.objectModel.autogen.cs | 1 - .../xml/cmdlets-over-objects.xmlSerializer.autogen.cs | 1 - .../engine/SessionStateDriveAPIs.cs | 1 - src/System.Management.Automation/engine/SessionStateItem.cs | 1 - .../engine/SessionStateNavigation.cs | 1 - src/System.Management.Automation/engine/SessionStateProperty.cs | 1 - src/System.Management.Automation/engine/TransactedString.cs | 1 - src/System.Management.Automation/engine/TransactionManager.cs | 1 - .../engine/hostifaces/RunspaceInvoke.cs | 1 - src/System.Management.Automation/namespaces/ProviderBase.cs | 1 - .../security/CredentialParameter.cs | 1 - src/TypeCatalogGen/TypeCatalogGen.cs | 1 - test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs | 2 +- .../BenchmarkDotNet.Extensions/MandatoryCategoryValidator.cs | 2 +- .../dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs | 2 +- .../BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs | 2 +- .../dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs | 2 +- test/perf/dotnet-tools/Reporting/Counter.cs | 2 +- test/perf/dotnet-tools/Reporting/Os.cs | 2 +- test/perf/dotnet-tools/ResultsComparer/CommandLineOptions.cs | 2 +- test/perf/dotnet-tools/ResultsComparer/DataTransferContracts.cs | 2 +- 45 files changed, 9 insertions(+), 45 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs index cbebb9b4557..2b11b6d3b03 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CounterFileInfo.cs @@ -54,4 +54,3 @@ public UInt32 SampleCount private UInt32 _sampleCount = 0; } } - diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs index ed4cdb51ff9..729334d0605 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs @@ -679,4 +679,3 @@ private void WriteSampleSetObject(PerformanceCounterSampleSet set, bool firstSet } } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs index 6f93119c999..94e923bfa6e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CommitTransactionCommand.cs @@ -28,4 +28,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs index 3731687599c..ffd69951c61 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs @@ -1465,4 +1465,3 @@ protected override void BeginProcessing() #endregion RemoveEventLogCommand } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs index 484ddb96680..6b6551619f1 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetTransactionCommand.cs @@ -23,4 +23,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs index 85d8c4feb3f..27f812c7a80 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetWMIObjectCommand.cs @@ -438,4 +438,3 @@ private string GetClassNameFromQuery(string query) #endregion Command code } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs index 297dd5269a9..3d6fc27cc3c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/RollbackTransactionCommand.cs @@ -28,4 +28,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs index 6c178626d96..58dcfbd1daa 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/StartTransactionCommand.cs @@ -107,4 +107,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs index 056cf60265b..67d3acee44a 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/UseTransactionCommand.cs @@ -91,4 +91,3 @@ protected override void EndProcessing() } } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs index 375a8101075..59cb3067efc 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/AddLocalGroupMemberCommand.cs @@ -301,4 +301,3 @@ private void ProcessSid(SecurityIdentifier groupSid) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs index 09e7bdf9452..592c77726fe 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/DisableLocalUserCommand.cs @@ -217,4 +217,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs index e321a03e266..88627ba2e33 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/EnableLocalUserCommand.cs @@ -217,4 +217,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs index 3965c362335..4c11a3c4c36 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupCommand.cs @@ -168,4 +168,3 @@ private void ProcessSids() } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs index 8be09e1ded5..0b3625f6ef7 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalGroupMemberCommand.cs @@ -233,4 +233,3 @@ private IEnumerable ProcessSid(SecurityIdentifier groupSid) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs index e469d043ffa..9f8d3b9311b 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/GetLocalUserCommand.cs @@ -170,4 +170,3 @@ private void ProcessSids() } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs index 59e4f4ca13f..b709d22a485 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalGroupCommand.cs @@ -118,4 +118,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs index b3916f46071..d3402b5a4c9 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/NewLocalUserCommand.cs @@ -292,4 +292,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs index 0c0af710af1..981643cf04c 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupCommand.cs @@ -210,4 +210,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs index 7e132405b2a..47d0a77784e 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalGroupMemberCommand.cs @@ -299,4 +299,3 @@ private void ProcessSid(SecurityIdentifier groupSid) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs index 0c61da2e117..6d6081fef7e 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RemoveLocalUserCommand.cs @@ -211,4 +211,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs index f32e3365086..c594fccb889 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalGroupCommand.cs @@ -230,4 +230,3 @@ private bool CheckShouldProcess(string groupName, string newName) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs index e6b1297a7d5..c23cf41ac61 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/RenameLocalUserCommand.cs @@ -230,4 +230,3 @@ private bool CheckShouldProcess(string userName, string newName) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs index b1943971e3d..49ae31dacc7 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalGroupCommand.cs @@ -177,4 +177,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs index 8fafa52c9e4..3bfdc24ac03 100644 --- a/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs +++ b/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Commands/SetLocalUserCommand.cs @@ -320,4 +320,3 @@ private bool CheckShouldProcess(string target) } } - diff --git a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.objectModel.autogen.cs b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.objectModel.autogen.cs index e2b87d4adf9..7274c3bb954 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.objectModel.autogen.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.objectModel.autogen.cs @@ -2237,4 +2237,3 @@ public string Value } } } - diff --git a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs index f463e5052bb..b8d0e88905c 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs @@ -10108,4 +10108,3 @@ public override System.Xml.Serialization.XmlSerializer GetSerializer(System.Type } } } - diff --git a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs index 34c1ac50521..d01d4c63f5d 100644 --- a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs @@ -1434,4 +1434,3 @@ internal PSDriveInfo CurrentDrive } #pragma warning restore 56500 - diff --git a/src/System.Management.Automation/engine/SessionStateItem.cs b/src/System.Management.Automation/engine/SessionStateItem.cs index 3d5262bf6c0..173043515ba 100644 --- a/src/System.Management.Automation/engine/SessionStateItem.cs +++ b/src/System.Management.Automation/engine/SessionStateItem.cs @@ -1375,4 +1375,3 @@ private object InvokeDefaultActionDynamicParameters( } #pragma warning restore 56500 - diff --git a/src/System.Management.Automation/engine/SessionStateNavigation.cs b/src/System.Management.Automation/engine/SessionStateNavigation.cs index a1139ebc198..d2d27ec2d83 100644 --- a/src/System.Management.Automation/engine/SessionStateNavigation.cs +++ b/src/System.Management.Automation/engine/SessionStateNavigation.cs @@ -1748,4 +1748,3 @@ private object MoveItemDynamicParameters( } #pragma warning restore 56500 - diff --git a/src/System.Management.Automation/engine/SessionStateProperty.cs b/src/System.Management.Automation/engine/SessionStateProperty.cs index d4568d2ebb3..9f621fa2f7a 100644 --- a/src/System.Management.Automation/engine/SessionStateProperty.cs +++ b/src/System.Management.Automation/engine/SessionStateProperty.cs @@ -1116,4 +1116,3 @@ private object ClearPropertyDynamicParameters( } #pragma warning restore 56500 - diff --git a/src/System.Management.Automation/engine/TransactedString.cs b/src/System.Management.Automation/engine/TransactedString.cs index 22a0afe9a9a..05eab93d198 100644 --- a/src/System.Management.Automation/engine/TransactedString.cs +++ b/src/System.Management.Automation/engine/TransactedString.cs @@ -195,4 +195,3 @@ private void ValidateTransactionOrEnlist() } } } - diff --git a/src/System.Management.Automation/engine/TransactionManager.cs b/src/System.Management.Automation/engine/TransactionManager.cs index 2add6f288f5..e77ffebedb4 100644 --- a/src/System.Management.Automation/engine/TransactionManager.cs +++ b/src/System.Management.Automation/engine/TransactionManager.cs @@ -706,4 +706,3 @@ public void Dispose(bool disposing) } } } - diff --git a/src/System.Management.Automation/engine/hostifaces/RunspaceInvoke.cs b/src/System.Management.Automation/engine/hostifaces/RunspaceInvoke.cs index 5fa8370bcea..dcce30264ec 100644 --- a/src/System.Management.Automation/engine/hostifaces/RunspaceInvoke.cs +++ b/src/System.Management.Automation/engine/hostifaces/RunspaceInvoke.cs @@ -161,4 +161,3 @@ protected virtual void Dispose(bool disposing) #endregion IDisposable Members } } - diff --git a/src/System.Management.Automation/namespaces/ProviderBase.cs b/src/System.Management.Automation/namespaces/ProviderBase.cs index ca4cb1de64c..07be68dc3ec 100644 --- a/src/System.Management.Automation/namespaces/ProviderBase.cs +++ b/src/System.Management.Automation/namespaces/ProviderBase.cs @@ -1984,4 +1984,3 @@ public void WriteError(ErrorRecord errorRecord) } #pragma warning restore 56506 - diff --git a/src/System.Management.Automation/security/CredentialParameter.cs b/src/System.Management.Automation/security/CredentialParameter.cs index 0d48e4fa738..1ea19691ae7 100644 --- a/src/System.Management.Automation/security/CredentialParameter.cs +++ b/src/System.Management.Automation/security/CredentialParameter.cs @@ -89,4 +89,3 @@ public override object Transform(EngineIntrinsics engineIntrinsics, object input } #pragma warning restore 56506 - diff --git a/src/TypeCatalogGen/TypeCatalogGen.cs b/src/TypeCatalogGen/TypeCatalogGen.cs index 3d4c0f21ed9..b0e604ec12d 100644 --- a/src/TypeCatalogGen/TypeCatalogGen.cs +++ b/src/TypeCatalogGen/TypeCatalogGen.cs @@ -470,4 +470,3 @@ internal TypeMetadata(string assemblyName, bool isTypeObsolete) } } } - diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs index 7d0631b896b..f478b6f7378 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs @@ -23,4 +23,4 @@ public static int ToExitCode(this IEnumerable summaries) return 0; } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/MandatoryCategoryValidator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/MandatoryCategoryValidator.cs index 7b3b2d38f3b..6f84b3f5767 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/MandatoryCategoryValidator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/MandatoryCategoryValidator.cs @@ -32,4 +32,4 @@ public IEnumerable Validate(ValidationParameters validationPara $"{benchmarkId} does not belong to one of the mandatory categories: {string.Join(", ", _mandatoryCategories)}. Use [BenchmarkCategory(Categories.$)]") ); } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs index 16ae22f3167..a2837d61988 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs @@ -24,4 +24,4 @@ public bool Predicate(BenchmarkCase benchmarkCase) return _counter++ % _partitionsCount.Value == _partitionIndex.Value; // will return true only for benchmarks that belong to it’s partition } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs index b001f603dcb..47d5564309e 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs @@ -30,4 +30,4 @@ public IEnumerable Validate(ValidationParameters validationPara benchmarkCase: group.First())); } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs index 87bf6d82d8d..7e2b587abca 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs @@ -145,4 +145,4 @@ private static Guid GenerateRandomGuid(Random random) return new Guid(bytes); } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/Reporting/Counter.cs b/test/perf/dotnet-tools/Reporting/Counter.cs index 3952369c312..f97f0771b99 100644 --- a/test/perf/dotnet-tools/Reporting/Counter.cs +++ b/test/perf/dotnet-tools/Reporting/Counter.cs @@ -20,4 +20,4 @@ public class Counter public IList Results { get; set; } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/Reporting/Os.cs b/test/perf/dotnet-tools/Reporting/Os.cs index 692a75ee7c5..760142d3137 100644 --- a/test/perf/dotnet-tools/Reporting/Os.cs +++ b/test/perf/dotnet-tools/Reporting/Os.cs @@ -12,4 +12,4 @@ public class Os public string Name { get; set; } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/ResultsComparer/CommandLineOptions.cs b/test/perf/dotnet-tools/ResultsComparer/CommandLineOptions.cs index d3ad01be95b..90a439f66cc 100644 --- a/test/perf/dotnet-tools/ResultsComparer/CommandLineOptions.cs +++ b/test/perf/dotnet-tools/ResultsComparer/CommandLineOptions.cs @@ -51,4 +51,4 @@ public static IEnumerable Examples } } } -} \ No newline at end of file +} diff --git a/test/perf/dotnet-tools/ResultsComparer/DataTransferContracts.cs b/test/perf/dotnet-tools/ResultsComparer/DataTransferContracts.cs index c3399ea4333..94511488efd 100644 --- a/test/perf/dotnet-tools/ResultsComparer/DataTransferContracts.cs +++ b/test/perf/dotnet-tools/ResultsComparer/DataTransferContracts.cs @@ -130,4 +130,4 @@ public class BdnResult public HostEnvironmentInfo HostEnvironmentInfo { get; set; } public List Benchmarks { get; set; } } -} \ No newline at end of file +} From 1e46d89c632fcd94bb43bc51f615cea154cd0474 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 3 Sep 2025 14:14:44 -0400 Subject: [PATCH 030/378] Add Codeql Suppressions (#25943) --- .../commands/management/Process.cs | 1 + .../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 1 + .../engine/NativeCommandProcessor.cs | 1 + .../engine/remoting/common/RunspaceConnectionInfo.cs | 1 + .../namespaces/FileSystemProvider.cs | 1 + 5 files changed, 5 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 56efe65b4bb..2e07a945a00 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -1903,6 +1903,7 @@ protected override void BeginProcessing() } catch (CommandNotFoundException) { + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path they are specifying and the process is on the user's system except for remoting in which case restricted remoting security guidelines should be used. startInfo.FileName = FilePath; #if UNIX // Arguments are passed incorrectly to the executable used for ShellExecute and not to filename https://github.com/dotnet/corefx/issues/30718 diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 3b8ff2e3372..7a784a1e495 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -1295,6 +1295,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM WriteWebRequestDebugInfo(currentRequest); } + // codeql[cs/ssrf] - This is expected Poweshell behavior where user inputted Uri is supported for the context of this method. The user assumes trust for the Uri and invocation is done on the user's machine, not a web application. If there is concern for remoting, they should use restricted remoting. response = client.SendAsync(currentRequest, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult(); if (IsWriteVerboseEnabled()) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 8b5b6af93a2..7384a9385c3 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -1605,6 +1605,7 @@ private ProcessStartInfo GetProcessStartInfo( { var startInfo = new ProcessStartInfo { + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. FileName = this.Path }; diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index b0f46e43830..d9a6d0b317b 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2272,6 +2272,7 @@ internal int StartSSHProcess( // linux|macos: // Subsystem powershell /usr/local/bin/pwsh -SSHServerMode -NoLogo -NoProfile + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified, so any file executed in the runspace would be in the user's local system/process or a system they have access to in which case restricted remoting security guidelines should be used. System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(filePath); // pass "-i identity_file" command line argument to ssh if KeyFilePath is set diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 3d13ac05d4d..c5df7a9339a 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -1324,6 +1324,7 @@ protected override void InvokeDefaultAction(string path) if (ShouldProcess(resource, action)) { var invokeProcess = new System.Diagnostics.Process(); + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path they are specifying. If there is concern for remoting, restricted remoting guidelines should be used. invokeProcess.StartInfo.FileName = path; #if UNIX bool useShellExecute = false; From 499cedfaf67b47c08bccf0cefe79e403c761604d Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:13:58 -0500 Subject: [PATCH 031/378] Add build to vPack Pipeline (#25915) Co-authored-by: Travis Plunk (HE/HIM) Co-authored-by: Travis Plunk --- .pipelines/PowerShell-vPack-Official.yml | 283 +++++++++++++++------- .pipelines/templates/obp-file-signing.yml | 25 +- tools/packaging/packaging.psm1 | 18 +- 3 files changed, 229 insertions(+), 97 deletions(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index a1bb28c0e19..5783785cfd6 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,32 +1,30 @@ trigger: none parameters: # parameters are shown up in ADO UI in a build queue time +- name: OfficialBuild + type: boolean + default: true - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean default: true -- name: 'debug' - displayName: 'Enable debug output' - type: boolean - default: false -- name: 'architecture' +- name: vPackName type: string - displayName: 'Select the vpack architecture:' + displayName: 'VPack Name:' + default: 'PowerShell' values: - - x64 - - x86 - - arm64 - default: x64 -- name: 'VPackPublishOverride' - type: string - displayName: 'VPack Publish Override Version (can leave blank):' - default: ' ' + - PowerShell + - PowerShellDoNotUse - name: 'ReleaseTagVar' type: string displayName: 'Release Tag Var:' default: 'fromBranch' +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false -name: vPack_${{ parameters.architecture }}_$(date:yyMM).$(date:dd)$(rev:rrr) +name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -51,6 +49,12 @@ variables: value: ${{ parameters.ReleaseTagVar }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@templates', 'v2/Microsoft.NonOfficial.yml@templates' ) }} + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general resources: repositories: @@ -59,17 +63,8 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main - pipelines: - - pipeline: PSPackagesOfficial - source: 'PowerShell-Packages-Official' - trigger: - branches: - include: - - master - - releases/* - extends: - template: v2/Microsoft.Official.yml@templates + template: ${{ variables.templateFile }} parameters: platform: name: 'windows_undocked' # windows undocked @@ -99,35 +94,116 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - stage: main + - stage: BuildStage jobs: - - job: main + - job: BuildJob pool: type: windows + strategy: + matrix: + x86: + architecture: x86 + + x64: + architecture: x64 + + arm64: + architecture: arm64 + variables: + ArtifactPlatform: 'windows' + ob_artifactBaseName: drop_build_$(architecture) ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell.${{ parameters.architecture }}' - ob_createvpack_description: PowerShell ${{ parameters.architecture }} $(version) ob_createvpack_owneralias: tplunk - ob_createvpack_versionAs: string - ob_createvpack_version: '$(version)' + ob_createvpack_versionAs: parts ob_createvpack_propsFile: true ob_createvpack_verbose: true + ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' + ob_createvpack_description: PowerShell $(architecture) $(version) + # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ + ob_createvpack_majorVer: $(pwshMajorVersion) + ob_createvpack_minorVer: $(pwshMinorVersion) + ob_createvpack_patchVer: $(pwshPatchVersion) + ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: + ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) + ${{ else }}: + ob_createvpack_prereleaseVer: $(Build.SourceVersion) steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s + env: + ob_restore_phase: true + - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes UseJson: no + - pwsh: | + $version = '$(Version)' + Write-Verbose -Verbose "Version: $version" + if(!$version) { + throw "Version is not set." + } + + $mainVersionParts = $version -split '-' + + Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" + $versionParts = $mainVersionParts[0] -split '[.]'; + $major = $versionParts[0] + $minor = $versionParts[1] + $patch = $versionParts[2] + + $previewPart = $mainVersionParts[1] + Write-Verbose -Verbose "previewPart: $previewPart" + + Write-Host "major: $major; minor: $minor; patch: $patch;" + + $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + if($previewPart) { + $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" + } else { + Write-Verbose -Verbose "No prerelease part found in version string." + } + displayName: Set ob_createvpack_*Ver + env: + ob_restore_phase: true + + # Validate pwsh*Version variables + - pwsh: | + $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") + foreach ($var in $variables) { + if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { + throw "Required variable '`$env:$var' is not set." + } + } + displayName: Validate pwsh*Version variables + env: + ob_restore_phase: true + - pwsh: | if($env:RELEASETAGVAR -match '-') { throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" } displayName: Stop any preview release + env: + ob_restore_phase: true - task: UseDotNet@2 displayName: 'Use .NET Core sdk' @@ -136,88 +212,115 @@ extends: version: 3.1.x installationPath: $(Agent.ToolsDirectory)/dotnet + ### BUILD ### + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(repoRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: false # Do not upload results + Language: csharp + + - task: UseDotNet@2 + displayName: 'Install .NET based on global.json' + inputs: + useGlobalJson: true + workingDirectory: $(repoRoot) + env: + ob_restore_phase: true + - pwsh: | - $packageArtifactName = 'drop_windows_package_package_win_${{ parameters.architecture }}' - $vstsCommandString = "vso[task.setvariable variable=PackageArtifactName]$packageArtifactName" - Write-Host "sending " + $vstsCommandString + # Need to set PowerShellRoot variable for obp-file-signing template + $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" + Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - $packageArtifactPath = '$(Pipeline.Workspace)\PSPackagesOfficial' - $vstsCommandString = "vso[task.setvariable variable=PackageArtifactPath]$packageArtifactPath" - Write-Host "sending " + $vstsCommandString + $Architecture = '$(Architecture)' + $runtime = switch ($Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + } + + $params = @{} + if ($env:BuildConfiguration -eq 'minSize') { + $params['ForMinimalSize'] = $true + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - displayName: 'Set package artifact variables' - - download: PSPackagesOfficial - artifact: $(PackageArtifactName) - displayName: Download package + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(repoRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force - - pwsh: 'Get-ChildItem $(PackageArtifactPath)\* -recurse | Select-Object -ExpandProperty Name' - displayName: 'Capture Artifact Listing' + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose - - pwsh: | - $message = @() - $packages = Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip, *.msi - - if($packages.count -eq 0) {throw "No packages found in $(PackageArtifactPath)"} - - $packages | ForEach-Object { - if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR } - if($message.count -gt 0){throw ($message | out-string)} - displayName: 'Validate Zip and MSI Package Names' + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam - - pwsh: | - Get-ChildItem $(PackageArtifactPath)\* -recurse -include *.zip | ForEach-Object { - if($_.Name -match 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(${{ parameters.architecture }})\.(zip){1}') - { - Expand-Archive -Path $_.FullName -DestinationPath $(ob_outputDirectory) - } - } - displayName: 'Extract Zip to ob_outputDirectory' + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\src' + ob_restore_phase: true + + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + SigningProfile: $(windows_build_tools_cert_id) + OfficialBuild: false + vPackScenario: true + + ### END OF BUILD ### - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse - Get-Content $(ob_outputdirectory)\preview.json -ErrorAction SilentlyContinue | Write-Host + Get-ChildItem env:/ob_createvpack_*Ver + Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host displayName: Debug Output Directory and Version condition: succeededOrFailed() - - pwsh: | - Write-Host "Using VPackPublishOverride variable" - $vpackVersion = '${{ parameters.VPackPublishOverride }}' - $vstsCommandString = "vso[task.setvariable variable=ob_createvpack_version]$vpackVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - condition: ne('${{ parameters.VPackPublishOverride }}', ' ') - displayName: 'Set ob_createvpack_version with VPackPublishOverride' - - pwsh: | Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse + $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" + throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" } $vpackFiles displayName: Debug Output Directory and Version condition: succeededOrFailed() - - - task: onebranch.pipeline.signing@1 - displayName: 'Onebranch Signing' - inputs: - command: 'sign' - signing_environment: 'azure-ado' - cp_code: $(windows_build_tools_cert_id) - files_to_sign: '**/*.exe;**/System.Management.Automation.dll' - search_root: $(ob_outputDirectory) diff --git a/.pipelines/templates/obp-file-signing.yml b/.pipelines/templates/obp-file-signing.yml index b6683d3caaf..cbe44ad0018 100644 --- a/.pipelines/templates/obp-file-signing.yml +++ b/.pipelines/templates/obp-file-signing.yml @@ -1,6 +1,9 @@ parameters: binPath: '$(ob_outputDirectory)' globalTool: 'false' + SigningProfile: 'external_distribution' + OfficialBuild: true + vPackScenario: false steps: - pwsh: | @@ -80,7 +83,7 @@ steps: displayName: Sign 1st party files inputs: command: 'sign' - signing_profile: external_distribution + signing_profile: ${{ parameters.SigningProfile }} files_to_sign: '**\*.psd1;**\*.psm1;**\*.ps1xml;**\*.ps1;**\*.dll;**\*.exe;**\pwsh' search_root: $(Pipeline.Workspace)/toBeSigned @@ -95,12 +98,15 @@ steps: $BuildPath = (Get-Item '${{ parameters.binPath }}').FullName Write-Verbose -Verbose -Message "BuildPath: $BuildPath" + $officialBuild = [System.Convert]::ToBoolean('${{ parameters.OfficialBuild }}') ## copy all files to be signed to build folder - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath '$(Pipeline.Workspace)/toBeSigned' + Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath '$(Pipeline.Workspace)/toBeSigned' -OfficialBuild $officialBuild $dlls = Get-ChildItem $BuildPath/*.dll, $BuildPath/*.exe -Recurse $signatures = $dlls | Get-AuthenticodeSignature - $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch '^CN=Microsoft.*'}| select-object -ExpandProperty Path + $officialIssuerPattern = '^CN=(Microsoft Code Signing PCA|Microsoft Root Certificate Authority|Microsoft Corporation).*' + $testCert = '^CN=(Microsoft|TestAzureEngBuildCodeSign).*' + $missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch $testCert -or $_.SignerCertificate.Issuer -notmatch $officialIssuerPattern} | select-object -ExpandProperty Path Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" @@ -137,11 +143,20 @@ steps: displayName: Capture ThirdParty Signed files - pwsh: | + $officialBuild = [System.Convert]::ToBoolean('${{ parameters.OfficialBuild }}') + $vPackScenario = [System.Convert]::ToBoolean('${{ parameters.vPackScenario }}') Import-Module '$(PowerShellRoot)/build.psm1' -Force Import-Module '$(PowerShellRoot)/tools/packaging' -Force $isGlobalTool = '${{ parameters.globalTool }}' -eq 'true' - if (-not $isGlobalTool) { + if ($vPackScenario) { + Write-Verbose -Verbose -Message "vPackScenario is true, copying to $(ob_outputDirectory)" + $pathForUpload = New-Item -ItemType Directory -Path '$(ob_outputDirectory)' -Force + Write-Verbose -Verbose -Message "pathForUpload: $pathForUpload" + Copy-Item -Path '${{ parameters.binPath }}\*' -Destination $pathForUpload -Recurse -Force -Verbose + Write-Verbose -Verbose -Message "Files copied to $pathForUpload" + } + elseif (-not $isGlobalTool) { $pathForUpload = New-Item -ItemType Directory -Path '$(ob_outputDirectory)/Signed-$(Runtime)' -Force Write-Verbose -Verbose -Message "pathForUpload: $pathForUpload" Copy-Item -Path '${{ parameters.binPath }}\*' -Destination $pathForUpload -Recurse -Force -Verbose @@ -153,7 +168,7 @@ steps: Write-Verbose "Copying third party signed files to the build folder" $thirdPartySignedFilesPath = (Get-Item '$(Pipeline.Workspace)/thirdPartyToBeSigned').FullName - Update-PSSignedBuildFolder -BuildPath $pathForUpload -SignedFilesPath $thirdPartySignedFilesPath + Update-PSSignedBuildFolder -BuildPath $pathForUpload -SignedFilesPath $thirdPartySignedFilesPath -OfficialBuild $officialBuild displayName: 'Copy signed files for upload' diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 52355c1eb4f..b1e4327bee0 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -887,7 +887,8 @@ function Update-PSSignedBuildFolder [string]$BuildPath, [Parameter(Mandatory)] [string]$SignedFilesPath, - [string[]] $RemoveFilter = ('*.pdb', '*.zip', '*.r2rmap') + [string[]] $RemoveFilter = ('*.pdb', '*.zip', '*.r2rmap'), + [bool]$OfficialBuild = $true ) $BuildPathNormalized = (Get-Item $BuildPath).FullName @@ -943,8 +944,21 @@ function Update-PSSignedBuildFolder if ($IsWindows) { $signature = Get-AuthenticodeSignature -FilePath $signedFilePath - if ($signature.Status -ne 'Valid') { + + if ($signature.Status -ne 'Valid' -and $OfficialBuild) { + Write-Host "Certificate Issuer: $($signature.SignerCertificate.Issuer)" + Write-Host "Certificate Subject: $($signature.SignerCertificate.Subject)" Write-Error "Invalid signature for $signedFilePath" + } elseif ($OfficialBuild -eq $false) { + if ($signature.Status -eq 'NotSigned') { + Write-Warning "File is not signed: $signedFilePath" + } elseif ($signature.SignerCertificate.Issuer -notmatch '^CN=(Microsoft|TestAzureEngBuildCodeSign|Windows Internal Build Tools).*') { + Write-Warning "File signed with test certificate: $signedFilePath" + Write-Host "Certificate Issuer: $($signature.SignerCertificate.Issuer)" + Write-Host "Certificate Subject: $($signature.SignerCertificate.Subject)" + } else { + Write-Verbose -Verbose "File properly signed: $signedFilePath" + } } } else From d98418e65af1e0e78d7edfb382b9d014d5a08e9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 18:52:48 +0000 Subject: [PATCH 032/378] Bump actions/setup-dotnet from 4 to 5 (#25978) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 4eba9eeab6f..4b9bd916f93 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -183,7 +183,7 @@ jobs: with: fetch-depth: '0' - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v5 with: global-json-file: ./global.json From 3ef1bc6fe9409a328afef3b189fbf75cf3d5d777 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 18:56:27 +0000 Subject: [PATCH 033/378] Bump github/codeql-action from 3.29.11 to 3.30.0 (#25966) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 4b9bd916f93..b892f0f4a9d 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 + uses: github/codeql-action/init@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 + uses: github/codeql-action/analyze@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index b8d5abb5957..27686d61ceb 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.5 + uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 with: sarif_file: results.sarif From 6f028d46d11983574684b257ef53bd36d180f23b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Sep 2025 11:06:16 -0700 Subject: [PATCH 034/378] =?UTF-8?q?Update=20container=20images=20to=20use?= =?UTF-8?q?=20mcr.microsoft.com=20for=20Linux=20and=20Azure=20=E2=80=A6=20?= =?UTF-8?q?(#25981)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PowerShell-Coordinated_Packages-Official.yml | 7 ++++--- .pipelines/PowerShell-Packages-Official.yml | 3 +-- .pipelines/PowerShell-Release-Official-Azure.yml | 3 +-- .pipelines/PowerShell-Release-Official.yml | 6 +++--- .pipelines/apiscan-gen-notice.yml | 2 +- .pipelines/templates/linux.yml | 1 + .pipelines/templates/mac.yml | 1 + .pipelines/templates/windows-hosted-build.yml | 2 ++ build.psm1 | 12 +++++++----- 9 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index efc28942fcc..96b4192c792 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -69,7 +69,7 @@ variables: - name: __DOTNET_RUNTIME_FEED value: ${{ parameters.InternalSDKBlobURL }} - name: LinuxContainerImage - value: onebranch.azurecr.io/linux/ubuntu-2004:latest + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT @@ -99,7 +99,8 @@ variables: # Disable BinSkim at job level to override NonOfficial template defaults - name: ob_sdl_binskim_enabled value: false - + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} extends: template: ${{ variables.templateFile }} @@ -143,7 +144,7 @@ extends: - job: SetVars displayName: Set Variables pool: - type: windows + type: linux variables: - name: ob_outputDirectory diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index f0d428bf1d6..b756b6f8c36 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -56,7 +56,7 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - name: branchCounterKey @@ -66,7 +66,6 @@ variables: - group: MSIXSigningProfile - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - resources: pipelines: diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 8e144f1ee55..1f210ac6745 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -47,11 +47,10 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: PoolNames - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - resources: repositories: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 8c3e8728533..186e9757818 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -57,7 +57,7 @@ variables: - name: WindowsContainerImage value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/cbl-mariner/build:2.0 + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames @@ -284,7 +284,7 @@ extends: - stage: PublishGitHubReleaseAndNuget displayName: Publish GitHub and Nuget Release - dependsOn: + dependsOn: - setReleaseTagAndChangelog - UpdateChangeLog variables: @@ -404,7 +404,7 @@ extends: - stage: ChangesToMaster displayName: Ensure changes are in GH master - dependsOn: + dependsOn: - PublishPMC jobs: - template: /.pipelines/templates/approvalJob.yml@self diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 7596f79998e..54f6f4725c5 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -26,7 +26,7 @@ variables: - group: 'ComponentGovernance' - group: 'PoolNames' - name: LinuxContainerImage - value: onebranch.azurecr.io/linux/ubuntu-2004:latest + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index 6c47fd8abfd..83b7aa58ef3 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -201,5 +201,6 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: $(DropRootPath) + OfficialBuild: $(ps_official_build) - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 310c5695979..b08becedc22 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -148,5 +148,6 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: $(DropRootPath) + OfficialBuild: $(ps_official_build) - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 35dadbb839c..8cd622149fa 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -206,6 +206,7 @@ jobs: - template: /.pipelines/templates/obp-file-signing.yml@self parameters: binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + OfficialBuild: $(ps_official_build) ## first we sign all the files in the bin folder - ${{ if eq(variables['Architecture'], 'fxdependent') }}: @@ -213,6 +214,7 @@ jobs: parameters: binPath: '$(GlobalToolArtifactPath)/publish/PowerShell.Windows.x64/release' globalTool: 'true' + OfficialBuild: $(ps_official_build) - pwsh: | Get-ChildItem '$(GlobalToolArtifactPath)/obj/PowerShell.Windows.x64/release' diff --git a/build.psm1 b/build.psm1 index 7390bb183f7..d76dd7f63ff 100644 --- a/build.psm1 +++ b/build.psm1 @@ -193,7 +193,7 @@ function Get-EnvironmentInformation $environment += @{'IsRedHatFamily' = $environment.IsCentOS -or $environment.IsFedora -or $environment.IsRedHat} $environment += @{'IsSUSEFamily' = $environment.IsSLES -or $environment.IsOpenSUSE} $environment += @{'IsAlpine' = $LinuxInfo.ID -match 'alpine'} - $environment += @{'IsMariner' = $LinuxInfo.ID -match 'mariner'} + $environment += @{'IsMariner' = $LinuxInfo.ID -match 'mariner' -or $LinuxInfo.ID -match 'azurelinux'} # Workaround for temporary LD_LIBRARY_PATH hack for Fedora 24 # https://github.com/PowerShell/PowerShell/issues/2511 @@ -353,8 +353,8 @@ function Start-PSBuild { $PSModuleRestore = $true } - if ($Runtime -eq "linux-arm" -and $environment.IsLinux -and -not $environment.IsUbuntu) { - throw "Cross compiling for linux-arm is only supported on Ubuntu environment" + if ($Runtime -eq "linux-arm" -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { + throw "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" } if ("win-arm","win-arm64" -contains $Runtime -and -not $environment.IsWindows) { @@ -2207,6 +2207,8 @@ function Get-RedHatPackageManager { "yum install -y -q" } elseif ($environment.IsFedora -or (Get-Command -Name dnf -CommandType Application -ErrorAction SilentlyContinue)) { "dnf install -y -q" + } elseif ($environment.IsMariner -or (Get-Command -Name Test-DscConfiguration -CommandType Application -ErrorAction SilentlyContinue)) { + "tdnf install -y -q" } else { throw "Error determining package manager for this distribution." } @@ -2278,8 +2280,8 @@ function Start-PSBootstrap { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu) { - Write-Error "Cross compiling for linux-arm is only supported on Ubuntu environment" + if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { + Write-Error "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" return } From 60a85b1e76c5c5866ea0684fdc77f2c476967780 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Sep 2025 13:21:09 -0700 Subject: [PATCH 035/378] Make logical template name consistent between pipelines (#25990) --- .pipelines/MSIXBundle-vPack-Official.yml | 4 ++-- .../PowerShell-Coordinated_Packages-Official.yml | 2 +- .pipelines/PowerShell-Packages-Official.yml | 4 ++-- .pipelines/PowerShell-Release-Official-Azure.yml | 4 ++-- .pipelines/PowerShell-Release-Official.yml | 16 ++++++++-------- .pipelines/PowerShell-vPack-Official.yml | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index ef96f63f045..8e175c5a6bb 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -29,7 +29,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main @@ -44,7 +44,7 @@ resources: - releases/* extends: - template: v2/Microsoft.Official.yml@templates + template: v2/Microsoft.Official.yml@onebranchTemplates parameters: platform: name: 'windows_undocked' # windows undocked diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 96b4192c792..e70b65a9a64 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -1,4 +1,3 @@ -name: bins-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) trigger: none parameters: @@ -34,6 +33,7 @@ parameters: type: boolean default: false +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) resources: repositories: diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index b756b6f8c36..333d73276b8 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -28,7 +28,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -78,7 +78,7 @@ resources: - releases/* repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 1f210ac6745..f4c41143b5f 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: ev2-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -54,7 +54,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 186e9757818..974b8f328c8 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -29,7 +29,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -71,7 +71,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main @@ -95,7 +95,7 @@ resources: extends: template: ${{ variables.templateFile }} parameters: - release: + release: category: NonAzure featureFlags: WindowsHostVersion: @@ -303,8 +303,8 @@ extends: displayName: Push Git Tag jobName: PushGitTag instructions: | - Push the git tag to upstream - + Push the git tag to upstream + - template: /.pipelines/templates/approvalJob.yml@self parameters: displayName: Make Draft Public @@ -312,10 +312,10 @@ extends: jobName: DraftPublic instructions: | Make the GitHub Release Draft Public - + - stage: BlobPublic displayName: Make Blob Public - dependsOn: + dependsOn: - UpdateChangeLog - PushGitTagAndMakeDraftPublic jobs: @@ -426,7 +426,7 @@ extends: - stage: ReleaseClose displayName: Finish Release - dependsOn: + dependsOn: - ReleaseToMU - ReleaseSymbols jobs: diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 5783785cfd6..f110ff0366a 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -50,7 +50,7 @@ variables: - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@templates', 'v2/Microsoft.NonOfficial.yml@templates' ) }} + value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual # We shouldn't be using PATs anymore @@ -58,7 +58,7 @@ variables: resources: repositories: - - repository: templates + - repository: onebranchTemplates type: git name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main From 50d81d592d35c7576b8c10d6fc1e7573e2d4304e Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Sat, 6 Sep 2025 12:27:43 -0700 Subject: [PATCH 036/378] Add LinuxHost Network configuration to PowerShell Packages pipeline (#26000) --- .pipelines/PowerShell-Packages-Official.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 333d73276b8..552e7d10a68 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -92,6 +92,8 @@ extends: WindowsHostVersion: Version: 2022 Network: KS3 + LinuxHostVersion: + Network: KS3 linuxEsrpSigning: true incrementalSDLBinaryAnalysis: true globalSdl: From 43c2d983495c641460ce7c6f4783dd6b7e911cc0 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:44:14 +0100 Subject: [PATCH 037/378] Remove unnecessary `CS0618` suppressions from Variant APIs (#26006) --- .../WindowsTaskbarJumpList/PropVariant.cs | 2 -- src/System.Management.Automation/engine/COM/ComInvoker.cs | 3 --- src/System.Management.Automation/engine/COM/ComUtil.cs | 5 ----- 3 files changed, 10 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs index 10db7912b4a..408c59c482a 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/PropVariant.cs @@ -34,9 +34,7 @@ internal PropVariant(string value) throw new ArgumentException("PropVariantNullString", nameof(value)); } -#pragma warning disable CS0618 // Type or member is obsolete (might get deprecated in future versions _valueType = (ushort)VarEnum.VT_LPWSTR; -#pragma warning restore CS0618 // Type or member is obsolete (might get deprecated in future versions _ptr = Marshal.StringToCoTaskMemUni(value); } diff --git a/src/System.Management.Automation/engine/COM/ComInvoker.cs b/src/System.Management.Automation/engine/COM/ComInvoker.cs index a1b4a4c1ba7..ea8b8b96d79 100644 --- a/src/System.Management.Automation/engine/COM/ComInvoker.cs +++ b/src/System.Management.Automation/engine/COM/ComInvoker.cs @@ -7,9 +7,6 @@ using COM = System.Runtime.InteropServices.ComTypes; -// Disable obsolete warnings about VarEnum and COM-marshaling APIs in CoreCLR -#pragma warning disable 618 - namespace System.Management.Automation { internal static class ComInvoker diff --git a/src/System.Management.Automation/engine/COM/ComUtil.cs b/src/System.Management.Automation/engine/COM/ComUtil.cs index e244e4cdf3f..8cd5e73b835 100644 --- a/src/System.Management.Automation/engine/COM/ComUtil.cs +++ b/src/System.Management.Automation/engine/COM/ComUtil.cs @@ -141,9 +141,6 @@ private static string GetStringFromCustomType(COM.ITypeInfo typeinfo, IntPtr ref return "UnknownCustomtype"; } - // Disable obsolete warning about VarEnum in CoreCLR -#pragma warning disable 618 - /// /// This function gets a string representation of the Type Descriptor /// This is used in generating signature for Properties and Methods. @@ -259,8 +256,6 @@ internal static Type GetTypeFromTypeDesc(COM.TYPEDESC typedesc) return VarEnumSelector.GetTypeForVarEnum(vt); } -#pragma warning restore 618 - /// /// Converts a FuncDesc out of GetFuncDesc into a MethodInformation. /// From 41093ec8ae85ac708a01f7775e1740f95f23b798 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 8 Sep 2025 14:27:54 -0500 Subject: [PATCH 038/378] Add v7.5.3 Changelog (#25994) --- CHANGELOG/7.5.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index d2071727790..e231ce6b0e2 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,47 @@ # 7.5 Changelog +## [7.5.3] + +### General Cmdlet Updates and Fixes + +- Fix `Out-GridView` by replacing the use of obsolete `BinaryFormatter` with custom implementation. (#25559) +- Remove `OnDeserialized` and `Serializable` attributes from `Microsoft.Management.UI.Internal` project (#25831) +- Make the interface `IDeepCloneable` internal (#25830) + +### Tools + +- Add CodeQL suppressions (#25972) + +### Tests + +- Fix updatable help test for new content (#25944) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET SDK 9.0.304

+ +
+ +
    +
  • Make logical template name consistent between pipelines (#25991)
  • +
  • Update container images to use mcr.microsoft.com for Linux and Azure Linux (#25986)
  • +
  • Add build to vPack Pipeline (#25975)
  • +
  • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25964)
  • +
  • Update branch for release (#25942)
  • +
+ +
+ +### Documentation and Help Content + +- Fix typo in CHANGELOG for script filename suggestion (#25963) + +[7.5.3]: https://github.com/PowerShell/PowerShell/compare/v7.5.2...v7.5.3 + ## [7.5.2] - 2025-06-24 ### Engine Updates and Fixes @@ -41,7 +83,6 @@ [7.5.2]: https://github.com/PowerShell/PowerShell/compare/v7.5.1...v7.5.2 - ## [7.5.1] ### Engine Updates and Fixes From db25106909d7e6f4e935a0c05c4d196e6a4e7b72 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 8 Sep 2025 12:28:24 -0700 Subject: [PATCH 039/378] Fix variable reference for release environment in pipeline (#26012) --- .pipelines/PowerShell-Release-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 974b8f328c8..986f803361b 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -288,7 +288,7 @@ extends: - setReleaseTagAndChangelog - UpdateChangeLog variables: - ob_release_environment: ${{ parameters.releaseEnvironment }} + ob_release_environment: ${{ variables.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-githubNuget.yml@self parameters: From f0794987980fbb59227aaf6745ac371dbbdd5be6 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 8 Sep 2025 17:07:48 -0500 Subject: [PATCH 040/378] Add 7.4.12 Changelog (#26011) --- CHANGELOG/7.4.md | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md index a04b7c82e6e..64e955312d8 100644 --- a/CHANGELOG/7.4.md +++ b/CHANGELOG/7.4.md @@ -1,5 +1,37 @@ # 7.4 Changelog +## [7.4.12] + +### Tools + +- Add CodeQL suppressions (#25973) + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.413

+ +
+ +
    +
  • Add LinuxHost Network configuration to PowerShell Packages pipeline (#26003)
  • +
  • Update container images to use mcr.microsoft.com for Linux and Azure Linux (#25987)
  • +
  • Update SDK to 8.0.413 (#25993)
  • +
  • Make logical template name consistent between pipelines (#25992)
  • +
  • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25965)
  • +
+ +
+ +### Documentation and Help Content + +- Update third-party library versions to `8.0.19` for `ObjectPool`, Windows Compatibility, and `System.Drawing.Common` (#26001) + +[7.4.12]: https://github.com/PowerShell/PowerShell/compare/v7.4.11...v7.4.12 + ## [7.4.11] - 2025-06-17 ### Engine Updates and Fixes @@ -252,7 +284,7 @@ _This release is internal only. It is not available for download._
  • Add updated libicu dependency for Debian packages (#24301)
  • Add mapping to azurelinux repo (#24290)
  • Update vpack pipeline (#24281)
  • -
  • Add BaseUrl to buildinfo json file (#24376)
  • +
  • Add BaseUrl to buildinfo JSON file (#24376)
  • Delete the msix blob if it's already there (#24353)
  • Make some release tests run in a hosted pools (#24270)
  • Create new pipeline for compliance (#24252)
  • @@ -855,7 +887,7 @@ Bump .NET 8 to version 8.0.101
  • Bump StyleCop.Analyzers from 1.2.0-beta.406 to 1.2.0-beta.507 (#19837)
  • Bump Microsoft.CodeAnalysis.CSharp from 4.6.0-1.final to 4.7.0-2.final (#19838)(#19667)
  • Update to .NET 8 Preview 4 (#19696)
  • -
  • Update experimental-feature json files (#19828)
  • +
  • Update experimental-feature JSON files (#19828)
  • Bump JsonSchema.Net from 4.1.1 to 4.1.5 (#19790)(#19768)(#19788)
  • Update group to assign PRs in fabricbot.json (#19759)
  • Add retry on failure for all upload tasks in Azure Pipelines (#19761)
  • @@ -863,7 +895,7 @@ Bump .NET 8 to version 8.0.101
  • Delete symbols on Linux as well (#19735)
  • Update windows.json packaging BOM (#19728)
  • Disable SBOM signing for CI and add extra files for packaging tests (#19729)
  • -
  • Update experimental-feature json files (#19698(#19588))
  • +
  • Update experimental-feature JSON files (#19698(#19588))
  • Add ProductCode in registry for MSI install (#19590)
  • Runas format changed (#15434) (Thanks @krishnayalavarthi!)
  • For Preview releases, add pwsh-preview.exe alias to MSIX package (#19602)
  • @@ -1024,7 +1056,7 @@ Bump .NET 8 to version 8.0.101 - Build the relative URI for links from the response in `Invoke-WebRequest` (#19092) (Thanks @CarloToso!) - Fix redirection for `-CustomMethod` `POST` in WebCmdlets (#19111) (Thanks @CarloToso!) - Dispose previous response in Webcmdlets (#19117) (Thanks @CarloToso!) -- Improve `Invoke-WebRequest` XML and json errors format (#18837) (Thanks @CarloToso!) +- Improve `Invoke-WebRequest` XML and JSON errors format (#18837) (Thanks @CarloToso!) - Fix error formatting to remove the unneeded leading newline for concise view (#19080) - Add `-NoHeader` parameter to `ConvertTo-Csv` and `Export-Csv` cmdlets (#19108) (Thanks @ArmaanMcleod!) - Fix `Start-Process -Credential -Wait` to work on Windows (#19082) From 2689c44e36d6438b1830c88a71f00f480c9889d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 22:09:05 +0000 Subject: [PATCH 041/378] Bump actions/github-script from 7 to 8 (#25983) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/labels.yml | 2 +- .github/workflows/markdownLink.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 2a3ee69799b..cd0a1d31726 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -22,7 +22,7 @@ jobs: - name: Verify PR has label starting with 'cl-' id: verify-labels - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml index dbc5ccf139f..5ad78cf84d4 100644 --- a/.github/workflows/markdownLink.yml +++ b/.github/workflows/markdownLink.yml @@ -44,7 +44,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Super-Linter correction instructions if: failure() - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 with: script: | const message = "Super-Linter found issues in the changed files. Please check the logs for details. You can run the linter locally using the command: `./tools/super-lister/super-lister.ps1`."; From bce5047f2bb6cc39ac0d8d2a93a25fd120c1e620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:09:38 -0700 Subject: [PATCH 042/378] Bump github/codeql-action from 3.30.0 to 3.30.1 (#26008) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index b892f0f4a9d..14715f1b1d9 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 + uses: github/codeql-action/init@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 + uses: github/codeql-action/analyze@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 27686d61ceb..e5ea8425495 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.29.5 + uses: github/codeql-action/upload-sarif@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 with: sarif_file: results.sarif From a4dc4d821011c8070d1ba6ef19ad324e49f6420a Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 10 Sep 2025 12:19:30 -0400 Subject: [PATCH 043/378] Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26025) --- .pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json index 00555349c35..ce974fe69e5 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json @@ -17,8 +17,8 @@ { "type": "Run", "properties": { - "imageName": "adm-mariner-20-l", - "imageVersion": "v11" + "imageName": "adm-azurelinux-30-l", + "imageVersion": "v2" } } ] From afe0c86ddba31fc53fb5f9dea5969abab3b9e0af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:35:47 -0700 Subject: [PATCH 044/378] Bump github/codeql-action from 3.30.1 to 3.30.2 (#26029) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 14715f1b1d9..ad00549eb45 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 + uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 + uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index e5ea8425495..29befb40665 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5 + uses: github/codeql-action/upload-sarif@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 with: sarif_file: results.sarif From 3b8aa798cfc5ce403c3c86c37840d93603f9116c Mon Sep 17 00:00:00 2001 From: Richard Slater <630786+RichardSlater@users.noreply.github.com> Date: Wed, 10 Sep 2025 21:07:56 +0100 Subject: [PATCH 045/378] fix(apt-package): add libicu76 dependency to support Debian 13 (#25866) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index b1e4327bee0..ef8fba4efb8 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1612,7 +1612,7 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + "libicu76|libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) From a1b417691f93a4245fdbe23678c232c6b2072538 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:55:07 -0700 Subject: [PATCH 046/378] Move PowerShell build to use .NET SDK 10.0.100-rc.1 (#26027) Co-authored-by: Dongbo Wang --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/Program.cs | 198 +++++++++--------- test/tools/WebListener/WebListener.csproj | 2 +- tools/cgmanifest.json | 102 ++++----- 14 files changed, 174 insertions(+), 170 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index eec6d6685f7..8541f8ba795 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100-preview.7.25380.108", + "sdkImageVersion": "10.0.100-rc.1.25451.107", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index f81c7d1c0cd..e7cce33e5d9 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-preview.7.25380.108" + "version": "10.0.100-rc.1.25451.107" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 4a87006b68f..547911668e9 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 8c67a116c3c..029571c4145 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 11be5d04b81..2fd3f0075d6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 47189a24778..d60337d5d90 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 630e110cc68..2c796312a1a 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,13 +16,13 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 2c962d9528e..710102ca2fa 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 4c7872bcf67..b8245b9d315 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,17 +32,17 @@ - - + + - + - + - - + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 6007608a979..10c707c176a 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index b6417c011c4..f50e3bccf60 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/Program.cs b/test/tools/WebListener/Program.cs index 500e1c7062c..58baf77b1d7 100644 --- a/test/tools/WebListener/Program.cs +++ b/test/tools/WebListener/Program.cs @@ -6,9 +6,9 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Https; +using Microsoft.Extensions.Hosting; namespace mvc { @@ -18,108 +18,112 @@ public static void Main(string[] args) { if (args.Length != 7) { - System.Console.WriteLine("Required: "); + Console.WriteLine("Required: "); Environment.Exit(1); } - BuildWebHost(args).Run(); + BuildHost(args).Run(); } - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder() - .UseStartup().UseKestrel(options => + public static IHost BuildHost(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { - options.AllowSynchronousIO = true; - - options.Listen( - IPAddress.Loopback, - int.Parse(args[2]), - listenOptions => - { - listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - }); - - options.Listen( - IPAddress.Loopback, - int.Parse(args[3]), - listenOptions => - { - #pragma warning disable SYSLIB0057 - var certificate = new X509Certificate2(args[0], args[1]); - #pragma warning restore SYSLIB0057 - - HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); - httpsOption.SslProtocols = SslProtocols.Tls12; - httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; - httpsOption.CheckCertificateRevocation = false; - httpsOption.ServerCertificate = certificate; - listenOptions.UseHttps(httpsOption); - listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - }); - - options.Listen( - IPAddress.Loopback, - int.Parse(args[4]), - listenOptions => - { - #pragma warning disable SYSLIB0057 - var certificate = new X509Certificate2(args[0], args[1]); - #pragma warning restore SYSLIB0057 - - HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); - - // TLS 1.1 is obsolete. Using this value now defaults to TLS 1.2. - httpsOption.SslProtocols = SslProtocols.Tls12; - - httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; - httpsOption.CheckCertificateRevocation = false; - httpsOption.ServerCertificate = certificate; - listenOptions.UseHttps(httpsOption); - listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - }); - - options.Listen( - IPAddress.Loopback, - int.Parse(args[5]), - listenOptions => - { - #pragma warning disable SYSLIB0057 - var certificate = new X509Certificate2(args[0], args[1]); - #pragma warning restore SYSLIB0057 - - HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); - - // TLS is obsolete. Using this value now defaults to TLS 1.2. - httpsOption.SslProtocols = SslProtocols.Tls12; - - httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; - httpsOption.CheckCertificateRevocation = false; - httpsOption.ServerCertificate = certificate; - listenOptions.UseHttps(httpsOption); - listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - }); - - options.Listen( - IPAddress.Loopback, - int.Parse(args[6]), - listenOptions => - { - #pragma warning disable SYSLIB0057 - var certificate = new X509Certificate2(args[0], args[1]); - #pragma warning restore SYSLIB0057 - - HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); - httpsOption.SslProtocols = SslProtocols.Tls13; - httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; - httpsOption.CheckCertificateRevocation = false; - httpsOption.ServerCertificate = certificate; - listenOptions.UseHttps(httpsOption); - listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - }); + webBuilder.UseStartup(); + webBuilder.UseKestrel(options => + { + options.AllowSynchronousIO = true; + + options.Listen( + IPAddress.Loopback, + int.Parse(args[2]), + listenOptions => + { + listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + }); + + options.Listen( + IPAddress.Loopback, + int.Parse(args[3]), + listenOptions => + { +#pragma warning disable SYSLIB0057 + var certificate = new X509Certificate2(args[0], args[1]); +#pragma warning restore SYSLIB0057 + + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); + httpsOption.SslProtocols = SslProtocols.Tls12; + httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; + httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; + httpsOption.CheckCertificateRevocation = false; + httpsOption.ServerCertificate = certificate; + listenOptions.UseHttps(httpsOption); + listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + }); + + options.Listen( + IPAddress.Loopback, + int.Parse(args[4]), + listenOptions => + { +#pragma warning disable SYSLIB0057 + var certificate = new X509Certificate2(args[0], args[1]); +#pragma warning restore SYSLIB0057 + + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); + + // TLS 1.1 is obsolete. Using this value now defaults to TLS 1.2. + httpsOption.SslProtocols = SslProtocols.Tls12; + + httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; + httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; + httpsOption.CheckCertificateRevocation = false; + httpsOption.ServerCertificate = certificate; + listenOptions.UseHttps(httpsOption); + listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + }); + + options.Listen( + IPAddress.Loopback, + int.Parse(args[5]), + listenOptions => + { +#pragma warning disable SYSLIB0057 + var certificate = new X509Certificate2(args[0], args[1]); +#pragma warning restore SYSLIB0057 + + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); + + // TLS is obsolete. Using this value now defaults to TLS 1.2. + httpsOption.SslProtocols = SslProtocols.Tls12; + + httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; + httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; + httpsOption.CheckCertificateRevocation = false; + httpsOption.ServerCertificate = certificate; + listenOptions.UseHttps(httpsOption); + listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + }); + + options.Listen( + IPAddress.Loopback, + int.Parse(args[6]), + listenOptions => + { +#pragma warning disable SYSLIB0057 + var certificate = new X509Certificate2(args[0], args[1]); +#pragma warning restore SYSLIB0057 + + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); + httpsOption.SslProtocols = SslProtocols.Tls13; + httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; + httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => { return true; }; + httpsOption.CheckCertificateRevocation = false; + httpsOption.ServerCertificate = certificate; + listenOptions.UseHttps(httpsOption); + listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + }); + }); }) .Build(); } diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 0f381efed19..46638197255 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 57c44ca752e..acff38d562a 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -85,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -125,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -335,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -375,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -435,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -615,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -625,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -655,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -665,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -725,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -735,7 +736,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -745,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -755,7 +756,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false @@ -775,11 +776,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.8" + "Version": "9.0.9" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From cfc0bcd9f566170aa55d1a1d6ebf0d68eb93a9d3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 10 Sep 2025 14:57:44 -0700 Subject: [PATCH 047/378] Fix the APIScan pipeline (#26016) 1. When removing unused runtimes, keep the `win` and `win-x64` runtime folders. 2. Stop downloading `getfilesiginforedist.dll` from Azure blob. The original `getfilesiginforedist.dll` produced from the build works fine with the symbols retrieved by `dotnet-symbols`. --- .pipelines/apiscan-gen-notice.yml | 4 +- .pipelines/templates/compliance/apiscan.yml | 55 +++++++-------------- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 54f6f4725c5..9cc83e7136a 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -83,11 +83,11 @@ extends: break: true # always break the build on binskim issues in addition to TSA upload policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - # APIScan requires a non-Ready-To-Run build + # APIScan requires a non-Ready-To-Run build apiscan: enabled: true softwareName: "PowerShell" # Default is repo name - versionNumber: "7.5" # Default is build number + versionNumber: "7.6" # Default is build number isLargeApp: false # Default: false. symbolsFolder: $(SymbolsServerUrl);$(ob_outputDirectory) #softwareFolder - relative path to a folder to be scanned. Default value is root of artifacts folder diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 17f07a597b5..817d5ab777f 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -17,7 +17,6 @@ jobs: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: DotNetPrivateBuildAccess - - group: Azure Blob variable group - group: ReleasePipelineSecrets - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv @@ -75,34 +74,6 @@ jobs: workingDirectory: '$(repoRoot)' retryCountOnTaskFailure: 2 - - task: AzurePowerShell@5 - displayName: Download winverify-private Artifacts - inputs: - azureSubscription: az-blob-cicd-infra - scriptType: inlineScript - azurePowerShellVersion: LatestVersion - workingDirectory: '$(repoRoot)' - pwsh: true - inline: | - # download smybols for getfilesiginforedist.dll - $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' - $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' - $storageAccountName = "pscoretestdata" - $containerName = 'winverify-private' - $winverifySymbolsPath = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)/winverify-symbols' -Force - $dllName = 'getfilesiginforedist.dll' - $winverifySymbolsDllPath = Join-Path $winverifySymbolsPath $dllName - - $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount - - Get-AzStorageBlobContent -Container $containerName -Blob $dllName -Destination $winverifySymbolsDllPath -Context $context - - - pwsh: | - Get-ChildItem -Path '$(System.ArtifactsDirectory)/winverify-symbols' - displayName: Capture winverify-private Artifacts - workingDirectory: '$(repoRoot)' - condition: succeededOrFailed() - - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. displayName: 🔏 CodeQL 3000 Init condition: eq(variables['CODEQL_ENABLED'], 'true') @@ -121,23 +92,35 @@ jobs: Remove-Item -Recurse -Force $OutputFolder/ref } - Copy-Item -Path "$OutputFolder\*" -Destination '$(ob_outputDirectory)' -Recurse -Verbose + $Destination = '$(ob_outputDirectory)' + if (-not (Test-Path $Destination)) { + Write-Verbose -Verbose -Message "Creating destination folder '$Destination'" + $null = mkdir $Destination + } + + Copy-Item -Path "$OutputFolder\*" -Destination $Destination -Recurse -Verbose workingDirectory: '$(repoRoot)' displayName: 'Build PowerShell Source' - pwsh: | - # Only key windows runtimes - Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -notmatch '.*\/runtimes\/win'} | Foreach-Object { + # Only keep windows runtimes + Write-Verbose -Verbose -Message "Deleting non-win-x64 runtimes ..." + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' | Where-Object {$_.FullName -notmatch '.*\\runtimes\\win'} | Foreach-Object { Write-Verbose -Verbose -Message "Deleting $($_.FullName)" - Remove-Item -Force -Verbose -Path $_.FullName + Remove-Item -Path $_.FullName -Recurse -Force } - # Temporarily remove runtimes/win-x64 due to issues with that runtime - Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' -File -Recurse | Where-Object {$_.FullName -match '.*\/runtimes\/win-x86\/'} | Foreach-Object { + # Remove win-x86/arm/arm64 runtimes due to issues with those runtimes + Write-Verbose -Verbose -Message "Temporarily deleting win-x86/arm/arm64 runtimes ..." + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes\*' | Where-Object {$_.FullName -match '.*\\runtimes\\win-(x86|arm)'} | Foreach-Object { Write-Verbose -Verbose -Message "Deleting $($_.FullName)" - Remove-Item -Force -Verbose -Path $_.FullName + Remove-Item -Path $_.FullName -Recurse -Force } + Write-Host + Write-Verbose -Verbose -Message "Show content in 'runtimes' folder:" + Get-ChildItem -Path '$(ob_outputDirectory)\runtimes' + Write-Host workingDirectory: '$(repoRoot)' displayName: 'Remove unused runtimes' From abb70228cb79291519b7d2e4873b382e5a50f044 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 11 Sep 2025 11:29:46 -0700 Subject: [PATCH 048/378] Update version for the package `Microsoft.PowerShell.Native` (#26041) --- .../System.Management.Automation.csproj | 2 +- tools/packaging/boms/windows.json | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index b8245b9d315..a235b37f71e 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -47,7 +47,7 @@ - + diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 81054967e65..d8857c71786 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -14,6 +14,16 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "build.manifest", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "build.manifest.sig", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "clretwrc.dll", "FileType": "NonProduct", From d418ffe84c9480fd5d1a89b5747d9ab591bb5762 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:55:36 +0100 Subject: [PATCH 049/378] Make some tests less noisy on failure (#26035) --- .../Microsoft.PowerShell.PSResourceGet.Tests.ps1 | 4 ++-- test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 | 4 ++-- test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 index 46e4f60cbc2..9285281daec 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.PSResourceGet/Microsoft.PowerShell.PSResourceGet.Tests.ps1 @@ -239,7 +239,7 @@ Describe "PSResourceGet - Module tests (Admin)" -Tags @('Feature', 'RequireAdmin } It "Should install a module correctly to the required location with AllUsers scope" { - Install-PSResource -Name $TestModule -Repository $RepositoryName -Scope AllUsers + Install-PSResource -Name $TestModule -Repository $RepositoryName -Scope AllUsers -ErrorAction Stop $module = Get-Module $TestModule -ListAvailable $module.Name | Should -Be $TestModule @@ -323,7 +323,7 @@ Describe "PSResourceGet - Script tests (Admin)" -Tags @('Feature', 'RequireAdmin } It "Should install a script correctly to the required location with AllUsers scope" { - Install-PSResource -Name $TestScript -Repository $RepositoryName -Scope AllUsers + Install-PSResource -Name $TestScript -Repository $RepositoryName -Scope AllUsers -ErrorAction Stop } AfterAll { diff --git a/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 b/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 index 1fd935b22dd..a3a60fa359a 100644 --- a/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 +++ b/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 @@ -170,7 +170,7 @@ Describe "PowerShellGet - Module tests (Admin)" -Tags @('Feature', 'RequireAdmin } It "Should install a module correctly to the required location with AllUsers scope" { - Install-Module -Name $TestModule -Repository $RepositoryName -Scope AllUsers + Install-Module -Name $TestModule -Repository $RepositoryName -Scope AllUsers -ErrorAction Stop $module = Get-Module $TestModule -ListAvailable $module.Name | Should -Be $TestModule @@ -247,7 +247,7 @@ Describe "PowerShellGet - Script tests (Admin)" -Tags @('Feature', 'RequireAdmin } It "Should install a script correctly to the required location with AllUsers scope" { - Install-Script -Name $TestScript -Repository $RepositoryName -NoPathUpdate -Scope AllUsers + Install-Script -Name $TestScript -Repository $RepositoryName -NoPathUpdate -Scope AllUsers -ErrorAction Stop $installedScriptInfo = Get-InstalledScript -Name $TestScript $installedScriptInfo | Should -Not -BeNullOrEmpty diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index d4cbb420066..593a2ee89d7 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -219,7 +219,7 @@ function RunUpdateHelpTests [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) - Update-Help -Module:$moduleName -Force @UICultureParam @sourcePathParam -Scope:$updateScope + Update-Help -Module:$moduleName -Force @UICultureParam @sourcePathParam -Scope:$updateScope -ErrorAction Stop [hashtable] $userScopeParam = $(if ($userscope) { @{ UserScope = $true } } else { @{} }) ValidateInstalledHelpContent -moduleName:$moduleName @userScopeParam From a5394cb9cf28667e7ebd18121d1a9f953ca1bac4 Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Fri, 12 Sep 2025 02:28:03 +0530 Subject: [PATCH 050/378] Fix a typo in the 7.4 changelog (#26038) --- CHANGELOG/7.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md index 64e955312d8..a4966b09e99 100644 --- a/CHANGELOG/7.4.md +++ b/CHANGELOG/7.4.md @@ -118,7 +118,7 @@
  • Migrate MacOS Signing to OneBranch (#25412)
  • Remove call to NuGet (#25410)
  • Restore a script needed for build from the old release pipeline cleanup (#25201) (#25408)
  • -
  • Switch to ubuntu-lastest for CI (#25406)
  • +
  • Switch to ubuntu-latest for CI (#25406)
  • Update GitHub Actions to work in private GitHub repository (#25403)
  • Simplify PR Template (#25407)
  • Disable SBOM generation on set variables job in release build (#25341)
  • From c15a8efc758702b4e9fcdecf6e9f6dbc4a322c51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:58:23 -0700 Subject: [PATCH 051/378] Bump github/codeql-action from 3.30.2 to 3.30.3 (#26036) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index ad00549eb45..6a30bfcba22 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -189,7 +189,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -215,7 +215,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 29befb40665..237a05d3479 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.29.5 + uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 with: sarif_file: results.sarif From 37a0e3389a20ad28cd11b49b1cacd87ba189465c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 12 Sep 2025 00:06:26 +0100 Subject: [PATCH 052/378] Ensure data-serialization files end with one newline (#26039) --- .github/ISSUE_TEMPLATE/WG_member_request.yaml | 1 - .pipelines/templates/windows-package-build.yml | 1 - .vsts-ci/psresourceget-acr.yml | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/WG_member_request.yaml b/.github/ISSUE_TEMPLATE/WG_member_request.yaml index 052a2b0f713..1d7f0e9ba53 100644 --- a/.github/ISSUE_TEMPLATE/WG_member_request.yaml +++ b/.github/ISSUE_TEMPLATE/WG_member_request.yaml @@ -64,4 +64,3 @@ body: I have the following public links to articles, code, or other resources that demonstrate my skills... validations: required: true - diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/windows-package-build.yml index 53b57df45dd..7cd0869caa0 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/windows-package-build.yml @@ -302,4 +302,3 @@ jobs: displayName: 'List artifacts' env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index ca3334ff271..194c7ba9f57 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -153,4 +153,3 @@ stages: Publish-TestResults -Title "PSResourceGet - ACR tests" -Path $outputFilePath -Type NUnit displayName: 'PSResourceGet ACR functional tests using AzAuth' - From 42e86f6c5faa6a76d59194a5a14c8a85bbe8beb0 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 15 Sep 2025 11:37:04 -0700 Subject: [PATCH 053/378] Fix race condition in RemoteHyperVSocket (#26057) --- .editorconfig | 4 + .github/workflows/linux-ci.yml | 1 + .github/workflows/macos-ci.yml | 1 + .github/workflows/windows-ci.yml | 1 + build.psm1 | 27 +- .../host/msh/CommandLineParameterParser.cs | 137 ++- .../host/msh/ConsoleHost.cs | 51 +- .../CommandLineParameterParserStrings.resx | 3 + .../resources/ConsoleHostStrings.resx | 3 + .../common/RemoteSessionHyperVSocket.cs | 800 ++++++++++++++---- .../fanin/OutOfProcTransportManager.cs | 24 +- .../server/OutOfProcServerMediator.cs | 28 + .../resources/RemotingErrorIdStrings.resx | 6 + test/xUnit/csharp/test_CommandLineParser.cs | 22 + test/xUnit/csharp/test_RemoteHyperV.cs | 661 +++++++++++++++ 15 files changed, 1572 insertions(+), 197 deletions(-) create mode 100644 test/xUnit/csharp/test_RemoteHyperV.cs diff --git a/.editorconfig b/.editorconfig index 72707109516..57d2f6c6c3e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -126,6 +126,10 @@ dotnet_code_quality_unused_parameters = non_public:suggestion # https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/quality-rules/ca1859 dotnet_diagnostic.CA1859.severity = suggestion +# Disable SA1600 (ElementsMustBeDocumented) for test directory only +[test/**/*.cs] +dotnet_diagnostic.SA1600.severity = none + # CSharp code style settings: [*.cs] diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 6a30bfcba22..d4d2c14f8ee 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -21,6 +21,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 8e5f1620bb5..dc1c38a162d 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -19,6 +19,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job concurrency: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 1bc6ebe0a1f..18b426aa191 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -18,6 +18,7 @@ on: - master - release/** - github-mirror + - "*-feature" # Path filters for PRs need to go into the changes job diff --git a/build.psm1 b/build.psm1 index d76dd7f63ff..ffbeddb1c21 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1984,7 +1984,9 @@ function Test-PSPesterResults function Start-PSxUnit { [CmdletBinding()]param( - [string] $xUnitTestResultsFile = "xUnitResults.xml" + [string] $xUnitTestResultsFile = "xUnitResults.xml", + [switch] $DebugLogging, + [string] $Filter ) # Add .NET CLI tools to PATH @@ -2042,9 +2044,28 @@ function Start-PSxUnit { # We run the xUnit tests sequentially to avoid race conditions caused by manipulating the config.json file. # xUnit tests run in parallel by default. To make them run sequentially, we need to define the 'xunit.runner.json' file. - dotnet test --configuration $Options.configuration --test-adapter-path:. "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + $extraParams = @() + if($Filter) { + $extraParams += @( + '--filter' + $Filter + ) + } + + if($DebugLogging) { + $extraParams += @( + "--logger:console;verbosity=detailed" + ) + } else { + $extraParams += @( + "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + ) + } + dotnet test @extraParams --configuration $Options.configuration --test-adapter-path:. - Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + if(!$DebugLogging){ + Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + } } finally { $env:DOTNET_ROOT = $originalDOTNET_ROOT diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs index 50d2bd77d0f..0fb85e740f4 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs @@ -196,6 +196,7 @@ internal static int MaxNameLength() "workingdirectory" }; +#pragma warning disable SA1025 // CodeMustNotContainMultipleWhitespaceInARow /// /// These represent the parameters that are used when starting pwsh. /// We can query in our telemetry to determine how pwsh was invoked. @@ -203,35 +204,36 @@ internal static int MaxNameLength() [Flags] internal enum ParameterBitmap : long { - Command = 0x00000001, // -Command | -c - ConfigurationName = 0x00000002, // -ConfigurationName | -config - CustomPipeName = 0x00000004, // -CustomPipeName - EncodedCommand = 0x00000008, // -EncodedCommand | -e | -ec - EncodedArgument = 0x00000010, // -EncodedArgument - ExecutionPolicy = 0x00000020, // -ExecutionPolicy | -ex | -ep - File = 0x00000040, // -File | -f - Help = 0x00000080, // -Help, -?, /? - InputFormat = 0x00000100, // -InputFormat | -inp | -if - Interactive = 0x00000200, // -Interactive | -i - Login = 0x00000400, // -Login | -l - MTA = 0x00000800, // -MTA - NoExit = 0x00001000, // -NoExit | -noe - NoLogo = 0x00002000, // -NoLogo | -nol - NonInteractive = 0x00004000, // -NonInteractive | -noni - NoProfile = 0x00008000, // -NoProfile | -nop - OutputFormat = 0x00010000, // -OutputFormat | -o | -of - SettingsFile = 0x00020000, // -SettingsFile | -settings - SSHServerMode = 0x00040000, // -SSHServerMode | -sshs - SocketServerMode = 0x00080000, // -SocketServerMode | -sockets - ServerMode = 0x00100000, // -ServerMode | -server - NamedPipeServerMode = 0x00200000, // -NamedPipeServerMode | -namedpipes - STA = 0x00400000, // -STA - Version = 0x00800000, // -Version | -v - WindowStyle = 0x01000000, // -WindowStyle | -w - WorkingDirectory = 0x02000000, // -WorkingDirectory | -wd - ConfigurationFile = 0x04000000, // -ConfigurationFile - NoProfileLoadTime = 0x08000000, // -NoProfileLoadTime - CommandWithArgs = 0x10000000, // -CommandWithArgs | -cwa + Command = 0x0000000000000001, // -Command | -c + ConfigurationName = 0x0000000000000002, // -ConfigurationName | -config + CustomPipeName = 0x0000000000000004, // -CustomPipeName + EncodedCommand = 0x0000000000000008, // -EncodedCommand | -e | -ec + EncodedArgument = 0x0000000000000010, // -EncodedArgument + ExecutionPolicy = 0x0000000000000020, // -ExecutionPolicy | -ex | -ep + File = 0x0000000000000040, // -File | -f + Help = 0x0000000000000080, // -Help, -?, /? + InputFormat = 0x0000000000000100, // -InputFormat | -inp | -if + Interactive = 0x0000000000000200, // -Interactive | -i + Login = 0x0000000000000400, // -Login | -l + MTA = 0x0000000000000800, // -MTA + NoExit = 0x0000000000001000, // -NoExit | -noe + NoLogo = 0x0000000000002000, // -NoLogo | -nol + NonInteractive = 0x0000000000004000, // -NonInteractive | -noni + NoProfile = 0x0000000000008000, // -NoProfile | -nop + OutputFormat = 0x0000000000010000, // -OutputFormat | -o | -of + SettingsFile = 0x0000000000020000, // -SettingsFile | -settings + SSHServerMode = 0x0000000000040000, // -SSHServerMode | -sshs + SocketServerMode = 0x0000000000080000, // -SocketServerMode | -sockets + ServerMode = 0x0000000000100000, // -ServerMode | -server + NamedPipeServerMode = 0x0000000000200000, // -NamedPipeServerMode | -namedpipes + STA = 0x0000000000400000, // -STA + Version = 0x0000000000800000, // -Version | -v + WindowStyle = 0x0000000001000000, // -WindowStyle | -w + WorkingDirectory = 0x0000000002000000, // -WorkingDirectory | -wd + ConfigurationFile = 0x0000000004000000, // -ConfigurationFile + NoProfileLoadTime = 0x0000000008000000, // -NoProfileLoadTime + CommandWithArgs = 0x0000000010000000, // -CommandWithArgs | -cwa + // Enum values for specified ExecutionPolicy EPUnrestricted = 0x0000000100000000, // ExecutionPolicy unrestricted EPRemoteSigned = 0x0000000200000000, // ExecutionPolicy remote signed @@ -241,7 +243,11 @@ internal enum ParameterBitmap : long EPBypass = 0x0000002000000000, // ExecutionPolicy bypass EPUndefined = 0x0000004000000000, // ExecutionPolicy undefined EPIncorrect = 0x0000008000000000, // ExecutionPolicy incorrect + + // V2 Socket Server Mode + V2SocketServerMode = 0x0000100000000000, // -V2SocketServerMode | -v2so } +#pragma warning restore SA1025 // CodeMustNotContainMultipleWhitespaceInARow internal ParameterBitmap ParametersUsed = 0; @@ -597,6 +603,33 @@ internal bool RemoveWorkingDirectoryTrailingCharacter return _removeWorkingDirectoryTrailingCharacter; } } + + internal DateTimeOffset? UTCTimestamp + { + get + { + AssertArgumentsParsed(); + return _utcTimestamp; + } + } + + internal string? Token + { + get + { + AssertArgumentsParsed(); + return _token; + } + } + + internal bool V2SocketServerMode + { + get + { + AssertArgumentsParsed(); + return _v2SocketServerMode; + } + } #endif #endregion Internal properties @@ -916,6 +949,14 @@ private void ParseHelper(string[] args) _showBanner = false; ParametersUsed |= ParameterBitmap.SocketServerMode; } +#if !UNIX + else if (MatchSwitch(switchKey, "v2socketservermode", "v2so")) + { + _v2SocketServerMode = true; + _showBanner = false; + ParametersUsed |= ParameterBitmap.V2SocketServerMode; + } +#endif else if (MatchSwitch(switchKey, "servermode", "s")) { _serverMode = true; @@ -1176,6 +1217,37 @@ private void ParseHelper(string[] args) { _removeWorkingDirectoryTrailingCharacter = true; } + else if (MatchSwitch(switchKey, "token", "to")) + { + ++i; + if (i >= args.Length) + { + SetCommandLineError( + string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.MissingMandatoryArgument, "-Token")); + break; + } + + _token = args[i]; + + // Not adding anything to ParametersUsed, because it is required with V2 socket server mode + // So, we can assume it based on that bit + } + else if (MatchSwitch(switchKey, "utctimestamp", "utc")) + { + ++i; + if (i >= args.Length) + { + SetCommandLineError( + string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.MissingMandatoryArgument, "-UTCTimestamp")); + break; + } + + // Parse as iso8601UtcString + _utcTimestamp = DateTimeOffset.ParseExact(args[i], "yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); + + // Not adding anything to ParametersUsed, because it is required with V2 socket server mode + // So, we can assume it based on that bit + } #endif else { @@ -1530,6 +1602,9 @@ private bool CollectArgs(string[] args, ref int i) } private bool _socketServerMode; +#if !UNIX + private bool _v2SocketServerMode; +#endif private bool _serverMode; private bool _namedPipeServerMode; private bool _sshServerMode; @@ -1562,6 +1637,10 @@ private bool CollectArgs(string[] args, ref int i) private string? _executionPolicy; private string? _settingsFile; private string? _workingDirectory; +#if !UNIX + private string? _token; + private DateTimeOffset? _utcTimestamp; +#endif #if !UNIX private ProcessWindowStyle? _windowStyle; diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index ab9bdab568d..8a38b1904cb 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -198,7 +198,26 @@ internal static int Start( } // Servermode parameter validation check. - if ((s_cpp.ServerMode && s_cpp.NamedPipeServerMode) || (s_cpp.ServerMode && s_cpp.SocketServerMode) || (s_cpp.NamedPipeServerMode && s_cpp.SocketServerMode)) + int serverModeCount = 0; + if (s_cpp.ServerMode) + { + serverModeCount++; + } + if (s_cpp.NamedPipeServerMode) + { + serverModeCount++; + } + if (s_cpp.SocketServerMode) + { + serverModeCount++; + } +#if !UNIX + if (s_cpp.V2SocketServerMode) + { + serverModeCount++; + } +#endif + if (serverModeCount > 1) { s_tracer.TraceError("Conflicting server mode parameters, parameters must be used exclusively."); s_theConsoleHost?.ui.WriteErrorLine(ConsoleHostStrings.ConflictingServerModeParameters); @@ -242,6 +261,34 @@ internal static int Start( configurationName: s_cpp.ConfigurationName); exitCode = 0; } +#if !UNIX + else if (s_cpp.V2SocketServerMode) + { + if (s_cpp.Token == null) + { + s_tracer.TraceError("Token is required for V2SocketServerMode."); + s_theConsoleHost?.ui.WriteErrorLine(string.Format(CultureInfo.CurrentCulture, ConsoleHostStrings.MissingMandatoryParameter, "-Token", "-V2SocketServerMode")); + return ExitCodeBadCommandLineParameter; + } + + if (s_cpp.UTCTimestamp == null) + { + s_tracer.TraceError("UTCTimestamp is required for V2SocketServerMode."); + s_theConsoleHost?.ui.WriteErrorLine(string.Format(CultureInfo.CurrentCulture, ConsoleHostStrings.MissingMandatoryParameter, "-UTCTimestamp", "-v2socketservermode")); + return ExitCodeBadCommandLineParameter; + } + + ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("V2SocketServerMode", s_cpp.ParametersUsedAsDouble); + ProfileOptimization.StartProfile("StartupProfileData-V2SocketServerMode"); + HyperVSocketMediator.Run( + initialCommand: s_cpp.InitialCommand, + configurationName: s_cpp.ConfigurationName, + token: s_cpp.Token, + tokenCreationTime: s_cpp.UTCTimestamp.Value); + + exitCode = 0; + } +#endif else if (s_cpp.SocketServerMode) { ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SocketServerMode", s_cpp.ParametersUsedAsDouble); @@ -1879,6 +1926,7 @@ private void DoRunspaceInitialization(RunspaceCreationEventArgs args) { s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.ShellBannerCLAuditMode); } + break; case PSLanguageMode.NoLanguage: @@ -2745,6 +2793,7 @@ e is RemoteException || #endif } } + // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 // Removed HandleUnexpectedExceptions infrastructure finally diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx index 34bb696c33c..33445ceebd2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx @@ -225,4 +225,7 @@ Valid formats are: Invalid ExecutionPolicy value '{0}'. + + An argument is required to be supplied to the '{0}' parameter. + diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx index 80b3d4aafe0..9bc06e0d42f 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx @@ -185,4 +185,7 @@ The current session does not support debugging; execution will continue. PushRunspace can only push a remote runspace. + + The '{0}' parameter is mandatory and must be specified when using the '{1}' parameter. + diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index 94ce5af0208..02cf5b29697 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -7,8 +7,10 @@ using System.Net.Sockets; using System.Text; using System.Threading; +using System.Buffers; using Dbg = System.Diagnostics.Debug; +using SMA = System.Management.Automation; namespace System.Management.Automation.Remoting { @@ -140,6 +142,10 @@ internal sealed class RemoteSessionHyperVSocketServer : IDisposable private readonly object _syncObject; private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource(); + // This is to prevent persistent replay attacks. + // it is not meant to ensure all replay attacks are impossible. + private const int MAX_TOKEN_LIFE_MINUTES = 10; + #endregion #region Properties @@ -175,64 +181,74 @@ internal sealed class RemoteSessionHyperVSocketServer : IDisposable public RemoteSessionHyperVSocketServer(bool LoopbackMode) { - // TODO: uncomment below code when .NET supports Hyper-V socket duplication - /* - NamedPipeClientStream clientPipeStream; - byte[] buffer = new byte[1000]; - int bytesRead; - */ _syncObject = new object(); Exception ex = null; try { - // TODO: uncomment below code when .NET supports Hyper-V socket duplication - /* - if (!LoopbackMode) - { - // - // Create named pipe client. - // - using (clientPipeStream = new NamedPipeClientStream(".", - "PS_VMSession", - PipeDirection.InOut, - PipeOptions.None, - TokenImpersonationLevel.None)) - { - // - // Connect to named pipe server. - // - clientPipeStream.Connect(10*1000); - - // - // Read LPWSAPROTOCOL_INFO. - // - bytesRead = clientPipeStream.Read(buffer, 0, 1000); - } - } + Guid serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); // HV_GUID_VM_SESSION_SERVICE_ID_2 + Guid loopbackId = new Guid("e0e16197-dd56-4a10-9195-5ee7a155a838"); // HV_GUID_LOOPBACK + Guid parentId = new Guid("a42e7cda-d03f-480c-9cc2-a4de20abb878"); // HV_GUID_PARENT + Guid vmId = LoopbackMode ? loopbackId : parentId; + HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, vmId, serviceId); + + Socket listenSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + listenSocket.Bind(endpoint); + + listenSocket.Listen(1); + HyperVSocket = listenSocket.Accept(); + + Stream = new NetworkStream(HyperVSocket, true); + + // Create reader/writer streams. + TextReader = new StreamReader(Stream); + TextWriter = new StreamWriter(Stream); + TextWriter.AutoFlush = true; // - // Create duplicate socket. + // listenSocket is not closed when it goes out of scope here. Sometimes it is + // closed later in this thread, while other times it is not closed at all. This will + // cause problem when we set up a second PowerShell Direct session. Let's + // explicitly close listenSocket here for safe. // - byte[] protocolInfo = new byte[bytesRead]; - Array.Copy(buffer, protocolInfo, bytesRead); + if (listenSocket != null) + { + try { listenSocket.Dispose(); } + catch (ObjectDisposedException) { } + } + } + catch (Exception e) + { + ex = e; + } - SocketInformation sockInfo = new SocketInformation(); - sockInfo.ProtocolInformation = protocolInfo; - sockInfo.Options = SocketInformationOptions.Connected; + if (ex != null) + { + Dbg.Fail("Unexpected error in RemoteSessionHyperVSocketServer."); - socket = new Socket(sockInfo); - if (socket == null) - { - Dbg.Assert(false, "Unexpected error in RemoteSessionHyperVSocketServer."); + // Unexpected error. + string errorMessage = !string.IsNullOrEmpty(ex.Message) ? ex.Message : string.Empty; + _tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, + "Unexpected error in constructor: {0}", errorMessage); - tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, - "Unexpected error in constructor: {0}", "socket duplication failure"); - } - */ + throw new PSInvalidOperationException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketServerConstructorFailure), + ex, + nameof(PSRemotingErrorId.RemoteSessionHyperVSocketServerConstructorFailure), + ErrorCategory.InvalidOperation, + null); + } + } + + public RemoteSessionHyperVSocketServer(bool LoopbackMode, string token, DateTimeOffset tokenCreationTime) + { + _syncObject = new object(); - // TODO: remove below 6 lines of code when .NET supports Hyper-V socket duplication + Exception ex = null; + + try + { Guid serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); // HV_GUID_VM_SESSION_SERVICE_ID_2 HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, Guid.Empty, serviceId); @@ -242,6 +258,31 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) listenSocket.Listen(1); HyperVSocket = listenSocket.Accept(); + TimeSpan timeout = TimeSpan.FromMinutes(MAX_TOKEN_LIFE_MINUTES); + DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); + DateTimeOffset now = DateTimeOffset.UtcNow; + + // Calculate remaining time and create cancellation token + TimeSpan remainingTime = timeoutExpiry - now; + + // Check if the token has already expired + if (remainingTime <= TimeSpan.Zero) + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); + } + + // Set socket timeout for receive operations to prevent indefinite blocking + int timeoutMs = (int)remainingTime.TotalMilliseconds; + HyperVSocket.ReceiveTimeout = timeoutMs; + HyperVSocket.SendTimeout = timeoutMs; + + // Create a cancellation token that will be cancelled when the timeout expires + using var cancellationTokenSource = new CancellationTokenSource(remainingTime); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + ValidateToken(HyperVSocket, token, cancellationToken); + Stream = new NetworkStream(HyperVSocket, true); // Create reader/writer streams. @@ -257,8 +298,13 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) // if (listenSocket != null) { - try { listenSocket.Dispose(); } - catch (ObjectDisposedException) { } + try + { + listenSocket.Dispose(); + } + catch (ObjectDisposedException) + { + } } } catch (Exception e) @@ -272,8 +318,12 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) // Unexpected error. string errorMessage = !string.IsNullOrEmpty(ex.Message) ? ex.Message : string.Empty; - _tracer.WriteMessage("RemoteSessionHyperVSocketServer", "RemoteSessionHyperVSocketServer", Guid.Empty, - "Unexpected error in constructor: {0}", errorMessage); + _tracer.WriteMessage( + "RemoteSessionHyperVSocketServer", + "RemoteSessionHyperVSocketServer", + Guid.Empty, + "Unexpected error in constructor: {0}", + errorMessage); throw new PSInvalidOperationException( PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketServerConstructorFailure), @@ -283,7 +333,6 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) null); } } - #endregion #region IDisposable @@ -333,6 +382,79 @@ public void Dispose() } #endregion + + /// + /// Validates the token received from the client over the HyperVSocket. + /// Throws PSDirectException if the token is invalid or not received in time. + /// + /// The connected HyperVSocket. + /// The expected token string. + /// Cancellation token for timeout handling. + internal static void ValidateToken(Socket socket, string token, CancellationToken cancellationToken = default) + { + // Check for cancellation before starting validation + cancellationToken.ThrowIfCancellationRequested(); + + // We should move to this pattern and + // in the tests I found I needed to get a bigger buffer than the token length + // and test length of the received data similar to this pattern. + string responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, RemoteSessionHyperVSocketClient.VERSION_REQUEST.Length + 4); + if (string.IsNullOrEmpty(responseString) || responseString.Length != RemoteSessionHyperVSocketClient.VERSION_REQUEST.Length) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Version Request: " + responseString)); + } + + cancellationToken.ThrowIfCancellationRequested(); + + socket.Send(Encoding.UTF8.GetBytes(RemoteSessionHyperVSocketClient.CLIENT_VERSION)); + responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, RemoteSessionHyperVSocketClient.CLIENT_VERSION.Length + 4); + + // In the future we may need to handle different versions, differently. + // For now, we are just checking that we exchanged versions correctly. + if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith(RemoteSessionHyperVSocketClient.VERSION_PREFIX, StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Version Response: " + responseString)); + } + + cancellationToken.ThrowIfCancellationRequested(); + + socket.Send("PASS"u8); + + // The client should send the token in the format TOKEN + // the token should be up to 256 bits, which is less than 50 characters. + // I'll double that to 100 characters to be safe, plus the "TOKEN " prefix. + // So we expect a response of length 6 + 100 = 106 characters. + responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, 110); + + cancellationToken.ThrowIfCancellationRequested(); + + if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith("TOKEN ", StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + // If the response is not in the expected format, we throw an exception. + // This is a failure to authenticate the client. + // don't send this response for risk of information disclosure. + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Token Response")); + } + + // Extract the token from the response. + string responseToken = responseString.Substring(6).Trim(); + + if (!string.Equals(responseToken, token, StringComparison.Ordinal)) + { + socket.Send("FAIL"u8); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + // Acknowledge the token is valid with "PASS". + socket.Send("PASS"u8); + } } internal sealed class RemoteSessionHyperVSocketClient : IDisposable @@ -340,7 +462,15 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable #region Members private readonly object _syncObject; - private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource(); + + #region tracer + /// + /// An instance of the PSTraceSource class used for trace output. + /// + [SMA.TraceSource("RemoteSessionHyperVSocketClient", "Class that has PowerShell Direct Client implementation")] + private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("RemoteSessionHyperVSocketClient", "Class that has PowerShell Direct Client implementation"); + + #endregion tracer private static readonly ManualResetEvent s_connectDone = new ManualResetEvent(false); @@ -354,6 +484,14 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable #endregion + #region version constants + + internal const string VERSION_REQUEST = "VERSION"; + internal const string CLIENT_VERSION = "VERSION_2"; + internal const string VERSION_PREFIX = "VERSION_"; + + #endregion + #region Properties /// @@ -364,7 +502,7 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable /// /// Returns the Hyper-V socket object. /// - public Socket HyperVSocket { get; } + public Socket HyperVSocket { get; private set; } /// /// Returns the network stream object. @@ -381,6 +519,37 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable /// public StreamWriter TextWriter { get; private set; } + /// + /// True if the client is a Hyper-V container. + /// + public bool IsContainer { get; } + + /// + /// True if the client is using backwards compatible mode. + /// This is used to determine if the client should use + /// the backwards compatible or not. + /// In modern mode, the vmicvmsession service will + /// hand off the socket to the PowerShell process + /// inside the VM automatically. + /// In backwards compatible mode, the vmicvmsession + /// service create a new socket to the PowerShell process + /// inside the VM. + /// + public bool UseBackwardsCompatibleMode { get; private set; } + + /// + /// The authentication token used for the session. + /// This token is provided by the broker and provided to the server to authenticate the server session. + /// This protocol uses two connections: + /// 1. The first is to the broker or vmicvmsession service to exchange credentials and configuration. + /// The broker will respond with an authentication token. The broker also launches a PowerShell + /// server process with the authentication token. + /// 2. The second is to the server process, that was launched by the broker, + /// inside the VM, which uses the authentication token to verify that the client is the same client + /// that connected to the broker. + /// + public string AuthenticationToken { get; private set; } + /// /// Returns true if object is currently disposed. /// @@ -393,7 +562,9 @@ internal sealed class RemoteSessionHyperVSocketClient : IDisposable internal RemoteSessionHyperVSocketClient( Guid vmId, bool isFirstConnection, - bool isContainer = false) + bool useBackwardsCompatibleMode = false, + bool isContainer = false, + string authenticationToken = null) { Guid serviceId; @@ -412,28 +583,16 @@ internal RemoteSessionHyperVSocketClient( EndPoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, vmId, serviceId); - HyperVSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + IsContainer = isContainer; - // - // We need to call SetSocketOption() in order to set up Hyper-V socket connection between container host and Hyper-V container. - // Here is the scenario: the Hyper-V container is inside a utility vm, which is inside the container host - // - if (isContainer) - { - var value = new byte[sizeof(uint)]; - value[0] = 1; + UseBackwardsCompatibleMode = useBackwardsCompatibleMode; - try - { - HyperVSocket.SetSocketOption((System.Net.Sockets.SocketOptionLevel)HV_PROTOCOL_RAW, - (System.Net.Sockets.SocketOptionName)HVSOCKET_CONTAINER_PASSTHRU, - (byte[])value); - } - catch - { - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure)); - } + if (!isFirstConnection && !useBackwardsCompatibleMode && !string.IsNullOrEmpty(authenticationToken)) + { + // If this is not the first connection and we are using backwards compatible mode, + // we should not set the authentication token here. + // The authentication token will be set during the Connect method. + AuthenticationToken = authenticationToken; } } @@ -489,6 +648,81 @@ public void Dispose() #region Public Methods + private void ShutdownSocket() + { + if (HyperVSocket != null) + { + // Ensure the socket is disposed properly. + try + { + s_tracer.WriteLine("ShutdownSocket: Disposing of the HyperVSocket."); + HyperVSocket.Dispose(); + } + catch (Exception ex) + { + s_tracer.WriteLine("ShutdownSocket: Exception while disposing the socket: {0}", ex.Message); + } + } + + // Dispose of the existing stream if it exists. + if (Stream != null) + { + try + { + Stream.Dispose(); + } + catch (Exception ex) + { + s_tracer.WriteLine("ShutdownSocket: Exception while disposing the stream: {0}", ex.Message); + } + } + } + + /// + /// Recreates the HyperVSocket and connects it to the endpoint, updating the Stream if successful. + /// + private bool ConnectSocket() + { + HyperVSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + + // + // We need to call SetSocketOption() in order to set up Hyper-V socket connection between container host and Hyper-V container. + // Here is the scenario: the Hyper-V container is inside a utility vm, which is inside the container host + // + if (IsContainer) + { + var value = new byte[sizeof(uint)]; + value[0] = 1; + + try + { + HyperVSocket.SetSocketOption( + (System.Net.Sockets.SocketOptionLevel)HV_PROTOCOL_RAW, + (System.Net.Sockets.SocketOptionName)HVSOCKET_CONTAINER_PASSTHRU, + value); + } + catch + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure)); + } + } + + s_tracer.WriteLine("Connect: Client connecting, to {0}; isContainer: {1}.", EndPoint.ServiceId.ToString(), IsContainer); + HyperVSocket.Connect(EndPoint); + + // Check if the socket is connected. + // If it is connected, create a NetworkStream. + if (HyperVSocket.Connected) + { + s_tracer.WriteLine("Connect: Client connected, to {0}; isContainer: {1}.", EndPoint.ServiceId.ToString(), IsContainer); + Stream = new NetworkStream(HyperVSocket, true); + return true; + } + + return false; + } + /// /// Connect to Hyper-V socket server. This is a blocking call until a /// connection occurs or the timeout time has elapsed. @@ -516,100 +750,51 @@ public bool Connect( } } - HyperVSocket.Connect(EndPoint); - - if (HyperVSocket.Connected) + if (ConnectSocket()) { - _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty, - "Client connected."); - - Stream = new NetworkStream(HyperVSocket, true); - if (isFirstConnection) { - if (string.IsNullOrEmpty(networkCredential.Domain)) + var exchangeResult = ExchangeCredentialsAndConfiguration(networkCredential, configurationName, HyperVSocket, this.UseBackwardsCompatibleMode); + if (!exchangeResult.success) { - networkCredential.Domain = "localhost"; - } + // We will not block here for a container because a container does not have a broker. + if (IsRequirePsDirectAuthenticationEnabled(@"SOFTWARE\\Microsoft\\PowerShell", Microsoft.Win32.RegistryHive.LocalMachine)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: RequirePsDirectAuthentication is enabled, requiring latest transport version."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVNegotiationFailed)); + } - bool emptyPassword = string.IsNullOrEmpty(networkCredential.Password); - bool emptyConfiguration = string.IsNullOrEmpty(configurationName); - - byte[] domain = Encoding.Unicode.GetBytes(networkCredential.Domain); - byte[] userName = Encoding.Unicode.GetBytes(networkCredential.UserName); - byte[] password = Encoding.Unicode.GetBytes(networkCredential.Password); - byte[] response = new byte[4]; // either "PASS" or "FAIL" - string responseString; - - // - // Send credential to VM so that PowerShell process inside VM can be - // created under the correct security context. - // - HyperVSocket.Send(domain); - HyperVSocket.Receive(response); - - HyperVSocket.Send(userName); - HyperVSocket.Receive(response); - - // - // We cannot simply send password because if it is empty, - // the vmicvmsession service in VM will block in recv method. - // - if (emptyPassword) - { - HyperVSocket.Send("EMPTYPW"u8); - HyperVSocket.Receive(response); - responseString = Encoding.ASCII.GetString(response); - } - else - { - HyperVSocket.Send("NONEMPTYPW"u8); - HyperVSocket.Receive(response); + this.UseBackwardsCompatibleMode = true; + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Using backwards compatible mode."); - HyperVSocket.Send(password); - HyperVSocket.Receive(response); - responseString = Encoding.ASCII.GetString(response); + // If the first connection fails in modern mode, fall back to backwards compatible mode. + ShutdownSocket(); // will terminate the broker + ConnectSocket(); // restart the broker + exchangeResult = ExchangeCredentialsAndConfiguration(networkCredential, configurationName, HyperVSocket, this.UseBackwardsCompatibleMode); + if (!exchangeResult.success) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Failed to exchange credentials and configuration in backwards compatible mode."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Credential")); + } } - - // - // There are 3 cases for the responseString received above. - // - "FAIL": credential is invalid - // - "PASS": credential is valid, but PowerShell Direct in VM does not support configuration (Server 2016 TP4 and before) - // - "CONF": credential is valid, and PowerShell Direct in VM supports configuration (Server 2016 TP5 and later) - // - - // - // Credential is invalid. - // - if (string.Equals(responseString, "FAIL", StringComparison.Ordinal)) + else { - HyperVSocket.Send(response); - - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + this.AuthenticationToken = exchangeResult.authenticationToken; } + } - // - // If PowerShell Direct in VM supports configuration, send configuration name. - // - if (string.Equals(responseString, "CONF", StringComparison.Ordinal)) + if (!isFirstConnection) + { + if (!this.UseBackwardsCompatibleMode) { - if (emptyConfiguration) - { - HyperVSocket.Send("EMPTYCF"u8); - } - else - { - HyperVSocket.Send("NONEMPTYCF"u8); - HyperVSocket.Receive(response); - - byte[] configName = Encoding.Unicode.GetBytes(configurationName); - HyperVSocket.Send(configName); - } + s_tracer.WriteLine("Connect-Server: Performing transport version and token exchange for Hyper-V socket. isFirstConnection: {0}, UseBackwardsCompatibleMode: {1}", isFirstConnection, this.UseBackwardsCompatibleMode); + RemoteSessionHyperVSocketClient.PerformTransportVersionAndTokenExchange(HyperVSocket, this.AuthenticationToken); } else { - HyperVSocket.Send(response); + s_tracer.WriteLine("Connect-Server: Skipping transport version and token exchange for backwards compatible mode."); } } @@ -621,8 +806,7 @@ public bool Connect( } else { - _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty, - "Client unable to connect."); + s_tracer.WriteLine("Connect: Client unable to connect."); result = false; } @@ -630,12 +814,318 @@ public bool Connect( return result; } + /// + /// Performs the transport version and token exchange sequence for the Hyper-V socket connection. + /// Throws PSDirectException on failure. + /// + /// The socket to use for communication. + /// The authentication token to send. + public static void PerformTransportVersionAndTokenExchange(Socket socket, string authenticationToken) + { + if (string.IsNullOrEmpty(authenticationToken)) + { + s_tracer.WriteLine("PerformTransportVersionAndTokenExchange: Authentication token is null or empty. Aborting transport version and token exchange."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + socket.Send(Encoding.UTF8.GetBytes(VERSION_REQUEST)); + string responseStr = ReceiveResponse(socket, 16); + + // Check if the response starts with the expected version prefix. + // We will rely on the broker to determine if the two can communicate. + // At least, for now. + if (!responseStr.StartsWith(VERSION_PREFIX, StringComparison.Ordinal)) + { + s_tracer.WriteLine("PerformTransportVersionAndTokenExchange: Server responded with an invalid response of {0}. Notifying the transport manager to downgrade if allowed.", responseStr); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Server", "TransportVersion")); + } + + socket.Send(Encoding.UTF8.GetBytes(CLIENT_VERSION)); + string response = ReceiveResponse(socket, 4); // either "PASS" or "FAIL" + + if (!string.Equals(response, "PASS", StringComparison.Ordinal)) + { + s_tracer.WriteLine( + "PerformTransportVersionAndTokenExchange: Transport version negotiation with server failed. Response: {0}", response); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Server", "TransportVersion")); + } + + byte[] tokenBytes = Encoding.UTF8.GetBytes("TOKEN " + authenticationToken); + socket.Send(tokenBytes); + + // This is the opportunity for the server to tell the client to go away. + string tokenResponse = ReceiveResponse(socket, 256); // either "PASS" or "FAIL", but get a little more buffer to allow for better error in the future + if (!string.Equals(tokenResponse, "PASS", StringComparison.Ordinal)) + { + s_tracer.WriteLine( + "PerformTransportVersionAndTokenExchange: Server Authentication Token exchange failed. Response: {0}", tokenResponse); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + } + + /// + /// Checks if the registry key RequirePsDirectAuthentication is set to 1. + /// Returns true if fallback should be aborted. + /// Uses the 64-bit registry view on 64-bit systems to ensure consistent behavior regardless of process architecture. + /// On 32-bit systems, uses the default registry view since there is no WOW64 redirection. + /// + internal static bool IsRequirePsDirectAuthenticationEnabled(string keyPath, Microsoft.Win32.RegistryHive registryHive) + { + const string regValueName = "RequirePsDirectAuthentication"; + + try + { + Microsoft.Win32.RegistryView registryView = Environment.Is64BitOperatingSystem + ? Microsoft.Win32.RegistryView.Registry64 + : Microsoft.Win32.RegistryView.Default; + + using (Microsoft.Win32.RegistryKey baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey( + registryHive, + registryView)) + { + using (Microsoft.Win32.RegistryKey key = baseKey.OpenSubKey(keyPath)) + { + if (key != null) + { + var value = key.GetValue(regValueName); + if (value is int intValue && intValue != 0) + { + return true; + } + } + + return false; + } + } + } + catch (Exception regEx) + { + s_tracer.WriteLine("IsRequirePsDirectAuthenticationEnabled: Exception while checking registry key: {0}", regEx.Message); + return false; // If we cannot read the registry, assume the feature is not enabled. + } + } + + /// + /// Handles credential and configuration exchange with the VM for the first connection. + /// + public static (bool success, string authenticationToken) ExchangeCredentialsAndConfiguration(NetworkCredential networkCredential, string configurationName, Socket HyperVSocket, bool useBackwardsCompatibleMode) + { + // Encoding for the Hyper-V socket communication + // To send the domain, username, password, and configuration name, use UTF-16 (Encoding.Unicode) + // All other sends use UTF-8 (Encoding.UTF8) + // Receiving uses ASCII encoding + // NOT CONFUSING AT ALL + + if (!useBackwardsCompatibleMode) + { + HyperVSocket.Send(Encoding.UTF8.GetBytes(VERSION_REQUEST)); + // vmicvmsession service in VM will respond with "VERSION_2" or newer + // Version 1 protocol will respond with "PASS" or "FAIL" + // Receive the response and check for VERSION_2 or newer + string responseStr = ReceiveResponse(HyperVSocket, 16); + if (!responseStr.StartsWith(VERSION_PREFIX, StringComparison.Ordinal)) + { + s_tracer.WriteLine("When asking for version the server responded with an invalid response of {0}.", responseStr); + s_tracer.WriteLine("Session is invalid, continuing session with a fake user to close the session with the broker for stability."); + // If not the new protocol, finish the conversation + // Send a fake user + // Use ? <> that are illegal in user names so no one can create the user + string probeUserName = "?"; // must be less than or equal to 20 characters for Windows Server 2016 + s_tracer.WriteLine("probeUserName (static): length: {0}", probeUserName.Length); + SendUserData(probeUserName, HyperVSocket); + responseStr = ReceiveResponse(HyperVSocket, 4); // either "PASS" or "FAIL" + s_tracer.WriteLine("When sending user {0}.", responseStr); + + // Send that the password is empty + HyperVSocket.Send("EMPTYPW"u8); + responseStr = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" + s_tracer.WriteLine("When sending EMPTYPW: {0}.", responseStr); // server responds with FAIL so we respond with FAIL and the conversation is done + HyperVSocket.Send("FAIL"u8); + + s_tracer.WriteLine("Notifying the transport manager to downgrade if allowed."); + // end new code + return (false, null); + } + + HyperVSocket.Send(Encoding.UTF8.GetBytes(CLIENT_VERSION)); + ReceiveResponse(HyperVSocket, 4); // either "PASS" or "FAIL" + } + + if (string.IsNullOrEmpty(networkCredential.Domain)) + { + networkCredential.Domain = "localhost"; + } + + System.Security.SecureString securePassword = networkCredential.SecurePassword; + int passwordLength = securePassword.Length; + bool emptyPassword = (passwordLength <= 0); + bool emptyConfiguration = string.IsNullOrEmpty(configurationName); + + string responseString; + + // Send credential to VM so that PowerShell process inside VM can be + // created under the correct security context. + SendUserData(networkCredential.Domain, HyperVSocket); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + SendUserData(networkCredential.UserName, HyperVSocket); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + // We cannot simply send password because if it is empty, + // the vmicvmsession service in VM will block in recv method. + if (emptyPassword) + { + HyperVSocket.Send("EMPTYPW"u8); + responseString = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" (note, "PASS" is not used in VERSION_2 or newer mode) + } + else + { + HyperVSocket.Send("NONEMPTYPW"u8); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + // Get the password bytes from the SecureString, send them, and then zero out the byte array. + byte[] passwordBytes = Microsoft.PowerShell.SecureStringHelper.GetData(securePassword); + try + { + HyperVSocket.Send(passwordBytes); + } + finally + { + // Zero out the byte array for security + Array.Clear(passwordBytes); + } + + responseString = ReceiveResponse(HyperVSocket, 4); // either "CONF", "PASS" or "FAIL" (note, "PASS" is not used in VERSION_2 or newer mode) + } + + // Check for invalid response from server + if (!string.Equals(responseString, "FAIL", StringComparison.Ordinal) && + !string.Equals(responseString, "PASS", StringComparison.Ordinal) && + !string.Equals(responseString, "CONF", StringComparison.Ordinal)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server responded with an invalid response of {0} for credentials.", responseString); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Credential")); + } + + // Credential is invalid. + if (string.Equals(responseString, "FAIL", StringComparison.Ordinal)) + { + HyperVSocket.Send("FAIL"u8); + // should we be doing this? Disabling the test for now + // HyperVSocket.Shutdown(SocketShutdown.Both); + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server responded with FAIL for credentials."); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); + } + + // If PowerShell Direct in VM supports configuration, send configuration name. + if (string.Equals(responseString, "CONF", StringComparison.Ordinal)) + { + if (emptyConfiguration) + { + HyperVSocket.Send("EMPTYCF"u8); + } + else + { + HyperVSocket.Send("NONEMPTYCF"u8); + ReceiveResponse(HyperVSocket, 4); // only "PASS" is expected + + SendUserData(configurationName, HyperVSocket); + } + } + else + { + HyperVSocket.Send("PASS"u8); + } + + if (!useBackwardsCompatibleMode) + { + // Receive the token from the server + // Getting 1024 bytes because it is well above the expected token size + // The expected size at the time of writing this would be about 50 based64 characters, + // plus the 6 characters for the "TOKEN " prefix. + // The 50 character size is designed to last 10 years of cryptographic changes. + // Since the broker completely controls the cryptographic portion here, + // allowing a significant larger size, allows the broker to make almost arbitrary changes, + // without breaking the client. + string token = ReceiveResponse(HyperVSocket, 1024); // either "PASS" or "FAIL" + if (token == null || !token.StartsWith("TOKEN ", StringComparison.Ordinal)) + { + s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server did not respond with a valid token. Response: {0}", token); + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Token " + token)); + } + + token = token.Substring(6); // remove "TOKEN " prefix + + HyperVSocket.Send("PASS"u8); // acknowledge the token + return (true, token); + } + + return (true, null); + } + public void Close() { Stream.Dispose(); HyperVSocket.Dispose(); } + /// + /// Receives a response from the socket and decodes it. + /// + /// The socket to receive from. + /// The size of the buffer to use for receiving data. + /// The decoded response string. + internal static string ReceiveResponse(Socket socket, int bufferSize) + { + System.Buffers.ArrayPool pool = System.Buffers.ArrayPool.Shared; + byte[] responseBuffer = pool.Rent(bufferSize); + int bytesReceived = 0; + try + { + bytesReceived = socket.Receive(responseBuffer); + if (bytesReceived == 0) + { + return null; + } + + string response = Encoding.ASCII.GetString(responseBuffer, 0, bytesReceived); + + // Handle null terminators and log if found + if (response.EndsWith('\0')) + { + int originalLength = response.Length; + response = response.TrimEnd('\0'); + // Cannot log actual response, because we don't know if it is sensitive + s_tracer.WriteLine( + "ReceiveResponse: Removed null terminator(s). Original length: {0}, New length: {1}", + originalLength, + response.Length); + } + + return response; + } + finally + { + pool.Return(responseBuffer); + } + } + + /// + /// Sends user data (domain, username, etc.) over the HyperVSocket using Unicode encoding. + /// + private static void SendUserData(string data, Socket socket) + { + // this encodes the data in UTF-16 (Unicode) + byte[] buffer = Encoding.Unicode.GetBytes(data); + socket.Send(buffer); + } #endregion } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index 96a8b833885..d9532c8691a 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1014,7 +1014,7 @@ internal void OnCloseTimeOutTimerElapsed(object source) } #endregion - + #region Protected Methods /// @@ -1544,8 +1544,9 @@ internal VMHyperVSocketClientSessionTransportManager( /// public override void CreateAsync() { - _client = new RemoteSessionHyperVSocketClient(_vmGuid, true); - if (!_client.Connect(_networkCredential, _configurationName, true)) + // isFirstConnection: true - specifies to use VM_SESSION_SERVICE_ID socket. + _client = new RemoteSessionHyperVSocketClient(_vmGuid, useBackwardsCompatibleMode: false, isFirstConnection: true); + if (!_client.Connect(_networkCredential, _configurationName, isFirstConnection: true)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1555,11 +1556,14 @@ public override void CreateAsync() ErrorCategory.InvalidOperation, null); } + bool useBackwardsCompatibleMode = _client.UseBackwardsCompatibleMode; + string token = _client.AuthenticationToken; - // TODO: remove below 3 lines when Hyper-V socket duplication is supported in .NET framework. _client.Dispose(); - _client = new RemoteSessionHyperVSocketClient(_vmGuid, false); - if (!_client.Connect(_networkCredential, _configurationName, false)) + + // isFirstConnection: false - specifies to use the SESSION_SERVICE_ID_2 socket. + _client = new RemoteSessionHyperVSocketClient(_vmGuid, useBackwardsCompatibleMode: useBackwardsCompatibleMode, isFirstConnection: false, authenticationToken: token); + if (!_client.Connect(_networkCredential, _configurationName, isFirstConnection: false)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1617,7 +1621,9 @@ internal ContainerHyperVSocketClientSessionTransportManager( /// public override void CreateAsync() { - _client = new RemoteSessionHyperVSocketClient(_targetGuid, false, true); + // Container scenario is not working. + // When we fix it we need to setup the token in ContainerConnectionInfo and use it here. + _client = new RemoteSessionHyperVSocketClient(_targetGuid, isFirstConnection: false, useBackwardsCompatibleMode: false, isContainer: true); if (!_client.Connect(null, string.Empty, false)) { _client.Dispose(); @@ -1716,7 +1722,7 @@ public override void CreateAsync() // Start connection timeout timer if requested. // Timer callback occurs only once after timeout time. _connectionTimer = new Timer( - callback: (_) => + callback: (_) => { if (_connectionEstablished) { @@ -2505,7 +2511,7 @@ internal OutOfProcessServerSessionTransportManager(OutOfProcessTextWriter outWri _stdErrWriter = errWriter; _cmdTransportManagers = new Dictionary(); - this.WSManTransportErrorOccured += (object sender, TransportErrorOccuredEventArgs e) => + this.WSManTransportErrorOccured += (object sender, TransportErrorOccuredEventArgs e) => { string msg = e.Exception.TransportMessage ?? e.Exception.InnerException?.Message ?? string.Empty; _stdErrWriter.WriteLine(StringUtil.Format(RemotingErrorIdStrings.RemoteTransportError, msg)); diff --git a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs index 14b0240858b..6c794e21b24 100644 --- a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs +++ b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs @@ -635,6 +635,16 @@ private HyperVSocketMediator() originalStdErr = new HyperVSocketErrorTextWriter(_hypervSocketServer.TextWriter); } + private HyperVSocketMediator(string token, + DateTimeOffset tokenCreationTime) + : base(false) + { + _hypervSocketServer = new RemoteSessionHyperVSocketServer(false, token: token, tokenCreationTime: tokenCreationTime); + + originalStdIn = _hypervSocketServer.TextReader; + originalStdOut = new OutOfProcessTextWriter(_hypervSocketServer.TextWriter); + originalStdErr = new HyperVSocketErrorTextWriter(_hypervSocketServer.TextWriter); + } #endregion #region Static Methods @@ -656,6 +666,24 @@ internal static void Run( configurationFile: null); } + internal static void Run( + string initialCommand, + string configurationName, + string token, + DateTimeOffset tokenCreationTime) + { + lock (SyncObject) + { + s_instance = new HyperVSocketMediator(token, tokenCreationTime); + } + + s_instance.Start( + initialCommand: initialCommand, + cryptoHelper: new PSRemotingCryptoHelperServer(), + workingDirectory: null, + configurationName: configurationName, + configurationFile: null); + } #endregion } diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 9e572797bd2..a9dc46bdec5 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1726,4 +1726,10 @@ SSH client process terminated before connection could be established. Failed to get Hyper-V VM State. The value was of the type {0} but was expected to be Microsoft.HyperV.PowerShell.VMState or System.String. + + Hyper-V {0} sent an invalid {1} response during the connection negotiation. + + + Negotiating a secure connection to Hyper-V failed. Make sure the Host and Guest are updated with all relevant Microsoft Updates. + diff --git a/test/xUnit/csharp/test_CommandLineParser.cs b/test/xUnit/csharp/test_CommandLineParser.cs index 5025584d6ac..01f572d230d 100644 --- a/test/xUnit/csharp/test_CommandLineParser.cs +++ b/test/xUnit/csharp/test_CommandLineParser.cs @@ -48,6 +48,9 @@ public static void TestDefaults() Assert.False(cpp.ShowVersion); Assert.False(cpp.SkipProfiles); Assert.False(cpp.SocketServerMode); +#if !UNIX + Assert.False(cpp.V2SocketServerMode); +#endif Assert.False(cpp.SSHServerMode); if (Platform.IsWindows) { @@ -336,6 +339,25 @@ public static void TestParameter_SocketServerMode(params string[] commandLine) Assert.Null(cpp.ErrorMessage); } +#if !UNIX + [Theory] + [InlineData("-v2socketservermode", "-token", "natoheusatoehusnatoeu", "-utctimestamp", "2023-10-01T12:00:00Z")] + [InlineData("-v2so", "-token", "asentuhasoneuthsaoe", "-utctimestamp", "2025-06-09T12:00:00Z")] + public static void TestParameter_V2SocketServerMode(params string[] commandLine) + { + var cpp = new CommandLineParameterParser(); + + cpp.Parse(commandLine); + + Assert.False(cpp.AbortStartup); + Assert.True(cpp.NoExit); + Assert.False(cpp.ShowShortHelp); + Assert.False(cpp.ShowBanner); + Assert.True(cpp.V2SocketServerMode); + Assert.Null(cpp.ErrorMessage); + } +#endif + [Theory] [InlineData("-servermode")] [InlineData("-s")] diff --git a/test/xUnit/csharp/test_RemoteHyperV.cs b/test/xUnit/csharp/test_RemoteHyperV.cs new file mode 100644 index 00000000000..f694f6894df --- /dev/null +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -0,0 +1,661 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Management.Automation.Language; +using System.Management.Automation.Subsystem; +using System.Management.Automation.Subsystem.Prediction; +using System.Threading; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Reflection; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace PSTests.Sequential +{ + public class RemoteHyperVTests + { + private static ITestOutputHelper _output; + private static TimeSpan timeout = TimeSpan.FromSeconds(15); + + public RemoteHyperVTests(ITestOutputHelper output) + { + if (!System.Management.Automation.Platform.IsWindows) + { + throw new SkipException("RemoteHyperVTests are only supported on Windows."); + } + + _output = output; + } + + // Helper method to connect with retries + private static void ConnectWithRetry(Socket client, IPAddress address, int port, ITestOutputHelper output, int maxRetries = 10) + { + int retryDelayMs = 500; + int attempt = 0; + bool connected = false; + while (attempt < maxRetries && !connected) + { + try + { + client.Connect(address, port); + connected = true; + } + catch (SocketException) + { + attempt++; + if (attempt < maxRetries) + { + output?.WriteLine($"Connect attempt {attempt} failed, retrying in {retryDelayMs}ms..."); + Thread.Sleep(retryDelayMs); + retryDelayMs *= 2; + } + else + { + output?.WriteLine($"Failed to connect after {maxRetries} attempts. This is most likely an intermittent failure due to environmental issues."); + throw; + } + } + } + } + + private static void StartHandshakeServer( + string name, + int port, + IEnumerable<(string message, + Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) + { + var expectedMessages = new Queue<(string message, byte[] bytes, Encoding encoding)>(); + foreach (var item in expectedClientSends) + { + var itemBytes = item.encoding.GetBytes(item.message); + expectedMessages.Enqueue((message: item.message, bytes: itemBytes, encoding: item.encoding)); + } + + var serverResponseBytes = new Queue(); + foreach (var item in serverResponses) + { + serverResponseBytes.Enqueue(item.encoding.GetBytes(item.message)); + } + + StartHandshakeServer(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); + } + + private static void StartHandshakeServer(string name, int port, Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, Queue serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + { + var buffer = new byte[1024]; + var listener = new TcpListener(IPAddress.Loopback, port); + listener.Start(); + try + { + using (var client = listener.AcceptSocket()) + { + if (sendFirst) + { + // Send the first message from the serverResponses queue + if (serverResponses.Count > 0) + { + var resp = serverResponses.Dequeue(); + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + + while (expectedClientSends.Count > 0) + { + client.ReceiveTimeout = 2 * 1000; // 2 seconds timeout for receiving data + cancellationToken.ThrowIfCancellationRequested(); + var expectedMessage = expectedClientSends.Dequeue(); + var expected = expectedMessage.bytes; + Array.Clear(buffer, 0, buffer.Length); + int received = client.Receive(buffer); + // Optionally validate received data matches expected + string expectedString = expectedMessage.message; + string bufferString = expectedMessage.encoding.GetString(buffer, 0, received); + string alternativeEncodedString = string.Empty; + if (expectedMessage.encoding == Encoding.Unicode) + { + alternativeEncodedString = Encoding.UTF8.GetString(buffer, 0, received); + } + else if (expectedMessage.encoding == Encoding.UTF8) + { + alternativeEncodedString = Encoding.Unicode.GetString(buffer, 0, received); + } + + if (received != expected.Length) + { + string errorMessage = $"Mock {name} - Expected {expected.Length} bytes, but received {received} bytes: `{bufferString}`(alt encoding: `{alternativeEncodedString}`); expected: {expectedString}"; + _output.WriteLine(errorMessage); + throw new Exception(errorMessage); + } + if (!string.Equals(bufferString, expectedString, StringComparison.OrdinalIgnoreCase)) + { + string errorMessage = $"Mock {name} - Expected `{expectedString}`; length {expected.Length}, but received; length {received}; `{bufferString}`(alt encoding: `{alternativeEncodedString}`) instead."; + _output.WriteLine(errorMessage); + throw new Exception(errorMessage); + } + _output.WriteLine($"Mock {name} - received expected message: " + expectedString); + if (serverResponses.Count > 0) + { + var resp = serverResponses.Dequeue(); + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + + if (verifyConnectionClosed) + { + _output.WriteLine($"Mock {name} - verifying client connection is closed."); + // Wait for the client to close the connection synchronously (no timeout) + try + { + while (true) + { + int bytesRead = client.Receive(buffer, SocketFlags.None); + if (bytesRead == 0) + { + break; + } + + // If we receive any data, log and throw (assume UTF8 encoding) + string unexpectedData = Encoding.UTF8.GetString(buffer, 0, bytesRead); + _output.WriteLine($"Mock {name} - received unexpected data after handshake: {unexpectedData}"); + throw new Exception($"Mock {name} - received unexpected data after handshake: {unexpectedData}"); + } + _output.WriteLine($"Mock {name} - client closed the connection."); + } + catch (SocketException ex) + { + _output.WriteLine($"Mock {name} - socket exception while waiting for client close: {ex.Message} {ex.GetType().FullName}"); + } + catch (ObjectDisposedException) + { + // Socket already closed + } + } + } + + _output.WriteLine($"Mock {name} - on port {port} completed successfully."); + } + finally + { + listener.Stop(); + } + } + + // Helper function to create a random 4-character ASCII response + private static string CreateRandomAsciiResponse() + { + var rand = new Random(); + // Randomly return either "PASS" or "FAIL" + return rand.Next(0, 2) == 0 ? "PASS" : "FAIL"; + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) CreateHandshakeTestData(NetworkCredential cred) + { + var expectedClientSends = new List<(string message, Encoding encoding)> + { + (message: cred.Domain, encoding: Encoding.Unicode), + (message: cred.UserName, encoding: Encoding.Unicode), + (message: "NONEMPTYPW", encoding: Encoding.ASCII), + (message: cred.Password, encoding: Encoding.Unicode) + }; + + var serverResponses = new List<(string message, Encoding encoding)> + { + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII), // Response to domain + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII), // Response to username + (message: CreateRandomAsciiResponse(), encoding: Encoding.ASCII) // Response to non-empty password + }; + + return (expectedClientSends, serverResponses); + } + + private static List<(string message, Encoding encoding)> CreateVersionNegotiationClientSends() + { + return new List<(string message, Encoding encoding)> + { + (message: "VERSION", encoding: Encoding.UTF8), + (message: "VERSION_2", encoding: Encoding.UTF8), + }; + } + + private static List<(string, Encoding)> CreateV2Sends(NetworkCredential cred, string configurationName) + { + var sends = CreateVersionNegotiationClientSends(); + var password = cred.Password; + var emptyPassword = string.IsNullOrEmpty(password); + + sends.AddRange(new List<(string message, Encoding encoding)> + { + (message: cred.Domain, encoding: Encoding.Unicode), + (message: cred.UserName, encoding: Encoding.Unicode) + }); + + if (!emptyPassword) + { + sends.AddRange(new List<(string message, Encoding encoding)> + { + (message: "NONEMPTYPW", encoding: Encoding.UTF8), + (message: cred.Password, encoding: Encoding.Unicode) + }); + } + else + { + sends.Add((message: "EMPTYPW", encoding: Encoding.UTF8)); // Empty password and we don't expect a response + } + + if (!string.IsNullOrEmpty(configurationName)) + { + sends.Add((message: "NONEMPTYCF", encoding: Encoding.UTF8)); + sends.Add((message: configurationName, encoding: Encoding.Unicode)); // Configuration string and we don't expect a response + } + else + { + sends.Add((message: "EMPTYCF", encoding: Encoding.UTF8)); // Configuration string and we don't expect a response + } + + sends.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to TOKEN + + return sends; + } + + private static List<(string, Encoding)> CreateV2Responses(string version = "VERSION_2", bool emptyConfig = false, string token = "FakeToken0+/=", bool emptyPassword = false) + { + var responses = new List<(string message, Encoding encoding)> + { + (message: version, encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to domain + (message: "PASS", encoding: Encoding.ASCII), // Response to username + }; + + if (!emptyPassword) + { + responses.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to non-empty password + } + + responses.Add((message: "CONF", encoding: Encoding.ASCII)); // Response to configuration + + if (!emptyConfig) + { + responses.Add((message: "PASS", encoding: Encoding.ASCII)); // Response to non-empty configuration + } + responses.Add((message: "TOKEN " + token, encoding: Encoding.ASCII)); // Response to with a token than uses each class of character in base 64 encoding + + return responses; + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) + CreateHandshakeTestDataV2(NetworkCredential cred, string version, string configurationName, string token) + { + bool emptyConfig = string.IsNullOrEmpty(configurationName); + bool emptyPassword = string.IsNullOrEmpty(cred.Password); + return (CreateV2Sends(cred, configurationName), CreateV2Responses(version, emptyConfig, token, emptyPassword)); + } + + // Helper method to create test data + private static (List<(string, Encoding)> expectedClientSends, List<(string, Encoding)> serverResponses) CreateHandshakeTestDataForFallback(NetworkCredential cred) + { + var expectedClientSends = new List<(string message, Encoding encoding)> + { + (message: "VERSION", encoding: Encoding.UTF8), + (message: @"?", encoding: Encoding.Unicode), + (message: "EMPTYPW", encoding: Encoding.UTF8), // Response to domain + (message: "FAIL", encoding: Encoding.UTF8), // Response to domain + }; + + List<(string message, Encoding encoding)> serverResponses = new List<(string message, Encoding encoding)> + { + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION but v1 server expects domain so it says "PASS" + (message: "PASS", encoding: Encoding.ASCII), // Response to username + (message: "FAIL", encoding: Encoding.ASCII) // Response to EMPTYPW + }; + + return (expectedClientSends, serverResponses); + } + + // Helper to create a password with at least one non-ASCII Unicode character + public static string CreateRandomUnicodePassword(string prefix) + { + var rand = new Random(); + var asciiPart = new char[6 + prefix.Length]; + // Copy prefix into asciiPart + Array.Copy(prefix.ToCharArray(), 0, asciiPart, 0, prefix.Length); + for (int i = prefix.Length; i < asciiPart.Length; i++) + { + asciiPart[i] = (char)rand.Next(33, 127); // ASCII printable + } + // Add a random Unicode character outside ASCII range (e.g., U+0100 to U+017F) + char unicodeChar = (char)rand.Next(0x0100, 0x017F); + // Insert the unicode character at a random position + int insertPos = rand.Next(0, asciiPart.Length + 1); + var passwordChars = new List(asciiPart); + passwordChars.Insert(insertPos, unicodeChar); + return new string(passwordChars.ToArray()); + } + + public static NetworkCredential CreateTestCredential() + { + return new NetworkCredential(CreateRandomUnicodePassword("username"), CreateRandomUnicodePassword("password"), CreateRandomUnicodePassword("domain")); + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Pass() + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + string configurationName = CreateRandomUnicodePassword("config"); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + expectedClientSends.Add(("PASS", Encoding.ASCII)); + serverResponses.Add(("PASS", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, true); + var result = exchangeResult.success; + _output.WriteLine($"Exchange result: {result}, Token: {exchangeResult.authenticationToken}"); + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.True(result, $"Expected Exchange to pass"); + } + + await serverTask; + } + + [SkippableTheory] + [InlineData("VERSION_2", "configurationname1", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/==")] // a fake base64 token about 512 bits long (double the size when this was spec'ed) + [InlineData("VERSION_10", null, "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/=")] // a fake base64 token about 256 bits Long (the size when this was spec'ed) + public async Task PerformCredentialAndConfigurationHandshake_V2_Pass(string versionResponse, string configurationName, string token) + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestDataV2(cred, versionResponse, configurationName, token); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: true, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + client.Connect(IPAddress.Loopback, port); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, false); + var result = exchangeResult.success; + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.True(result, $"Expected Exchange to pass for version response '{versionResponse}'"); + Assert.Equal(token, exchangeResult.authenticationToken); + } + + await serverTask; + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Fallback() + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + string configurationName = CreateRandomUnicodePassword("config"); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestDataForFallback(cred); + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + bool isFallback = false; + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + _output.WriteLine("Starting handshake with V2 protocol."); + client.Connect(IPAddress.Loopback, port); + var exchangeResult = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, configurationName, client, false); + isFallback = !exchangeResult.success; + + System.Threading.Thread.Sleep(100); // Allow time for server to process + _output.WriteLine("Handshake indicated fallback to V1."); + Assert.True(isFallback, "Expected fallback to V1."); + } + _output.WriteLine("Handshake completed successfully with fallback to V1."); + + await serverTask; + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V2_InvalidResponse() + { + // Arrange + int port = 51000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + //expectedClientSends.Add("FAI1"); + serverResponses.Add(("FAI1", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + + //cts.Token.Register(() => throw new OperationCanceledException("Test timed out.")); + + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + _output.WriteLine("connecting on port " + port); + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + + var ex = Record.Exception(() => System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, "config", client, true)); + + try + { + await serverTask; + } + catch (AggregateException exAgg) + { + Assert.Null(exAgg.Flatten().InnerExceptions[1].Message); + } + cts.Token.ThrowIfCancellationRequested(); + + Assert.NotNull(ex); + Assert.NotNull(ex.Message); + Assert.Contains("Hyper-V Broker sent an invalid Credential response", ex.Message); + } + } + + [SkippableFact] + public async Task PerformCredentialAndConfigurationHandshake_V1_Fail() + { + // Arrange + int port = 51000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var (expectedClientSends, serverResponses) = CreateHandshakeTestData(cred); + expectedClientSends.Add(("FAIL", Encoding.ASCII)); + serverResponses.Add(("FAIL", Encoding.ASCII)); + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)); + + // This scenario does not close the connection in a timely manner, so we set verifyConnectionClosed to false + var serverTask = Task.Run(() => StartHandshakeServer("Broker", port, expectedClientSends, serverResponses, verifyConnectionClosed: false, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + client.Connect(IPAddress.Loopback, port); + + var ex = Record.Exception(() => System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.ExchangeCredentialsAndConfiguration(cred, "config", client, true)); + + try + { + await serverTask; + } + catch (AggregateException exAgg) + { + Assert.Null(exAgg.Flatten().InnerExceptions[1].Message); + } + + cts.Token.ThrowIfCancellationRequested(); + + Assert.NotNull(ex); + Assert.NotNull(ex.Message); + Assert.Contains("The credential is invalid.", ex.Message); + } + } + + [SkippableTheory] + [InlineData("VERSION_2", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/==")] // a fake base64 token about 512 bits long (double the size when this was spec'ed) + [InlineData("VERSION_10", "FakeTokenaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAA0+/=")] // a fake base64 token about 256 bits Long (the size when this was spec'ed) + public async Task PerformTransportVersionAndTokenExchange_Pass(string version, string token) + { + // Arrange + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + var cred = CreateTestCredential(); + + var expectedClientSends = CreateVersionNegotiationClientSends(); + expectedClientSends.Add((message: "TOKEN " + token, encoding: Encoding.ASCII)); + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: version, encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Server", port, expectedClientSends, serverResponses, verifyConnectionClosed: true, cts.Token), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.PerformTransportVersionAndTokenExchange(client, token); + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + await serverTask; + } + + [SkippableTheory] + [InlineData(1, true)] + [InlineData(2, true)] + [InlineData(0, false)] + [InlineData(null, false)] + [System.Runtime.Versioning.SupportedOSPlatform("windows")] + public void IsRequirePsDirectAuthenticationEnabled(int? regValue, bool expected) + { + const string testKeyPath = @"SOFTWARE\Microsoft\TestRequirePsDirectAuthentication"; + const string valueName = "RequirePsDirectAuthentication"; + if (!System.Management.Automation.Platform.IsWindows) + { + throw new SkipException("RemoteHyperVTests are only supported on Windows."); + } + + // Clean up any previous test key + var regHive = Microsoft.Win32.RegistryHive.CurrentUser; + var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(regHive, Microsoft.Win32.RegistryView.Registry64); + baseKey.DeleteSubKeyTree(testKeyPath, false); + + bool? result = null; + + // Create the test key + using (var key = baseKey.CreateSubKey(testKeyPath)) + { + if (regValue.HasValue) + { + key.SetValue(valueName, regValue.Value, Microsoft.Win32.RegistryValueKind.DWord); + } + else + { + // Ensure the value does not exist + key.DeleteValue(valueName, false); + } + + result = System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient.IsRequirePsDirectAuthenticationEnabled(testKeyPath, regHive); + } + + Assert.True(result.HasValue, "IsRequirePsDirectAuthenticationEnabled should return a value."); + Assert.True(expected == result.Value, + $"Expected IsRequirePsDirectAuthenticationEnabled to return {expected} when registry value is {(regValue.HasValue ? regValue.ToString() : "not set")}."); + + return; + } + + [SkippableTheory] + [InlineData("testToken", "testToken")] + [InlineData("testToken\0", "testToken")] + public async Task ValidatePassesWhenTokensMatch(string token, string expectedToken) + { + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding)>{ + (message: "VERSION", encoding: Encoding.ASCII), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken); + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + await serverTask; + } + + [SkippableTheory] + [InlineData("abc", "xyz")] + [InlineData("abc", "abcdef")] + [InlineData("abcdef", "abc")] + [InlineData("abc\0def", "abc")] + public async Task ValidateFailsWhenTokensMismatch(string token, string expectedToken) + { + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding)>{ + (message: "VERSION", encoding: Encoding.ASCII), // Initial request + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "FAIL", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + var exception = Assert.Throws( + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken)); + System.Threading.Thread.Sleep(100); // Allow time for server to process + Assert.Contains("The credential is invalid.", exception.Message); + } + + await serverTask; + } + } +} From 00ad203c36e1f61a63c896a6cea5896a39036518 Mon Sep 17 00:00:00 2001 From: Hakan Sener Date: Tue, 16 Sep 2025 17:30:15 +0200 Subject: [PATCH 054/378] Update metadata for Stable to v7.5.3 and LTS to v7.4.12 (#26054) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- tools/metadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index bbe6977d33e..377b6ead763 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,9 +1,9 @@ { - "StableReleaseTag": "v7.5.2", + "StableReleaseTag": "v7.5.3", "PreviewReleaseTag": "v7.6.0-preview.4", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.5.2", - "LTSReleaseTag" : ["v7.4.11"], + "ReleaseTag": "v7.5.3", + "LTSReleaseTag" : ["v7.4.12"], "NextReleaseTag": "v7.6.0-preview.5", "LTSRelease": { "Latest": false, "Package": false }, "StableRelease": { "Latest": false, "Package": false } From 2376e284827c85e0ed55a7523a833e6c3c6aa8f0 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 22 Sep 2025 10:56:19 -0700 Subject: [PATCH 055/378] Ensure that socket timeouts are set only during the token validation (#26066) The main goal is to ensure that socket timeouts are set only during the token validation phase and are properly reset afterward, improving reliability and preventing unintended blocking or premature timeouts in subsequent operations. --- .../common/RemoteSessionHyperVSocket.cs | 57 +++--- test/xUnit/csharp/test_RemoteHyperV.cs | 186 ++++++++++++++++-- 2 files changed, 197 insertions(+), 46 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index 02cf5b29697..cd18dc511b1 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -258,30 +258,7 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode, string token, DateTime listenSocket.Listen(1); HyperVSocket = listenSocket.Accept(); - TimeSpan timeout = TimeSpan.FromMinutes(MAX_TOKEN_LIFE_MINUTES); - DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); - DateTimeOffset now = DateTimeOffset.UtcNow; - - // Calculate remaining time and create cancellation token - TimeSpan remainingTime = timeoutExpiry - now; - - // Check if the token has already expired - if (remainingTime <= TimeSpan.Zero) - { - throw new PSDirectException( - PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); - } - - // Set socket timeout for receive operations to prevent indefinite blocking - int timeoutMs = (int)remainingTime.TotalMilliseconds; - HyperVSocket.ReceiveTimeout = timeoutMs; - HyperVSocket.SendTimeout = timeoutMs; - - // Create a cancellation token that will be cancelled when the timeout expires - using var cancellationTokenSource = new CancellationTokenSource(remainingTime); - CancellationToken cancellationToken = cancellationTokenSource.Token; - - ValidateToken(HyperVSocket, token, cancellationToken); + ValidateToken(HyperVSocket, token, tokenCreationTime, MAX_TOKEN_LIFE_MINUTES * 60); Stream = new NetworkStream(HyperVSocket, true); @@ -389,9 +366,33 @@ public void Dispose() /// /// The connected HyperVSocket. /// The expected token string. - /// Cancellation token for timeout handling. - internal static void ValidateToken(Socket socket, string token, CancellationToken cancellationToken = default) + /// The creation time of the token. + /// The maximum lifetime of the token in seconds. + internal static void ValidateToken(Socket socket, string token, DateTimeOffset tokenCreationTime, int maxTokenLifeSeconds) { + TimeSpan timeout = TimeSpan.FromSeconds(maxTokenLifeSeconds); + DateTimeOffset timeoutExpiry = tokenCreationTime.Add(timeout); + DateTimeOffset now = DateTimeOffset.UtcNow; + + // Calculate remaining time and create cancellation token + TimeSpan remainingTime = timeoutExpiry - now; + + // Check if the token has already expired + if (remainingTime <= TimeSpan.Zero) + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential, "Token has expired")); + } + + // Create a cancellation token that will be cancelled when the timeout expires + using var cancellationTokenSource = new CancellationTokenSource(remainingTime); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + // Set socket timeout for receive operations to prevent indefinite blocking + int timeoutMs = (int)remainingTime.TotalMilliseconds; + socket.ReceiveTimeout = timeoutMs; + socket.SendTimeout = timeoutMs; + // Check for cancellation before starting validation cancellationToken.ThrowIfCancellationRequested(); @@ -430,6 +431,7 @@ internal static void ValidateToken(Socket socket, string token, CancellationToke // So we expect a response of length 6 + 100 = 106 characters. responseString = RemoteSessionHyperVSocketClient.ReceiveResponse(socket, 110); + // Final check if we got the token before the timeout cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith("TOKEN ", StringComparison.Ordinal)) @@ -454,6 +456,9 @@ internal static void ValidateToken(Socket socket, string token, CancellationToke // Acknowledge the token is valid with "PASS". socket.Send("PASS"u8); + + socket.ReceiveTimeout = 0; // Disable the timeout after successful validation + socket.SendTimeout = 0; } } diff --git a/test/xUnit/csharp/test_RemoteHyperV.cs b/test/xUnit/csharp/test_RemoteHyperV.cs index f694f6894df..27f7fb17375 100644 --- a/test/xUnit/csharp/test_RemoteHyperV.cs +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -63,15 +63,51 @@ private static void ConnectWithRetry(Socket client, IPAddress address, int port, } } + private static void SendResponse(string name, Socket client, Queue<(byte[] bytes, int delayMs)> serverResponses) + { + if (serverResponses.Count > 0) + { + _output.WriteLine($"Mock {name} ----------------------------------------------------"); + var respTuple = serverResponses.Dequeue(); + var resp = respTuple.bytes; + + if (respTuple.delayMs > 0) + { + _output.WriteLine($"Mock {name} - delaying response by {respTuple.delayMs} ms"); + Thread.Sleep(respTuple.delayMs); + } + if (resp.Length > 0) { + client.Send(resp, resp.Length, SocketFlags.None); + _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); + } + } + } + private static void StartHandshakeServer( string name, int port, - IEnumerable<(string message, - Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding)> expectedClientSends, IEnumerable<(string message, Encoding encoding)> serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + { + IEnumerable<(string message, Encoding encoding, int delayMs)> serverResponsesWithDelay = new List<(string message, Encoding encoding, int delayMs)>(); + foreach (var item in serverResponses) + { + ((List<(string message, Encoding encoding, int delayMs)>)serverResponsesWithDelay).Add((item.message, item.encoding, 1)); + } + StartHandshakeServer(name, port, expectedClientSends, serverResponsesWithDelay, verifyConnectionClosed, cancellationToken, sendFirst); + } + + private static void StartHandshakeServer( + string name, + int port, + IEnumerable<(string message, Encoding encoding)> expectedClientSends, + IEnumerable<(string message, Encoding encoding, int delayMs)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) { var expectedMessages = new Queue<(string message, byte[] bytes, Encoding encoding)>(); foreach (var item in expectedClientSends) @@ -80,17 +116,27 @@ private static void StartHandshakeServer( expectedMessages.Enqueue((message: item.message, bytes: itemBytes, encoding: item.encoding)); } - var serverResponseBytes = new Queue(); + var serverResponseBytes = new Queue<(byte[] bytes, int delayMs)>(); foreach (var item in serverResponses) { - serverResponseBytes.Enqueue(item.encoding.GetBytes(item.message)); + (byte[] bytes, int delayMs) queueItem = (item.encoding.GetBytes(item.message), item.delayMs); + serverResponseBytes.Enqueue(queueItem); } - StartHandshakeServer(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); + _output.WriteLine($"Mock {name} - starting listener on port {port} with {expectedMessages.Count} expected messages and {serverResponseBytes.Count} responses."); + StartHandshakeServerImplementation(name, port, expectedMessages, serverResponseBytes, verifyConnectionClosed, cancellationToken, sendFirst); } - private static void StartHandshakeServer(string name, int port, Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, Queue serverResponses, bool verifyConnectionClosed, CancellationToken cancellationToken, bool sendFirst = false) + private static void StartHandshakeServerImplementation( + string name, + int port, + Queue<(string message, byte[] bytes, Encoding encoding)> expectedClientSends, + Queue<(byte[] bytes, int delayMs)> serverResponses, + bool verifyConnectionClosed, + CancellationToken cancellationToken, + bool sendFirst = false) { + DateTime startTime = DateTime.UtcNow; var buffer = new byte[1024]; var listener = new TcpListener(IPAddress.Loopback, port); listener.Start(); @@ -101,19 +147,16 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me if (sendFirst) { // Send the first message from the serverResponses queue - if (serverResponses.Count > 0) - { - var resp = serverResponses.Dequeue(); - client.Send(resp, resp.Length, SocketFlags.None); - _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); - } + SendResponse(name, client, serverResponses); } while (expectedClientSends.Count > 0) { + _output.WriteLine($"Mock {name} - time elapsed: {(DateTime.UtcNow - startTime).TotalMilliseconds} milliseconds"); client.ReceiveTimeout = 2 * 1000; // 2 seconds timeout for receiving data cancellationToken.ThrowIfCancellationRequested(); var expectedMessage = expectedClientSends.Dequeue(); + _output.WriteLine($"Mock {name} - remaining expected messages: {expectedClientSends.Count}"); var expected = expectedMessage.bytes; Array.Clear(buffer, 0, buffer.Length); int received = client.Receive(buffer); @@ -143,12 +186,7 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me throw new Exception(errorMessage); } _output.WriteLine($"Mock {name} - received expected message: " + expectedString); - if (serverResponses.Count > 0) - { - var resp = serverResponses.Dequeue(); - client.Send(resp, resp.Length, SocketFlags.None); - _output.WriteLine($"Mock {name} - sent response: " + Encoding.ASCII.GetString(resp)); - } + SendResponse(name, client, serverResponses); } if (verifyConnectionClosed) @@ -178,6 +216,7 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me } catch (ObjectDisposedException) { + _output.WriteLine($"Mock {name} - socket already closed."); // Socket already closed } } @@ -185,8 +224,16 @@ private static void StartHandshakeServer(string name, int port, Queue<(string me _output.WriteLine($"Mock {name} - on port {port} completed successfully."); } + catch (Exception ex) + { + _output.WriteLine($"Mock {name} - Exception: {ex.Message} {ex.GetType().FullName}"); + _output.WriteLine(ex.StackTrace); + throw; + } finally { + _output.WriteLine($"Mock {name} - remaining expected messages: {expectedClientSends.Count}"); + _output.WriteLine($"Mock {name} - stopping listener on port {port}."); listener.Stop(); } } @@ -615,13 +662,111 @@ public async Task ValidatePassesWhenTokensMatch(string token, string expectedTok using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { ConnectWithRetry(client, IPAddress.Loopback, port, _output); - System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 1); System.Threading.Thread.Sleep(100); // Allow time for server to process } await serverTask; } + [SkippableTheory] + [InlineData(5500, "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.", "SocketException")] // test the socket timeout + [InlineData(3200, "canceled", "System.OperationCanceledException")] // test the cancellation token + [InlineData(10, "", "")] + public async Task ValidateTokenTimeoutFails(int timeoutMs, string expectedMessage, string expectedExceptionType = "SocketException") + { + string token = "testToken"; + string expectedToken = token; + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding, int delayMs)>{ + (message: "VERSION", encoding: Encoding.ASCII, delayMs: timeoutMs), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII, delayMs: timeoutMs), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII, delayMs: 1) + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII) // Response to token + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: true, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + if (expectedMessage.Length > 0) + { + var exception = Record.Exception( + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5)); // set the timeout to 5 seconds or 5000 ms + Assert.NotNull(exception); + string exceptionType = exception.GetType().FullName; + _output.WriteLine($"Caught exception of type {exceptionType} with message: {exception.Message}"); + Assert.Contains(expectedExceptionType, exceptionType, StringComparison.OrdinalIgnoreCase); + Assert.Contains(expectedMessage, exception.Message, StringComparison.OrdinalIgnoreCase); + } + else + { + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5); + } + System.Threading.Thread.Sleep(100); // Allow time for server to process + } + + if (expectedMessage.Length == 0) + { + await serverTask; + } + } + + [SkippableFact] + public async Task ValidateTokenTimeoutDoesAffectSession() + { + string token = "testToken"; + string expectedToken = token; + int port = 50000 + (int)(DateTime.Now.Ticks % 10000); + + var expectedClientSends = new List<(string message, Encoding encoding, int delayMs)>{ + (message: "VERSION", encoding: Encoding.ASCII, delayMs: 1), // Response to VERSION + (message: "VERSION_2", encoding: Encoding.ASCII, delayMs: 1), // Response to VERSION_2 + (message: $"TOKEN {token}", encoding: Encoding.ASCII, delayMs: 1), + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 99), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 100), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 101), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 102), // Send some data after the handshake + (message: string.Empty, encoding: Encoding.ASCII, delayMs: 103) // Send some data after the handshake + }; + + var serverResponses = new List<(string message, Encoding encoding)>{ + (message: "VERSION_2", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to VERSION_2 + (message: "PASS", encoding: Encoding.ASCII), // Response to token + (message: "PSRP-Message0", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message1", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message2", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message3", encoding: Encoding.ASCII), // Indicate server is ready to receive data + (message: "PSRP-Message4", encoding: Encoding.ASCII) // + + }; + + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2)); + var serverTask = Task.Run(() => StartHandshakeServer("Client", port, serverResponses, expectedClientSends, verifyConnectionClosed: false, cts.Token, sendFirst: true), cts.Token); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + ConnectWithRetry(client, IPAddress.Loopback, port, _output); + System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, DateTimeOffset.UtcNow, 5); + for (int i = 0; i < 5; i++) + { + System.Threading.Thread.Sleep(1500); + client.Send(Encoding.ASCII.GetBytes($"PSRP-Message{i}")); // Send some data after the handshake + } + } + + await serverTask; + } + [SkippableTheory] [InlineData("abc", "xyz")] [InlineData("abc", "abcdef")] @@ -649,8 +794,9 @@ public async Task ValidateFailsWhenTokensMismatch(string token, string expectedT using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { ConnectWithRetry(client, IPAddress.Loopback, port, _output); + DateTimeOffset tokenCreationTime = DateTimeOffset.UtcNow; // Token created 10 minutes ago var exception = Assert.Throws( - () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken)); + () => System.Management.Automation.Remoting.RemoteSessionHyperVSocketServer.ValidateToken(client, expectedToken, tokenCreationTime, 5)); System.Threading.Thread.Sleep(100); // Allow time for server to process Assert.Contains("The credential is invalid.", exception.Message); } From bd3e3c991caf29a362fcc955a6cb0eace7f5589a Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:58:43 -0700 Subject: [PATCH 056/378] Update `Microsoft.PowerShell.PSResourceGet` to 1.2.0-preview3 (#26056) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index b90e537ca21..e4fce43b396 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 2d8040f91c4e156815b5c7b325207bf0cc5d593c Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 22 Sep 2025 14:04:22 -0700 Subject: [PATCH 057/378] Ensure that the workflows are triggered on `.globalconfig` and other files at the root of the repo (#26034) --- .github/workflows/linux-ci.yml | 2 ++ .github/workflows/macos-ci.yml | 2 ++ .github/workflows/windows-ci.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index d4d2c14f8ee..30f5acd5619 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -12,6 +12,8 @@ on: - github-mirror paths: - "**" + - "*" + - ".globalconfig" - "!.github/ISSUE_TEMPLATE/**" - "!.dependabot/config.yml" - "!.pipelines/**" diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index dc1c38a162d..0007d550f06 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -10,6 +10,8 @@ on: - github-mirror paths: - "**" + - "*" + - ".globalconfig" - "!.github/ISSUE_TEMPLATE/**" - "!.dependabot/config.yml" - "!.pipelines/**" diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 18b426aa191..63e6c5ab7a3 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -8,6 +8,8 @@ on: - github-mirror paths: - "**" + - "*" + - ".globalconfig" - "!.vsts-ci/misc-analysis.yml" - "!.github/ISSUE_TEMPLATE/**" - "!.dependabot/config.yml" From f08e75899c0e2676e1493bc2821701db2dddd647 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:52:58 -0700 Subject: [PATCH 058/378] Update outdated package references (#26069) --- .../Microsoft.PowerShell.Commands.Utility.csproj | 2 +- .../System.Management.Automation.csproj | 2 +- .../BenchmarkDotNet.Extensions.csproj | 4 ++-- test/perf/dotnet-tools/Reporting/Reporting.csproj | 2 +- .../dotnet-tools/ResultsComparer/ResultsComparer.csproj | 4 ++-- tools/cgmanifest.json | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 2fd3f0075d6..a35f4258e56 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index a235b37f71e..033c39034ac 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -28,7 +28,7 @@ - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index c2310231c36..642210dc83d 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/Reporting/Reporting.csproj b/test/perf/dotnet-tools/Reporting/Reporting.csproj index 72a831b9406..b11b5e36ec4 100644 --- a/test/perf/dotnet-tools/Reporting/Reporting.csproj +++ b/test/perf/dotnet-tools/Reporting/Reporting.csproj @@ -6,7 +6,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index d9d36f3b3c5..47d4352df9c 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index acff38d562a..11c7447ff7d 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -66,7 +65,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.41.3" + "Version": "0.42.0" } }, "DevelopmentDependency": false @@ -196,7 +195,7 @@ "Type": "nuget", "Nuget": { "Name": "Newtonsoft.Json", - "Version": "13.0.3" + "Version": "13.0.4" } }, "DevelopmentDependency": false @@ -781,5 +780,6 @@ }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From 5e62bb7fa91a1b8e6ac4fdf4fd89d5490b6ee530 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 23 Sep 2025 01:22:09 +0100 Subject: [PATCH 059/378] Remove unused `FileStreamBackReader.NativeMethods` type (#26062) --- .../namespaces/FileSystemContentStream.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/System.Management.Automation/namespaces/FileSystemContentStream.cs b/src/System.Management.Automation/namespaces/FileSystemContentStream.cs index d95b31ed0fd..d0f8f08deab 100644 --- a/src/System.Management.Automation/namespaces/FileSystemContentStream.cs +++ b/src/System.Management.Automation/namespaces/FileSystemContentStream.cs @@ -1475,26 +1475,6 @@ _currentEncoding is UTF32Encoding || return _byteCount; } - - private static class NativeMethods - { - // Default values - private const int MAX_DEFAULTCHAR = 2; - private const int MAX_LEADBYTES = 12; - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct CPINFO - { - [MarshalAs(UnmanagedType.U4)] - internal int MaxCharSize; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEFAULTCHAR)] - public byte[] DefaultChar; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LEADBYTES)] - public byte[] LeadBytes; - } - } } /// From 7cf2740bdc0c373389d63eb1ba39f46c0c3a31ba Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 23 Sep 2025 01:22:25 +0100 Subject: [PATCH 060/378] Remove some unused `ConsoleControl` structs (#26063) --- .../host/msh/ConsoleControl.cs | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs index 8857c64fa50..7bda4bc5688 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs @@ -211,41 +211,6 @@ internal struct FONTSIGNATURE internal DWORD fsCsb1; } - [StructLayout(LayoutKind.Sequential)] - internal struct CHARSETINFO - { - // From public\sdk\inc\wingdi.h - internal uint ciCharset; // Character set value. - internal uint ciACP; // ANSI code-page identifier. - internal FONTSIGNATURE fs; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TEXTMETRIC - { - // From public\sdk\inc\wingdi.h - public int tmHeight; - public int tmAscent; - public int tmDescent; - public int tmInternalLeading; - public int tmExternalLeading; - public int tmAveCharWidth; - public int tmMaxCharWidth; - public int tmWeight; - public int tmOverhang; - public int tmDigitizedAspectX; - public int tmDigitizedAspectY; - public char tmFirstChar; - public char tmLastChar; - public char tmDefaultChar; - public char tmBreakChar; - public byte tmItalic; - public byte tmUnderlined; - public byte tmStruckOut; - public byte tmPitchAndFamily; - public byte tmCharSet; - } - #region SentInput Data Structures [StructLayout(LayoutKind.Sequential)] From 506869c157fbd481a3f6f9f9e50d9d0efec1fede Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 22 Sep 2025 21:19:39 -0700 Subject: [PATCH 061/378] Fix `-Debug` to not trigger the `ShouldProcess` prompt (#26081) --- .../engine/MshCommandRuntime.cs | 12 +++--- .../Write-Debug.Tests.ps1 | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/System.Management.Automation/engine/MshCommandRuntime.cs b/src/System.Management.Automation/engine/MshCommandRuntime.cs index 883c800deab..2e5cdb455b7 100644 --- a/src/System.Management.Automation/engine/MshCommandRuntime.cs +++ b/src/System.Management.Automation/engine/MshCommandRuntime.cs @@ -2992,21 +2992,19 @@ internal ConfirmImpact ConfirmPreference { // WhatIf not relevant, it never gets this far in that case if (Confirm) - return ConfirmImpact.Low; - if (Debug) { - if (IsConfirmFlagSet) // -Debug -Confirm:$false - return ConfirmImpact.None; return ConfirmImpact.Low; } - if (IsConfirmFlagSet) // -Confirm:$false + if (IsConfirmFlagSet) + { + // -Confirm:$false return ConfirmImpact.None; + } if (!_isConfirmPreferenceCached) { - bool defaultUsed = false; - _confirmPreference = Context.GetEnumPreference(SpecialVariables.ConfirmPreferenceVarPath, _confirmPreference, out defaultUsed); + _confirmPreference = Context.GetEnumPreference(SpecialVariables.ConfirmPreferenceVarPath, _confirmPreference, out _); _isConfirmPreferenceCached = true; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Debug.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Debug.Tests.ps1 index f93027cc578..951400349c3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Debug.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Debug.Tests.ps1 @@ -34,4 +34,44 @@ Describe "Write-Debug tests" -Tags "CI" { $out = $p.StandardError.ReadToEnd() $out | Should -BeNullOrEmpty } + + It "'-Debug' should not trigger 'ShouldProcess'" { + $pwsh = [PowerShell]::Create() + $pwsh.AddScript(@' +function Test-DebugWithConfirm +{ + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] + Param () + + PROCESS + { + Write-Debug -Message "Debug_Message1" + If ($PSCmdlet.ShouldProcess('Doing the thing.','Proceed?','Ready to do the thing.')) + { + Write-Output 'success' + } + Write-Debug -Message "Debug_Message2" + } + + END {} +} +'@) + $pwsh.Invoke() + $pwsh.Commands.Clear() + $pwsh.Streams.ClearStreams() + + try { + $result = $pwsh.AddScript("Test-DebugWithConfirm -Debug").Invoke() + $result.Count | Should -BeExactly 1 + $result[0] | Should -BeExactly 'success' + + $pwsh.Streams.Error.Count | Should -BeExactly 0 + $pwsh.Streams.Debug.Count | Should -BeExactly 2 + $pwsh.Streams.Debug[0] | Should -BeExactly 'Debug_Message1' + $pwsh.Streams.Debug[1] | Should -BeExactly 'Debug_Message2' + } + finally { + $pwsh.Dispose() + } + } } From 551a0fe6420cb045a5e8b66902c248c300cefba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Kafka?= <6414091+MatejKafka@users.noreply.github.com> Date: Tue, 23 Sep 2025 19:29:11 +0200 Subject: [PATCH 062/378] Fix `ConvertFrom-Json` to ignore comments inside array literals (#14553) (#26050) Co-authored-by: Dongbo Wang --- .../commands/utility/WebCmdlet/JsonObject.cs | 96 +++++++++---------- .../ConvertFrom-Json.Tests.ps1 | 32 +++++++ 2 files changed, 78 insertions(+), 50 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs index 33465683153..b626fd71db8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs @@ -10,7 +10,6 @@ using System.Management.Automation.Language; using System.Numerics; using System.Reflection; -using System.Text.RegularExpressions; using System.Threading; using Newtonsoft.Json; @@ -289,11 +288,11 @@ private static PSObject PopulateFromJDictionary(JObject entries, DuplicateMember return null; } - // Array switch (entry.Value) { case JArray list: { + // Array var listResult = PopulateFromJArray(list, out error); if (error != null) { @@ -333,45 +332,44 @@ private static ICollection PopulateFromJArray(JArray list, out ErrorReco { error = null; var result = new object[list.Count]; + var i = 0; - for (var index = 0; index < list.Count; index++) + foreach (var element in list) { - var element = list[index]; switch (element) { case JArray subList: + // Array + result[i++] = PopulateFromJArray(subList, out error); + if (error != null) { - // Array - var listResult = PopulateFromJArray(subList, out error); - if (error != null) - { - return null; - } - - result[index] = listResult; - break; + return null; } + + break; + case JObject dic: + // Dictionary + result[i++] = PopulateFromJDictionary(dic, new DuplicateMemberHashSet(dic.Count), out error); + if (error != null) { - // Dictionary - var dicResult = PopulateFromJDictionary(dic, new DuplicateMemberHashSet(dic.Count), out error); - if (error != null) - { - return null; - } - - result[index] = dicResult; - break; + return null; } + + break; + case JValue value: + if (value.Type != JTokenType.Comment) { - result[index] = value.Value; - break; + result[i++] = value.Value; } + + break; } } - return result; + // In the common case of not having any comments, return the original array, otherwise create a sliced copy. + return i == list.Count ? result : result[..i]; } // This function is a clone of PopulateFromDictionary using JObject as an input. @@ -436,46 +434,44 @@ private static ICollection PopulateHashTableFromJArray(JArray list, out { error = null; var result = new object[list.Count]; + var i = 0; - for (var index = 0; index < list.Count; index++) + foreach (var element in list) { - var element = list[index]; - switch (element) { - case JArray array: + case JArray subList: + // Array + result[i++] = PopulateHashTableFromJArray(subList, out error); + if (error != null) { - // Array - var listResult = PopulateHashTableFromJArray(array, out error); - if (error != null) - { - return null; - } - - result[index] = listResult; - break; + return null; } + + break; + case JObject dic: + // Dictionary + result[i++] = PopulateHashTableFromJDictionary(dic, out error); + if (error != null) { - // Dictionary - var dicResult = PopulateHashTableFromJDictionary(dic, out error); - if (error != null) - { - return null; - } - - result[index] = dicResult; - break; + return null; } + + break; + case JValue value: + if (value.Type != JTokenType.Comment) { - result[index] = value.Value; - break; + result[i++] = value.Value; } + + break; } } - return result; + // In the common case of not having any comments, return the original array, otherwise create a sliced copy. + return i == list.Count ? result : result[..i]; } #endregion ConvertFromJson diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-Json.Tests.ps1 index 599ff35639e..aebdc37d1c2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-Json.Tests.ps1 @@ -350,6 +350,38 @@ c 3 $json | Should -BeOfType ([string]) $json | Should -Be $Value.Substring(1, $Value.Length - 2) } + + It 'Ignores comments in arrays' -TestCase $testCasesWithAndWithoutAsHashtableSwitch { + param($AsHashtable) + + # https://github.com/powerShell/powerShell/issues/14553 + '[ + // comment + 100, + /* comment */ + 200 + ]' | ConvertFrom-Json -AsHashtable:$AsHashtable | Should -Be @(100, 200) + } + + It 'Ignores comments in dictionaries' -TestCase $testCasesWithAndWithoutAsHashtableSwitch { + param($AsHashtable) + + $json = '{ + // comment + "a": 100, + /* comment */ + "b": 200 + }' | ConvertFrom-Json -AsHashtable:$AsHashtable + + if ($AsHashtable) { + $json.Keys | Should -Be @("a", "b") + } else { + $json.psobject.Properties | Should -HaveCount 2 + } + + $json.a | Should -Be 100 + $json.b | Should -Be 200 + } } Describe 'ConvertFrom-Json -Depth Tests' -tags "Feature" { From 01e1e2269a675f69bb3e1b537b8016b55d66e1e1 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 23 Sep 2025 10:59:18 -0700 Subject: [PATCH 063/378] Add global config change detection to action (#26082) --- .github/actions/infrastructure/path-filters/action.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 78426bdff03..e150b1a9d09 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -83,7 +83,9 @@ runs: const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); - const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged; + const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); + + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; core.setOutput('toolsChanged', toolsChanged); core.setOutput('githubChanged', githubChanged); @@ -91,7 +93,9 @@ runs: core.setOutput('testsChanged', testsChanged); core.setOutput('mainSourceChanged', mainSourceChanged); core.setOutput('buildModuleChanged', buildModuleChanged); + core.setOutput('globalConfigChanged', globalConfigChanged); core.setOutput('source', source); + - name: Capture outputs run: | From d8b1cc55332079d2be94cc266891c85e57d88c55 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 24 Sep 2025 04:09:20 +0100 Subject: [PATCH 064/378] Enable CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types (#25813) --- .globalconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.globalconfig b/.globalconfig index d51e5cfacfa..fe6b1a03a95 100644 --- a/.globalconfig +++ b/.globalconfig @@ -558,6 +558,10 @@ dotnet_diagnostic.CA2015.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2016 dotnet_diagnostic.CA2016.severity = suggestion +# CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021 +dotnet_diagnostic.CA2021.severity = warning + # CA2100: Review SQL queries for security vulnerabilities # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2100 dotnet_diagnostic.CA2100.severity = none From 0fb6904d3ea119b667015a22f60dedf2406d47b0 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:41:56 -0500 Subject: [PATCH 065/378] Automate Store Publishing (#25725) --- .pipelines/PowerShell-Release-Official.yml | 13 +- .../store/PDP/PDP-Media/en-US/Error.png | Bin 0 -> 120539 bytes .../PDP-Media/en-US/Experimental_Features.png | Bin 0 -> 161370 bytes .../PDP/PDP-Media/en-US/Feedback_Provider.png | Bin 0 -> 167038 bytes .../PDP/PDP-Media/en-US/Predictor_Inline.png | Bin 0 -> 110258 bytes .../PDP-Media/en-US/Predictor_ListView.png | Bin 0 -> 146469 bytes .../store/PDP/PDP-Media/en-US/Prompt.png | Bin 0 -> 132747 bytes .../PDP/PDP-Media/en-US/Stable_Release.png | Bin 0 -> 179123 bytes .../store/PDP/PDP-Media/en-US/pwshLogo.png | Bin 0 -> 13152 bytes .pipelines/store/PDP/PDP/en-US/PDP.xml | 176 ++++++++++++++++++ .pipelines/store/SBConfig.json | 67 +++++++ .pipelines/templates/channelSelection.yml | 31 +++ .pipelines/templates/package-create-msix.yml | 128 +++++++++++++ .pipelines/templates/release-MSIX-Publish.yml | 115 ++++++++++++ .../templates/release-SetTagAndChangelog.yml | 4 +- tools/packaging/packaging.psm1 | 11 ++ 16 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Error.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Prompt.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png create mode 100644 .pipelines/store/PDP/PDP/en-US/PDP.xml create mode 100644 .pipelines/store/SBConfig.json create mode 100644 .pipelines/templates/channelSelection.yml create mode 100644 .pipelines/templates/release-MSIX-Publish.yml diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 986f803361b..36bee13a0c7 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -25,6 +25,10 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location type: boolean default: false + - name: skipMSIXPublish + displayName: Skip MSIX Publish + type: boolean + default: false - name: OfficialBuild type: boolean default: false @@ -363,13 +367,12 @@ extends: - stage: PublishMsix dependsOn: PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store + variables: + ob_release_environment: Production jobs: - - template: /.pipelines/templates/approvalJob.yml@self + - template: /.pipelines/templates/release-MSIX-Publish.yml@self parameters: - displayName: Publish the MSIX Bundle package to store - jobName: PublishMsix - instructions: | - Ask Steve to release MSIX bundle package to Store + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} - stage: PublishVPack dependsOn: PushGitTagAndMakeDraftPublic diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Error.png b/.pipelines/store/PDP/PDP-Media/en-US/Error.png new file mode 100644 index 0000000000000000000000000000000000000000..48e96378055b5d7fbb4d744007c1ebc073da2453 GIT binary patch literal 120539 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

    qKdpe4ED4mcn4J%^2KM0@o*9MuqiJ3p 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png new file mode 100644 index 0000000000000000000000000000000000000000..90420254a8e4a4720601e3050567db719819efc6 GIT binary patch literal 161370 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png new file mode 100644 index 0000000000000000000000000000000000000000..f4084360d5c630119e469b721dde87920d5a8346 GIT binary patch literal 167038 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 z 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 L$C>(5*M9y#()S`v literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8d62284859c6ce60c96d643b3b2bdb994471d0 GIT binary patch literal 110258 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 W56C)9ct$q>0000&bOJEruf;N2sW%7_MGX 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৉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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..a40d6fddfdc44c9f7fb643ebc4e84eda527a395d GIT binary patch literal 132747 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ǟ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િI>b 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�E+=*#$Yf8)8vJb1}=9_dWABXCqD%pWa_q_sbD7Q@=YUrk0Qi3$a5 zS=Fn5S&oE`_j|oFZ_D+yPvE4}!D9m%`DxdI?vkAD0akeTcH_tF-D0v#6bqA-#hksR^_wjm7 zyHWIrZM^A4S~+x3trRbH2sw_R%>kr3D@}`AdQHe^23CtVu4>Z?VW2J{3z)kpX3whDnT;pQ~(JQt=qYXB@J*E z`j)AW*?o(cD5iTyBSl?%1T*pj(Mhn8j{Dn581t?JSt0V5nBup zr#y!T7rD<{n%b)KmcUc)W!X;ML^VqfRTr`;J7%D^sWcAewPS3Ce~Ry+HK#%)_m*%Bm%7Bv(isWuwV62RP1+#>ej!2Qj+T=BZoXm#6Wy3UVW{q2*z< z@rS&i9x~qb_2{|suO76K^2N~rF(LZ$2rNs7eOShLQTmIn zs}!8X)6LuL!GWy)qr&XsXculW*zV%^Ry5-MOb((ryxiJ%Cx`H(sK&F;m6Q~7!O!vC z`|u^VfW1L8oov2Rb`wihRWZ)9!bo!BorY5!dP~IeN!4lP8VE}?c-#Y_F|1E1rkJO> zBWVLXZL-bA1f}|`HzG2gWIPxB5rfkv1m8VAtDcb_5=R!u@k{#%ig#pGw$cHCR+Hr5 zd1G%;zQVt#Y=sQ=)Usc9PfI}KRWvm<#wnKnqi>}xq9`DTU~DRG$XyPwkeG`2E<^~9 z1&q0EFWm84d0}$Qm)aI=vo5>J3`D#EewALs?q%>$ z@M^VD&z-q@4bALulo1vxhQoh~v4TRv=2;hSa6}{Y1|+KPk77;>mo;O=uHxRMw>eAk z7vDV{S2n#u$!h_Sb{UOcO%x1)s1_JLQBdAdGv4_Qi*{X;DY~bykvu!-m0l2MO}oFY zoj?y88S9M%`oTX3PtuJkvjXnXVh z@t49=W46kmh%(uFe23)?AE)?l>z^8!+%2xlBN?%1#N)wfUGsT*XQ2$?CHs z7l_NKoC9Hdf!j0clfh+YVU3pj_<^e6zgUYthHO z@OLWR-Dj4~rz<31GS4IxH>WyWR-MYLi=30VJEB({YJI$KH44~;$Wc3OGGHbm^%0** ziQLKnvC7vZer-+o4bB=FdCD;%0&*Vb>$y@(usr;yEc18C&R7P2#j2hLbxm!ftxlYG zL57dNB2tJlBHmbj4EQLC8|5bYBjlI!K$YGXzdv13h@wQLr^?tUlMl|vf3IO&>>fp} z<)tCo_(&c+s?x`_Au7Wp^*XS3644_m�-ID=%B|=h~b5ZOc}~$w;f(<4)0Z?9))3 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 literal 0 HcmV?d00001 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..c531f719c85429fa6192eae82bb434e0318de801 GIT binary patch literal 13152 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 + + + + + + + + + + + + Shell + + PowerShell + + Terminal + + Command Line + + Automation + + Task Automation + + Scripting + + + PowerShell is a task-based command-line shell and scripting language built on .NET. PowerShell helps system administrators and power-users rapidly automate task that manage operating systems (Linux, macOS, and Windows) and processes. + +PowerShell commands let you manage computers from the command line. PowerShell providers let you access data stores, such as the registry and certificate store, as easily as you access the file system. PowerShell includes a rich expression parser and a fully developed scripting language. + +PowerShell is Open Source. See https://github.com/powershell/powershell + + + + + + + + + + + + + + + + + + + + + + Please see our GitHub releases page for additional details. + + + + + + Prompt + + + + Inline Prediction + + + + Prediction List View + + + + Error Feedback Provider + + + + Feedback Provider + + + + Experimental Features + + + + + + + + + + + + + + + + + + + Interactive Shell + + Scripting Language + + Remote Management + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Corporation + + + + + https://github.com/PowerShell/PowerShell + + https://github.com/PowerShell/PowerShell/issues + + https://go.microsoft.com/fwlink/?LinkID=521839 + diff --git a/.pipelines/store/SBConfig.json b/.pipelines/store/SBConfig.json new file mode 100644 index 00000000000..002333cba1d --- /dev/null +++ b/.pipelines/store/SBConfig.json @@ -0,0 +1,67 @@ +{ + "helpUri": "https:\\\\aka.ms\\StoreBroker_Config", + "schemaVersion": 2, + "packageParameters": { + "PDPRootPath": "", + "Release": "", + "PDPInclude": [], + "PDPExclude": [], + "LanguageExclude": [ + "default", + "qps-ploc", + "qps-ploca", + "qps-plocm" + ], + "MediaRootPath": "", + "MediaFallbackLanguage": "en-US", + "PackagePath": [], + "OutPath": "", + "OutName": "", + "DisableAutoPackageNameFormatting": false + }, + "appSubmission": { + "productId": "", + "targetPublishMode": "NotSet", + "targetPublishDate": null, + "visibility": "NotSet", + "pricing": { + "priceId": "NotAvailable", + "trialPeriod": "NoFreeTrial", + "marketSpecificPricings": {}, + "sales": [] + }, + "allowTargetFutureDeviceFamilies": { + "Xbox": false, + "Team": false, + "Holographic": false, + "Desktop": false, + "Mobile": false + }, + "allowMicrosoftDecideAppAvailabilityToFutureDeviceFamilies": false, + "enterpriseLicensing": "None", + "applicationCategory": "NotSet", + "hardwarePreferences": [], + "hasExternalInAppProducts": false, + "meetAccessibilityGuidelines": false, + "canInstallOnRemovableMedia": false, + "automaticBackupEnabled": false, + "isGameDvrEnabled": false, + "gamingOptions": [ + { + "genres": [], + "isLocalMultiplayer": false, + "isLocalCooperative": false, + "isOnlineMultiplayer": false, + "isOnlineCooperative": false, + "localMultiplayerMinPlayers": 0, + "localMultiplayerMaxPlayers": 0, + "localCooperativeMinPlayers": 0, + "localCooperativeMaxPlayers": 0, + "isBroadcastingPrivilegeGranted": false, + "isCrossPlayEnabled": false, + "kinectDataForExternal": "Disabled" + } + ], + "notesForCertification": "" + } +} diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml new file mode 100644 index 00000000000..0e352ef7558 --- /dev/null +++ b/.pipelines/templates/channelSelection.yml @@ -0,0 +1,31 @@ +steps: +- pwsh: | + # Determine LTS, Preview, or Stable + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json + $LTS = $metadata.LTSRelease.Latest + $Stable = $metadata.StableRelease.Latest + $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' + + $IsLTS = [bool]$LTS + $IsStable = [bool]$Stable + $IsPreview = [bool]$isPreview + + $channelVars = @{ + IsLTS = $IsLTS + IsStable = $IsStable + IsPreview = $IsPreview + } + + $trueCount = ($channelVars.Values | Where-Object { $_ }) | Measure-Object | Select-Object -ExpandProperty Count + if ($trueCount -gt 1) { + Write-Error "Only one of IsLTS, IsStable, or IsPreview can be true. Current values: IsLTS=$IsLTS, IsStable=$IsStable, IsPreview=$IsPreview" + exit 1 + } + + foreach ($name in $channelVars.Keys) { + $value = if ($channelVars[$name]) { 'true' } else { 'false' } + Write-Verbose -Message "Setting $name variable: $value" -Verbose + Write-Host "##vso[task.setvariable variable=$name;isOutput=true]$value" + } + name: ChannelSelection + displayName: Select Preview, Stable, or LTS Channel diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 0ab2408e6a7..37a66362119 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -7,10 +7,16 @@ jobs: variables: - group: msixTools - group: 'Azure Blob variable group' + - group: 'Store Publish Variables' - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' steps: + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + - template: release-SetReleaseTagandContainerName.yml@self - task: DownloadPipelineArtifact@2 @@ -108,3 +114,125 @@ jobs: Write-Verbose -Verbose "Uploaded Bundle:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts + + - pwsh: | + Write-Verbose -Verbose "Pipeline.Workspace: $(Pipeline.Workspace)" + Get-ChildItem -Path $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)" + Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName + Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose + displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory + + - template: channelSelection.yml@self + + - pwsh: | + $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" + + # Define app configurations for each channel + $channelConfigs = @{ + 'LTS' = @{ + AppStoreName = 'PowerShell-LTS' + ProductId = '$(productId-LTS)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Stable' = @{ + AppStoreName = 'PowerShell' + ProductId = '$(productId-Stable)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Preview' = @{ + AppStoreName = 'PowerShell (Preview)' + ProductId = '$(productId-Preview)' + ServiceEndpoint = "StoreAppPublish-Preview" + } + } + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" + Write-Verbose -Verbose "Product ID: $($config.ProductId)" + + # Update PDP.xml file + $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' + if (Test-Path $pdpPath) { + Write-Verbose -Verbose "Updating PDP file: $pdpPath" + + [xml]$pdpXml = Get-Content $pdpPath -Raw + + $appStoreNameElement = $pdpXml.SelectSingleNode("//AppStoreName[@_locID]") + if ($appStoreNameElement) { + $appStoreNameElement.InnerText = $config.AppStoreName + Write-Verbose -Verbose "Updated AppStoreName to: $($config.AppStoreName)" + } else { + Write-Warning "AppStoreName element not found in PDP file" + } + + $pdpXml.Save($pdpPath) + Write-Verbose -Verbose "PDP file updated successfully" + } else { + Write-Error "PDP file not found: $pdpPath" + exit 1 + } + + # Update SBConfig.json file + $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' + if (Test-Path $sbConfigPath) { + Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" + + $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json + + $sbConfigJson.appSubmission.productId = $config.ProductId + Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" + + $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 + Write-Verbose -Verbose "SBConfig file updated successfully" + } else { + Write-Error "SBConfig file not found: $sbConfigPath" + exit 1 + } + + Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($config.SBConfigPath)" + name: UpdateConfigs + displayName: Update PDPs and SBConfig.json + + - task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@3 + displayName: 'Create StoreBroker Package' + inputs: + serviceEndpoint: '$(ServiceConnection)' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + + - pwsh: | + $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" + $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" + $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" + + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { + Write-Verbose -Verbose "Uploading StoreBroker Package files:" + Write-Verbose -Verbose "JSON File: $jsonFile" + Write-Verbose -Verbose "ZIP File: $zipFile" + + Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse + } + + else { + Write-Error "Required files not found in $submissionPackageDir" + } + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml new file mode 100644 index 00000000000..9a0dba8833f --- /dev/null +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -0,0 +1,115 @@ +parameters: + - name: skipMSIXPublish + type: boolean + +jobs: +- job: Store_Publish_MSIX + displayName: Publish MSIX to the Microsoft Store + pool: + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_msixbundle_CreateMSIXBundle + variables: + - group: 'Store Publish Variables' + - template: ./variable/release-shared.yml@self + parameters: + RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] + LTS: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] + STABLE: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] + PREVIEW: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] + steps: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Release Tag: $(ReleaseTag)" + Get-ChildItem $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName + displayName: 'Capture ReleaseTag and Downloaded Packages' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + if ("$(ReleaseTag)" -eq '') { + Write-Error "ReleaseTag is not set. Cannot proceed with publishing to the Store." + exit 1 + } + $middleURL = '' + $tagString = "$(ReleaseTag)" + if ($tagString -match '-') { + $middleURL = "preview" + } + elseif ($tagString -match '(\d+\.\d+)') { + $middleURL = $matches[1] + } + + $endURL = $tagString -replace '[v\.]','' + $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" + Write-Verbose -Verbose "Release Notes for the Store:" + Write-Verbose -Verbose "$message" + $jsonPath = "$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json" + $json = Get-Content $jsonPath -Raw | ConvertFrom-Json + + $json.listings.'en-us'.baseListing.releaseNotes = $message + + $json | ConvertTo-Json -Depth 100 | Set-Content $jsonPath -Encoding UTF8 + displayName: 'Update Release Notes in JSON' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" + + # Define app configurations for each channel using secret variables + $channelConfigs = @{ + 'LTS' = @{ + AppId = '$(AppID-LTS)' + ServiceEndpoint = 'StoreAppPublish-Stable' + } + 'Stable' = @{ + AppId = '$(AppID-Stable)' + ServiceEndpoint = 'StoreAppPublish-Stable' + } + 'Preview' = @{ + AppId = '$(AppID-Preview)' + ServiceEndpoint = 'StoreAppPublish-Preview' + } + } + + # Determine the current channel + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App ID: $($config.AppId)" + Write-Verbose -Verbose "Service Endpoint: $($config.ServiceEndpoint)" + + # Set pipeline variables for use in the store-publish task + Write-Host "##vso[task.setvariable variable=SelectedAppId]$($config.AppId)" + Write-Host "##vso[task.setvariable variable=SelectedServiceEndpoint]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SelectedChannel]$currentChannel" + displayName: 'Set StoreBroker Configurations' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish LTS StoreBroker Package' + condition: ne('${{ parameters.skipMSIXPublish }}', 'true') + inputs: + serviceEndpoint: '$(SelectedServiceEndpoint)' + appId: '$(SelectedAppId)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' diff --git a/.pipelines/templates/release-SetTagAndChangelog.yml b/.pipelines/templates/release-SetTagAndChangelog.yml index f0c516dd28f..b33e652b3c7 100644 --- a/.pipelines/templates/release-SetTagAndChangelog.yml +++ b/.pipelines/templates/release-SetTagAndChangelog.yml @@ -19,7 +19,7 @@ jobs: clean: true env: ob_restore_phase: true - + - pwsh: | Write-Verbose -Verbose "Release Tag: $(OutputReleaseTag.releaseTag)" $releaseVersion = '$(OutputReleaseTag.releaseTag)' -replace '^v','' @@ -47,3 +47,5 @@ jobs: New-Item -Path $(ob_outputDirectory)/CHANGELOG -ItemType Directory -Force Copy-Item -Path $filePath -Destination $(ob_outputDirectory)/CHANGELOG displayName: Upload Changelog + + - template: channelSelection.yml@self diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index ef8fba4efb8..8e7fb3c4e08 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -515,6 +515,7 @@ function Start-PSPackage { Architecture = $WindowsRuntime.Split('-')[1] Force = $Force Private = $Private + LTS = $LTS } if ($PSCmdlet.ShouldProcess("Create MSIX Package")) { @@ -3670,6 +3671,9 @@ function New-MSIXPackage # Produce private package for testing in Store [Switch] $Private, + # Produce LTS package + [Switch] $LTS, + # Force overwrite of package [Switch] $Force, @@ -3714,6 +3718,9 @@ function New-MSIXPackage } elseif ($ProductSemanticVersion.Contains('-')) { $ProductName += 'Preview' $displayName += ' Preview' + } elseif ($LTS) { + $ProductName += '-LTS' + $displayName += '-LTS' } Write-Verbose -Verbose "ProductName: $productName" @@ -3733,6 +3740,10 @@ function New-MSIXPackage # This is the PhoneProductId for the "Microsoft.PowerShellPreview" package. $PhoneProductId = "67859fd2-b02a-45be-8fb5-62c569a3e8bf" Write-Verbose "Using Preview assets" -Verbose + } elseif ($LTS) { + # This is the PhoneProductId for the "Microsoft.PowerShell-LTS" package. + $PhoneProductId = "a9af273a-c636-47ac-bc2a-775edf80b2b9" + Write-Verbose "Using LTS assets" -Verbose } # Appx manifest needs to be in root of source path, but the embedded version needs to be updated From 3cfa4b24699261c0dbbe8bead96c37cbd5af787d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 30 Sep 2025 11:44:27 -0700 Subject: [PATCH 066/378] Mark the 3 consistently failing tests as pending to unblock PRs (#26091) --- test/powershell/Host/ConsoleHost.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index 12da91bf19e..fffd959654b 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -1021,7 +1021,7 @@ public enum ShowWindowCommands : int $global:PSDefaultParameterValues = $defaultParamValues } - It "-WindowStyle should work on Windows" -TestCases @( + It "-WindowStyle should work on Windows" -Pending -TestCases @( @{WindowStyle="Normal"}, @{WindowStyle="Minimized"}, @{WindowStyle="Maximized"} # hidden doesn't work in CI/Server Core From 3aa49cca9bc66f00ccf1ae308584dbf082683782 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:18:52 -0700 Subject: [PATCH 067/378] Remove `IsScreenReaderActive()` check from `ConsoleHost` (#26118) --- .../host/msh/ConsoleHost.cs | 62 +++---------------- .../resources/ManagedEntranceStrings.resx | 9 +-- test/powershell/Host/ScreenReader.Tests.ps1 | 58 ----------------- 3 files changed, 12 insertions(+), 117 deletions(-) delete mode 100644 test/powershell/Host/ScreenReader.Tests.ps1 diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 8a38b1904cb..b866815a25c 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -54,16 +54,11 @@ internal sealed partial class ConsoleHost internal const int ExitCodeCtrlBreak = 128 + 21; // SIGBREAK internal const int ExitCodeInitFailure = 70; // Internal Software Error internal const int ExitCodeBadCommandLineParameter = 64; // Command Line Usage Error - private const uint SPI_GETSCREENREADER = 0x0046; #if UNIX internal const string DECCKM_ON = "\x1b[?1h"; internal const string DECCKM_OFF = "\x1b[?1l"; #endif - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref bool pvParam, uint fWinIni); - ///

    /// Internal Entry point in msh console host implementation. /// @@ -1680,35 +1675,6 @@ private void CreateRunspace(RunspaceCreationEventArgs runspaceCreationArgs) } } - /// - /// Check if a screen reviewer utility is running. - /// When a screen reader is running, we don't auto-load the PSReadLine module at startup, - /// since PSReadLine is not accessibility-friendly enough as of today. - /// - private bool IsScreenReaderActive() - { - if (_screenReaderActive.HasValue) - { - return _screenReaderActive.Value; - } - - _screenReaderActive = false; - if (Platform.IsWindowsDesktop) - { - // Note: this API can detect if a third-party screen reader is active, such as NVDA, but not the in-box Windows Narrator. - // Quoted from https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-systemparametersinfoa about the - // accessibility parameter 'SPI_GETSCREENREADER': - // "Narrator, the screen reader that is included with Windows, does not set the SPI_SETSCREENREADER or SPI_GETSCREENREADER flags." - bool enabled = false; - if (SystemParametersInfo(SPI_GETSCREENREADER, 0, ref enabled, 0)) - { - _screenReaderActive = enabled; - } - } - - return _screenReaderActive.Value; - } - private static bool LoadPSReadline() { // Don't load PSReadline if: @@ -1759,7 +1725,6 @@ private void DoCreateRunspace(RunspaceCreationEventArgs args) bool psReadlineFailed = false; // Load PSReadline by default unless there is no use: - // - screen reader is active, such as NVDA, indicating non-visual access // - we're running a command/file and just exiting // - stdin is redirected by a parent process // - we're not interactive @@ -1770,26 +1735,18 @@ private void DoCreateRunspace(RunspaceCreationEventArgs args) ReadOnlyCollection defaultImportModulesList = null; if (!customConfigurationProvided && LoadPSReadline()) { - if (IsScreenReaderActive()) + // Create and open Runspace with PSReadline. + defaultImportModulesList = DefaultInitialSessionState.Modules; + DefaultInitialSessionState.ImportPSModule(new[] { "PSReadLine" }); + consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState); + try { - s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.PSReadLineDisabledWhenScreenReaderIsActive); - s_theConsoleHost.UI.WriteLine(); + OpenConsoleRunspace(consoleRunspace, args.StaMode); } - else + catch (Exception) { - // Create and open Runspace with PSReadline. - defaultImportModulesList = DefaultInitialSessionState.Modules; - DefaultInitialSessionState.ImportPSModule(new[] { "PSReadLine" }); - consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState); - try - { - OpenConsoleRunspace(consoleRunspace, args.StaMode); - } - catch (Exception) - { - consoleRunspace = null; - psReadlineFailed = true; - } + consoleRunspace = null; + psReadlineFailed = true; } } @@ -3102,7 +3059,6 @@ private sealed class ConsoleHostStartupException : Exception private bool _setShouldExitCalled; private bool _isRunningPromptLoop; private bool _wasInitialCommandEncoded; - private bool? _screenReaderActive; // hostGlobalLock is used to sync public method calls (in case multiple threads call into the host) and access to // state that persists across method calls, like progress data. It's internal because the ui object also diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index a57d044a8be..2c0b0154757 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -132,9 +132,6 @@ [Restricted Language Mode] - - Warning: PowerShell detected that you might be using a screen reader and has disabled PSReadLine for compatibility purposes. If you want to re-enable it, run 'Import-Module PSReadLine'. - {1} A new PowerShell preview release is available: v{0} {2} {1} Upgrade now, or check out the release page at:{3}{2} @@ -162,9 +159,9 @@ [-CustomPipeName <string>] [-EncodedCommand <Base64EncodedCommand>] [-ExecutionPolicy <ExecutionPolicy>] [-InputFormat {Text | XML}] [-Interactive] [-MTA] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile] - [-NoProfileLoadTime] [-OutputFormat {Text | XML}] - [-SettingsFile <filePath>] [-SSHServerMode] [-STA] - [-Version] [-WindowStyle <style>] + [-NoProfileLoadTime] [-OutputFormat {Text | XML}] + [-SettingsFile <filePath>] [-SSHServerMode] [-STA] + [-Version] [-WindowStyle <style>] [-WorkingDirectory <directoryPath>] pwsh[.exe] -h | -Help | -? | /? diff --git a/test/powershell/Host/ScreenReader.Tests.ps1 b/test/powershell/Host/ScreenReader.Tests.ps1 deleted file mode 100644 index 1b11a0e3ffa..00000000000 --- a/test/powershell/Host/ScreenReader.Tests.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Describe "Validate start of console host" -Tag CI { - BeforeAll { - if (-not $IsWindows) { - return - } - - $csharp_source = @' - using System; - using System.Runtime.InteropServices; - - public class ScreenReaderTestUtility { - private const uint SPI_SETSCREENREADER = 0x0047; - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); - - public static bool ActivateScreenReader() { - return SystemParametersInfo(SPI_SETSCREENREADER, 1u, IntPtr.Zero, 0); - } - - public static bool DeactivateScreenReader() { - return SystemParametersInfo(SPI_SETSCREENREADER, 0u, IntPtr.Zero, 0); - } - } -'@ - $utilType = "ScreenReaderTestUtility" -as [type] - if (-not $utilType) { - $utilType = Add-Type -TypeDefinition $csharp_source -PassThru - } - - ## Make the screen reader status active. - $utilType::ActivateScreenReader() - } - - AfterAll { - if ($IsWindows) { - ## Make the screen reader status in-active. - $utilType::DeactivateScreenReader() - } - } - - It "PSReadLine should not be auto-loaded when screen reader status is active" -Skip:(-not $IsWindows) { - if (Test-IsWindowsArm64) { - Set-ItResult -Pending -Because "Needs investigation, PSReadline loads on ARM64" - } - - $output = & "$PSHOME/pwsh" -noprofile -noexit -c "Get-Module PSReadLine; exit" - $output.Length | Should -BeExactly 2 -Because "There should be two lines of output but we got: $output" - - ## The warning message about screen reader should be returned, but the PSReadLine module should not be loaded. - $output[0] | Should -BeLike "Warning:*'Import-Module PSReadLine'." - $output[1] | Should -BeExactly ([string]::Empty) - } -} From 716754d2208bfa3671409a833da055dc66fc39f9 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 30 Sep 2025 12:32:43 -0700 Subject: [PATCH 068/378] Remove `ThreadJob` module and update `PSReadLine` to 2.4.4-beta4 (#26120) --- src/Modules/PSGalleryModules.csproj | 3 +-- test/powershell/Modules/PSReadLine/PSReadLine.Tests.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index e4fce43b396..327c293e72c 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -15,8 +15,7 @@ - - + diff --git a/test/powershell/Modules/PSReadLine/PSReadLine.Tests.ps1 b/test/powershell/Modules/PSReadLine/PSReadLine.Tests.ps1 index 975f4f82da3..732404a6b36 100644 --- a/test/powershell/Modules/PSReadLine/PSReadLine.Tests.ps1 +++ b/test/powershell/Modules/PSReadLine/PSReadLine.Tests.ps1 @@ -12,13 +12,13 @@ Describe "PSReadLine" -tags "CI" { Import-Module PSReadLine $module = Get-Module PSReadLine $module.Name | Should -BeExactly 'PSReadLine' - $module.Version | Should -Match '^2.3.\d$' + $module.Version | Should -Match '^2.4.\d$' } It "Should be installed to `$PSHOME" { $module = Get-Module (Join-Path -Path $PSHOME -ChildPath "Modules" -AdditionalChildPath "PSReadLine") -ListAvailable $module.Name | Should -BeExactly 'PSReadLine' - $module.Version | Should -Match '^2.3.\d$' + $module.Version | Should -Match '^2.4.\d$' $module.Path | Should -Be (Join-Path -Path $PSHOME -ChildPath "Modules/PSReadLine/PSReadLine.psd1") } From 859431e0028ff623bbe4a71e7ff538855d965711 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 30 Sep 2025 12:56:54 -0700 Subject: [PATCH 069/378] Allow opt-out of the named-pipe listener using the environment variable `POWERSHELL_DIAGNOSTICS_OPTOUT` (#26086) --- .../engine/Utils.cs | 67 +++++++++++++++++- .../remoting/common/RemoteSessionNamedPipe.cs | 14 ++-- .../resources/RemotingErrorIdStrings.resx | 2 +- .../utils/Telemetry.cs | 69 +------------------ 4 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index ba43bc521ce..0de9fe0d5cc 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -24,7 +24,6 @@ using System.Threading; using Microsoft.PowerShell.Commands; using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; using TypeTable = System.Management.Automation.Runspaces.TypeTable; @@ -1548,6 +1547,72 @@ internal static bool IsSessionRestricted(ExecutionContext context) } return true; } + + /// + /// Determine whether the environment variable is set and how. + /// + /// The name of the environment variable. + /// If the environment variable is not set, use this as the default value. + /// A boolean representing the value of the environment variable. + internal static bool GetEnvironmentVariableAsBool(string name, bool defaultValue) + { + var str = Environment.GetEnvironmentVariable(name); + if (string.IsNullOrEmpty(str)) + { + return defaultValue; + } + + var boolStr = str.AsSpan(); + + if (boolStr.Length == 1) + { + if (boolStr[0] == '1') + { + return true; + } + + if (boolStr[0] == '0') + { + return false; + } + } + + if (boolStr.Length == 3 && + (boolStr[0] == 'y' || boolStr[0] == 'Y') && + (boolStr[1] == 'e' || boolStr[1] == 'E') && + (boolStr[2] == 's' || boolStr[2] == 'S')) + { + return true; + } + + if (boolStr.Length == 2 && + (boolStr[0] == 'n' || boolStr[0] == 'N') && + (boolStr[1] == 'o' || boolStr[1] == 'O')) + { + return false; + } + + if (boolStr.Length == 4 && + (boolStr[0] == 't' || boolStr[0] == 'T') && + (boolStr[1] == 'r' || boolStr[1] == 'R') && + (boolStr[2] == 'u' || boolStr[2] == 'U') && + (boolStr[3] == 'e' || boolStr[3] == 'E')) + { + return true; + } + + if (boolStr.Length == 5 && + (boolStr[0] == 'f' || boolStr[0] == 'F') && + (boolStr[1] == 'a' || boolStr[1] == 'A') && + (boolStr[2] == 'l' || boolStr[2] == 'L') && + (boolStr[3] == 's' || boolStr[3] == 'S') && + (boolStr[4] == 'e' || boolStr[4] == 'E')) + { + return false; + } + + return defaultValue; + } } } diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs index 4810d1b37ea..e21608a378f 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs @@ -12,7 +12,6 @@ using System.Security.AccessControl; using System.Security.Principal; using System.Threading; -using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; @@ -500,13 +499,14 @@ static RemoteSessionNamedPipeServer() { s_syncObject = new object(); - // All PowerShell instances will start with the named pipe - // and listener created and running. - IPCNamedPipeServerEnabled = true; - - CreateIPCNamedPipeServerSingleton(); + // Unless opt-out, all PowerShell instances will start with the named-pipe listener created and running. + IPCNamedPipeServerEnabled = !Utils.GetEnvironmentVariableAsBool(name: "POWERSHELL_DIAGNOSTICS_OPTOUT", defaultValue: false); - CreateProcessExitHandler(); + if (IPCNamedPipeServerEnabled) + { + CreateIPCNamedPipeServerSingleton(); + CreateProcessExitHandler(); + } } #endregion diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index a9dc46bdec5..819270da259 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1411,7 +1411,7 @@ All WinRM sessions connected to PowerShell session configurations, such as Micro Multiple processes were found with this name {0}. Use the process Id to specify a single process to enter. - Cannot enter process with Id '{0}' because it has not loaded the PowerShell engine. + Cannot enter process with Id '{0}' because it has not loaded the PowerShell engine or the named-pipe listener was disabled. No process was found with Id: {0}. diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 13a8d7d5ec5..5cd728e6c55 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Management.Automation; using System.Runtime.InteropServices; -using System.Security.AccessControl; using System.Threading; using Microsoft.ApplicationInsights; @@ -177,7 +176,7 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); + CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); if (CanSendTelemetry) { s_sessionId = Guid.NewGuid().ToString(); @@ -643,72 +642,6 @@ static ApplicationInsightsTelemetry() } } - /// - /// Determine whether the environment variable is set and how. - /// - /// The name of the environment variable. - /// If the environment variable is not set, use this as the default value. - /// A boolean representing the value of the environment variable. - private static bool GetEnvironmentVariableAsBool(string name, bool defaultValue) - { - var str = Environment.GetEnvironmentVariable(name); - if (string.IsNullOrEmpty(str)) - { - return defaultValue; - } - - var boolStr = str.AsSpan(); - - if (boolStr.Length == 1) - { - if (boolStr[0] == '1') - { - return true; - } - - if (boolStr[0] == '0') - { - return false; - } - } - - if (boolStr.Length == 3 && - (boolStr[0] == 'y' || boolStr[0] == 'Y') && - (boolStr[1] == 'e' || boolStr[1] == 'E') && - (boolStr[2] == 's' || boolStr[2] == 'S')) - { - return true; - } - - if (boolStr.Length == 2 && - (boolStr[0] == 'n' || boolStr[0] == 'N') && - (boolStr[1] == 'o' || boolStr[1] == 'O')) - { - return false; - } - - if (boolStr.Length == 4 && - (boolStr[0] == 't' || boolStr[0] == 'T') && - (boolStr[1] == 'r' || boolStr[1] == 'R') && - (boolStr[2] == 'u' || boolStr[2] == 'U') && - (boolStr[3] == 'e' || boolStr[3] == 'E')) - { - return true; - } - - if (boolStr.Length == 5 && - (boolStr[0] == 'f' || boolStr[0] == 'F') && - (boolStr[1] == 'a' || boolStr[1] == 'A') && - (boolStr[2] == 'l' || boolStr[2] == 'L') && - (boolStr[3] == 's' || boolStr[3] == 'S') && - (boolStr[4] == 'e' || boolStr[4] == 'E')) - { - return false; - } - - return defaultValue; - } - /// /// Send module load telemetry as a metric. /// For modules we send the module name (if allowed), and the version. From a1fad7f738e9154acfa4f5ee9824e9bc818b8253 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:48:45 -0700 Subject: [PATCH 070/378] Update package references for the master branch (#26124) --- .../BenchmarkDotNet.Extensions.csproj | 4 ++-- test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 642210dc83d..74a4cf9e089 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 47d4352df9c..9883c8b2d63 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 15c379ed016..33f0a2dde00 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -25,7 +25,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From a0cb55c8267cbfefb8f7d0458467044823ccc4e9 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 1 Oct 2025 11:42:47 -0700 Subject: [PATCH 071/378] Update 'ThirdPartyNotices.txt' in the master branch (#26130) --- ThirdPartyNotices.txt | 110 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 28a06a82744..8abff24592f 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Markdig.Signed 0.40.0 - BSD-2-Clause +Markdig.Signed 0.42.0 - BSD-2-Clause @@ -119,7 +119,7 @@ SOFTWARE. --------------------------------------------------------- -JsonSchema.Net 7.3.4 - MIT +JsonSchema.Net 7.4.0 - MIT Copyright (c) .NET Foundation and Contributors @@ -170,7 +170,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 9.0.3 - MIT +Microsoft.Bcl.AsyncInterfaces 9.0.9 - MIT Copyright (c) 2021 @@ -260,7 +260,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.13.0 - MIT +Microsoft.CodeAnalysis.Common 4.14.0 - MIT (c) Microsoft Corporation @@ -280,7 +280,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.13.0 - MIT +Microsoft.CodeAnalysis.CSharp 4.14.0 - MIT (c) Microsoft Corporation @@ -305,7 +305,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 9.0.3 - MIT +Microsoft.Extensions.ObjectPool 9.0.9 - MIT Copyright Jorn Zaefferer @@ -395,7 +395,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.3 - MIT +Microsoft.Win32.Registry.AccessControl 9.0.9 - MIT Copyright (c) 2021 @@ -485,7 +485,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.3 - MIT +Microsoft.Win32.SystemEvents 9.0.9 - MIT Copyright (c) 2021 @@ -575,7 +575,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.3 - MIT +Microsoft.Windows.Compatibility 9.0.9 - MIT (c) Microsoft Corporation @@ -594,7 +594,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Newtonsoft.Json 13.0.3 - MIT +Newtonsoft.Json 13.0.4 - MIT Copyright James Newton-King 2008 @@ -628,7 +628,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -718,7 +718,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -808,7 +808,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -898,7 +898,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -988,7 +988,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1078,7 +1078,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1168,7 +1168,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1258,7 +1258,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1348,7 +1348,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1438,7 +1438,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1528,7 +1528,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1618,7 +1618,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1708,7 +1708,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1798,7 +1798,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -1933,7 +1933,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -2023,7 +2023,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -2113,7 +2113,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.3 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -2203,7 +2203,7 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 9.0.3 - MIT +System.CodeDom 9.0.9 - MIT Copyright (c) 2021 @@ -2293,7 +2293,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 9.0.3 - MIT +System.ComponentModel.Composition 9.0.9 - MIT Copyright (c) 2021 @@ -2383,7 +2383,7 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.3 - MIT +System.ComponentModel.Composition.Registration 9.0.9 - MIT Copyright (c) 2021 @@ -2473,7 +2473,7 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.3 - MIT +System.Configuration.ConfigurationManager 9.0.9 - MIT Copyright (c) 2021 @@ -2563,7 +2563,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 9.0.3 - MIT +System.Data.Odbc 9.0.9 - MIT Copyright (c) 2021 @@ -2653,7 +2653,7 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 9.0.3 - MIT +System.Data.OleDb 9.0.9 - MIT Copyright (c) 2021 @@ -2762,7 +2762,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.3 - MIT +System.Diagnostics.EventLog 9.0.9 - MIT Copyright (c) 2021 @@ -2852,7 +2852,7 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.3 - MIT +System.Diagnostics.PerformanceCounter 9.0.9 - MIT Copyright (c) 2021 @@ -2942,7 +2942,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 9.0.3 - MIT +System.DirectoryServices 9.0.9 - MIT Copyright (c) 2021 @@ -3032,7 +3032,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.3 - MIT +System.DirectoryServices.AccountManagement 9.0.9 - MIT Copyright (c) 2021 @@ -3122,7 +3122,7 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.3 - MIT +System.DirectoryServices.Protocols 9.0.9 - MIT Copyright (c) 2021 @@ -3212,7 +3212,7 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 9.0.3 - MIT +System.Drawing.Common 9.0.9 - MIT (c) Microsoft Corporation @@ -3247,7 +3247,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.3 - MIT +System.IO.Packaging 9.0.9 - MIT Copyright (c) 2021 @@ -3337,7 +3337,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 9.0.3 - MIT +System.IO.Ports 9.0.9 - MIT Copyright (c) 2021 @@ -3427,7 +3427,7 @@ SOFTWARE. --------------------------------------------------------- -System.Management 9.0.3 - MIT +System.Management 9.0.9 - MIT Copyright (c) 2021 @@ -3517,7 +3517,7 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.3 - MIT +System.Net.Http.WinHttpHandler 9.0.9 - MIT Copyright (c) 2021 @@ -3643,7 +3643,7 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 9.0.3 - MIT +System.Reflection.Context 9.0.9 - MIT Copyright (c) 2021 @@ -3733,7 +3733,7 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 9.0.3 - MIT +System.Runtime.Caching 9.0.9 - MIT Copyright (c) 2021 @@ -3823,7 +3823,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.3 - MIT +System.Security.Cryptography.Pkcs 9.0.9 - MIT Copyright (c) 2021 @@ -3913,7 +3913,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.3 - MIT +System.Security.Cryptography.ProtectedData 9.0.9 - MIT Copyright (c) 2021 @@ -4003,7 +4003,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.3 - MIT +System.Security.Cryptography.Xml 9.0.9 - MIT Copyright (c) 2021 @@ -4093,7 +4093,7 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 9.0.3 - MIT +System.Security.Permissions 9.0.9 - MIT Copyright (c) 2021 @@ -4363,7 +4363,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.3 - MIT +System.ServiceModel.Syndication 9.0.9 - MIT Copyright (c) 2021 @@ -4453,7 +4453,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.3 - MIT +System.ServiceProcess.ServiceController 9.0.9 - MIT Copyright (c) 2021 @@ -4543,7 +4543,7 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 9.0.3 - MIT +System.Speech 9.0.9 - MIT Copyright (c) 2021 @@ -4633,7 +4633,7 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 9.0.3 - MIT +System.Threading.AccessControl 9.0.9 - MIT Copyright (c) 2021 @@ -4723,7 +4723,7 @@ SOFTWARE. --------------------------------------------------------- -System.Web.Services.Description 8.1.1 - MIT +System.Web.Services.Description 8.1.2 - MIT (c) Microsoft Corporation @@ -4759,7 +4759,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.3 - MIT +System.Windows.Extensions 9.0.9 - MIT Copyright (c) 2021 From b85237876d05c26951ca03beaf4e6173e209cc25 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 1 Oct 2025 12:38:19 -0700 Subject: [PATCH 072/378] Remove the use of Windows PowerShell ETW provider id and update `PSDiagnostics` module to work for PowerShell 7 (#25590) --- .../Windows/PSDiagnostics/PSDiagnostics.psm1 | 26 +++++++-------- .../utils/tracing/EtwActivity.cs | 1 - .../utils/tracing/Tracing.cs | 2 +- .../utils/tracing/TracingGen.cs | 14 +------- .../PSDiagnostics/PSDiagnostics.Tests.ps1 | 32 +++++++++---------- 5 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psm1 b/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psm1 index ce0739eb622..c31e9f25963 100644 --- a/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psm1 +++ b/src/Modules/Windows/PSDiagnostics/PSDiagnostics.psm1 @@ -4,21 +4,22 @@ <# PowerShell Diagnostics Module This module contains a set of wrapper scripts that - enable a user to use ETW tracing in Windows - PowerShell. + enable a user to use ETW tracing in PowerShell 7. #> -$script:Logman="$env:windir\system32\logman.exe" -$script:wsmanlogfile = "$env:windir\system32\wsmtraces.log" -$script:wsmprovfile = "$env:windir\system32\wsmtraceproviders.txt" +$script:windir = [System.Environment]::GetEnvironmentVariable("windir", [System.EnvironmentVariableTarget]::Machine) + +$script:Logman = "${script:windir}\system32\logman.exe" +$script:wsmanlogfile = "${script:windir}\system32\wsmtraces.log" +$script:wsmprovfile = "${script:windir}\system32\wsmtraceproviders.txt" $script:wsmsession = "wsmlog" $script:pssession = "PSTrace" -$script:psprovidername="Microsoft-Windows-PowerShell" +$script:psprovidername = "PowerShellCore" $script:wsmprovidername = "Microsoft-Windows-WinRM" $script:oplog = "/Operational" -$script:analyticlog="/Analytic" -$script:debuglog="/Debug" -$script:wevtutil="$env:windir\system32\wevtutil.exe" +$script:analyticlog = "/Analytic" +$script:debuglog = "/Debug" +$script:wevtutil = "${script:windir}\system32\wevtutil.exe" $script:slparam = "sl" $script:glparam = "gl" @@ -169,7 +170,6 @@ function Enable-PSWSManCombinedTrace $provfile = [io.path]::GetTempFilename() - $traceFileName = [string][Guid]::NewGuid() if ($DoNotOverwriteExistingTrace) { $fileName = [string][guid]::newguid() $logfile = $PSHOME + "\\Traces\\PSTrace_$fileName.etl" @@ -177,8 +177,8 @@ function Enable-PSWSManCombinedTrace $logfile = $PSHOME + "\\Traces\\PSTrace.etl" } - "Microsoft-Windows-PowerShell 0 5" | Out-File $provfile -Encoding ascii - "Microsoft-Windows-WinRM 0 5" | Out-File $provfile -Encoding ascii -Append + "$script:psprovidername 0 5" | Out-File $provfile -Encoding ascii + "$script:wsmprovidername 0 5" | Out-File $provfile -Encoding ascii -Append if (!(Test-Path $PSHOME\Traces)) { @@ -192,7 +192,7 @@ function Enable-PSWSManCombinedTrace Start-Trace -SessionName $script:pssession -OutputFilePath $logfile -ProviderFilePath $provfile -ETS - Remove-Item $provfile -Force -ea 0 + Remove-Item $provfile -Force -ErrorAction SilentlyContinue } function Disable-PSWSManCombinedTrace diff --git a/src/System.Management.Automation/utils/tracing/EtwActivity.cs b/src/System.Management.Automation/utils/tracing/EtwActivity.cs index 433d90297ee..e00fd33efe2 100644 --- a/src/System.Management.Automation/utils/tracing/EtwActivity.cs +++ b/src/System.Management.Automation/utils/tracing/EtwActivity.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics.Eventing; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; namespace System.Management.Automation.Tracing diff --git a/src/System.Management.Automation/utils/tracing/Tracing.cs b/src/System.Management.Automation/utils/tracing/Tracing.cs index babbc5d9d63..1d4684de58a 100644 --- a/src/System.Management.Automation/utils/tracing/Tracing.cs +++ b/src/System.Management.Automation/utils/tracing/Tracing.cs @@ -10,7 +10,7 @@ namespace System.Management.Automation.Tracing /// /// Tracer. /// - public sealed partial class Tracer : System.Management.Automation.Tracing.EtwActivity + public sealed partial class Tracer : EtwActivity { /// /// DebugMessage. diff --git a/src/System.Management.Automation/utils/tracing/TracingGen.cs b/src/System.Management.Automation/utils/tracing/TracingGen.cs index 05f088b7f93..b7413d5a763 100644 --- a/src/System.Management.Automation/utils/tracing/TracingGen.cs +++ b/src/System.Management.Automation/utils/tracing/TracingGen.cs @@ -10,7 +10,7 @@ namespace System.Management.Automation.Tracing /// /// Tracer. /// - public sealed partial class Tracer : System.Management.Automation.Tracing.EtwActivity + public sealed partial class Tracer : EtwActivity { /// /// Critical level. @@ -37,7 +37,6 @@ public sealed partial class Tracer : System.Management.Automation.Tracing.EtwAct /// public const long KeywordAll = 0xFFFFFFFF; - private static readonly Guid providerId = Guid.Parse("a0c1853b-5c40-4b15-8766-3cf1c58f985a"); private static readonly EventDescriptor WriteTransferEventEvent; private static readonly EventDescriptor DebugMessageEvent; private static readonly EventDescriptor M3PAbortingWorkflowExecutionEvent; @@ -218,17 +217,6 @@ static Tracer() /// public Tracer() : base() { } - /// - /// Provider Guid. - /// - protected override Guid ProviderId - { - get - { - return providerId; - } - } - /// /// Transfer Event. /// diff --git a/test/powershell/Modules/PSDiagnostics/PSDiagnostics.Tests.ps1 b/test/powershell/Modules/PSDiagnostics/PSDiagnostics.Tests.ps1 index 64fa8ba269f..30cc1b36fd4 100644 --- a/test/powershell/Modules/PSDiagnostics/PSDiagnostics.Tests.ps1 +++ b/test/powershell/Modules/PSDiagnostics/PSDiagnostics.Tests.ps1 @@ -9,7 +9,7 @@ Describe "PSDiagnostics cmdlets tests." -Tag "CI", "RequireAdminOnWindows" { $PSDefaultParameterValues["it:skip"] = $true } else{ - $LogSettingBak = Get-LogProperties -Name Microsoft-Windows-PowerShell/$LogType + $LogSettingBak = Get-LogProperties -Name PowerShellCore/$LogType } } AfterAll { @@ -20,37 +20,37 @@ Describe "PSDiagnostics cmdlets tests." -Tag "CI", "RequireAdminOnWindows" { } Context "Test for Enable-PSTrace and Disable-PSTrace cmdlets." { - It "Should enable $LogType logs for Microsoft-Windows-PowerShell." { - [XML]$CurrentSetting = & wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + It "Should enable $LogType logs for PowerShellCore." { + [XML]$CurrentSetting = & wevtutil gl PowerShellCore/$LogType /f:xml if($CurrentSetting.Channel.Enabled -eq 'true'){ - & wevtutil sl Microsoft-Windows-PowerShell/$LogType /e:false /q + & wevtutil sl PowerShellCore/$LogType /e:false /q } Enable-PSTrace -Force - [XML]$ExpectedOutput = & wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + [XML]$ExpectedOutput = & wevtutil gl PowerShellCore/$LogType /f:xml $ExpectedOutput.Channel.enabled | Should -BeExactly 'true' } - It "Should disable $LogType logs for Microsoft-Windows-PowerShell." { - [XML]$CurrentState = & wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + It "Should disable $LogType logs for PowerShellCore." { + [XML]$CurrentState = & wevtutil gl PowerShellCore/$LogType /f:xml if($CurrentState.channel.enabled -eq 'false'){ - & wevtutil sl Microsoft-Windows-PowerShell/$LogType /e:true /q + & wevtutil sl PowerShellCore/$LogType /e:true /q } Disable-PSTrace - [XML]$ExpectedOutput = & wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + [XML]$ExpectedOutput = & wevtutil gl PowerShellCore/$LogType /f:xml $ExpectedOutput.Channel.enabled | Should -Be 'false' } } Context "Test for Get-LogProperties cmdlet." { - It "Should return properties of $LogType logs for 'Microsoft-Windows-PowerShell'." { - [XML]$ExpectedOutput = wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + It "Should return properties of $LogType logs for 'PowerShellCore'." { + [XML]$ExpectedOutput = wevtutil gl PowerShellCore/$LogType /f:xml - $LogProperty = Get-LogProperties -Name Microsoft-Windows-PowerShell/$LogType + $LogProperty = Get-LogProperties -Name PowerShellCore/$LogType $LogProperty.Name | Should -Be $ExpectedOutput.channel.Name $LogProperty.Enabled | Should -Be $ExpectedOutput.channel.Enabled @@ -67,7 +67,7 @@ Describe "PSDiagnostics cmdlets tests." -Tag "CI", "RequireAdminOnWindows" { Context "Test for Set-LogProperties cmdlet." { BeforeAll { if ($IsWindows) { - [XML]$WevtUtilBefore = wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml + [XML]$WevtUtilBefore = wevtutil gl PowerShellCore/$LogType /f:xml $LogPropertyToSet = [Microsoft.PowerShell.Diagnostics.LogDetails]::new($WevtUtilBefore.channel.Name, [bool]::Parse($WevtUtilBefore.channel.Enabled), $LogType, @@ -78,12 +78,12 @@ Describe "PSDiagnostics cmdlets tests." -Tag "CI", "RequireAdminOnWindows" { } } - It "Should invert AutoBackup setting of $LogType logs for 'Microsoft-Windows-PowerShell'." { + It "Should invert AutoBackup setting of $LogType logs for 'PowerShellCore'." { $LogPropertyToSet.AutoBackup = -not $LogPropertyToSet.AutoBackup Set-LogProperties -LogDetails $LogPropertyToSet -Force - [XML]$ExpectedOutput = & wevtutil gl Microsoft-Windows-PowerShell/$LogType /f:xml - (Get-LogProperties -Name Microsoft-Windows-PowerShell/$LogType).AutoBackup | Should -Be ([bool]::Parse($ExpectedOutput.Channel.Logging.AutoBackup)) + [XML]$ExpectedOutput = & wevtutil gl PowerShellCore/$LogType /f:xml + (Get-LogProperties -Name PowerShellCore/$LogType).AutoBackup | Should -Be ([bool]::Parse($ExpectedOutput.Channel.Logging.AutoBackup)) } It "Should throw exception for invalid LogName." { From 51a21999defbe64f8a08cd7109bb7e18f57b1da6 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 1 Oct 2025 12:39:25 -0700 Subject: [PATCH 073/378] Fix R2R for fxdependent packaging (#26131) --- PowerShell.Common.props | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index a6568573379..91d44c21f03 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -186,21 +186,25 @@ EnvironmentVariable;Global + false + false Global + true + true AppLocal + true + true - true - true true portable From 31cd731926dcd81cce010f4e3c0f202b9f079eba Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 1 Oct 2025 14:09:34 -0700 Subject: [PATCH 074/378] Remove UseDotnet task and use the dotnet-install script (#26093) --- .pipelines/PowerShell-Packages-Official.yml | 6 ++++ .pipelines/templates/install-dotnet.yml | 19 +++++++++++++ .pipelines/templates/linux-package-build.yml | 4 ++- .pipelines/templates/linux.yml | 7 +---- .pipelines/templates/mac.yml | 8 ++---- .pipelines/templates/nupkg.yml | 10 +------ .../release-validate-fxdpackages.yml | 7 +---- .../release-validate-globaltools.yml | 7 +---- .pipelines/templates/release-validate-sdk.yml | 7 +---- .pipelines/templates/testartifacts.yml | 28 ++++++++----------- .pipelines/templates/windows-hosted-build.yml | 11 ++++---- .../templates/windows-package-build.yml | 11 +++----- build.psm1 | 5 ++-- 13 files changed, 57 insertions(+), 73 deletions(-) create mode 100644 .pipelines/templates/install-dotnet.yml diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 552e7d10a68..9c2dee1c571 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -27,6 +27,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time - name: OfficialBuild type: boolean default: false + - name: disableNetworkIsolation + type: boolean + default: false name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) @@ -66,6 +69,8 @@ variables: - group: MSIXSigningProfile - name: templateFile value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} resources: pipelines: @@ -96,6 +101,7 @@ extends: Network: KS3 linuxEsrpSigning: true incrementalSDLBinaryAnalysis: true + disableNetworkIsolation: ${{ variables.disableNetworkIsolation }} globalSdl: disableLegacyManifest: true # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml new file mode 100644 index 00000000000..c2a2cfebeca --- /dev/null +++ b/.pipelines/templates/install-dotnet.yml @@ -0,0 +1,19 @@ +steps: + - pwsh: | + if (-not (Test-Path '$(RepoRoot)')) { + $psRoot = '$(Build.SourcesDirectory)/PowerShell' + Set-Location $psRoot -Verbose + } + + $version = Get-Content ./global.json | ConvertFrom-Json | Select-Object -ExpandProperty sdk | Select-Object -ExpandProperty version + + Write-Verbose -Verbose "Installing .NET SDK with version $version" + + Import-Module ./build.psm1 -Force + Install-Dotnet -Version $version -Verbose + + displayName: 'Install dotnet SDK' + workingDirectory: $(RepoRoot) + env: + ob_restore_phase: true + diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 95996a597fe..68fa46690c2 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -87,6 +87,8 @@ jobs: env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + - template: /.pipelines/templates/install-dotnet.yml@self + - pwsh: | $packageType = '$(PackageType)' Write-Verbose -Verbose "packageType = $packageType" @@ -103,7 +105,7 @@ jobs: Import-Module "$repoRoot/build.psm1" Import-Module "$repoRoot/tools/packaging" - Start-PSBootstrap -Scenario Package + Start-PSBootstrap -Scenario Both $psOptionsPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${unsignedDrop}/psoptions/psoptions.json" diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index 83b7aa58ef3..aef0b53381f 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -64,12 +64,7 @@ jobs: AnalyzeInPipeline: false Language: csharp - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(PowerShellRoot) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $runtime = $env:RUNTIME diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index b08becedc22..ff4787b9bcf 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -39,12 +39,8 @@ jobs: sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(PowerShellRoot) + ## We cross compile for arm64, so the arch is always x64 + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | Import-Module $(PowerShellRoot)/build.psm1 -Force diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index dc43e841332..4756c99a9d3 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -94,15 +94,7 @@ jobs: parameters: repoRoot: $(PowerShellRoot) - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: '$(PowerShellRoot)' + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | Set-Location -Path '$(PowerShellRoot)' diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml index 9de8c7dad33..3f4f9a3bb6c 100644 --- a/.pipelines/templates/release-validate-fxdpackages.yml +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -61,12 +61,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $artifactName = '$(artifactName)' diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 3dd1fd15f56..4a7d23c8b4b 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -38,12 +38,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(REPOROOT) + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index cdd818f9dc2..4089d54e51b 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -46,12 +46,7 @@ jobs: Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse displayName: 'Capture Downloaded Artifacts' - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(REPOROOT) + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 240ceae80f7..751c9d5a53b 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -25,19 +25,16 @@ jobs: env: ob_restore_phase: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self parameters: - repoRoot: $(Build.SourcesDirectory)/PowerShell + repoRoot: $(RepoRoot) ob_restore_phase: true - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force @@ -93,19 +90,16 @@ jobs: env: ob_restore_phase: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self parameters: repoRoot: $(Build.SourcesDirectory)/PowerShell ob_restore_phase: true - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)/PowerShell" - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 8cd622149fa..4472744d7b5 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -65,12 +65,7 @@ jobs: AnalyzeInPipeline: false Language: csharp - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(PowerShellRoot) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $runtime = switch ($env:Architecture) @@ -144,6 +139,7 @@ jobs: } Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + Find-Dotnet ## Build global tool Write-Verbose -Message "Building PowerShell global tool for Windows.x64" -Verbose @@ -239,6 +235,9 @@ jobs: After that, we repack using Compress-Archive and rename it back to a nupkg. #> + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + Find-Dotnet + $packagingStrings = Import-PowerShellDataFile "$(PowerShellRoot)\tools\packaging\packaging.strings.psd1" $outputPath = Join-Path '$(ob_outputDirectory)' 'globaltool' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/windows-package-build.yml index 7cd0869caa0..bc23bfc659e 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/windows-package-build.yml @@ -78,12 +78,7 @@ jobs: env: ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - task: UseDotNet@2 - inputs: - useGlobalJson: true - workingDirectory: $(REPOROOT) - env: - ob_restore_phase: true + - template: /.pipelines/templates/install-dotnet.yml@self - pwsh: | $msixUrl = '$(makeappUrl)' @@ -112,7 +107,9 @@ jobs: Import-Module "$repoRoot\build.psm1" Import-Module "$repoRoot\tools\packaging" - Start-PSBootstrap -Scenario Package + Start-PSBootstrap -Scenario Both + + Find-Dotnet $signedFilesPath, $psoptionsFilePath = if ($env:RUNTIME -eq 'minsize') { "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_x64_${runtime}\$signedFolder" diff --git a/build.psm1 b/build.psm1 index ffbeddb1c21..a610c684e2c 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2092,8 +2092,8 @@ function Install-Dotnet { # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } - # $installObtainUrl = "https://dot.net/v1" - $installObtainUrl = "https://dotnet.microsoft.com/download/dotnet/scripts/v1" + $installObtainUrl = "https://builds.dotnet.microsoft.com/dotnet/scripts/v1" + #$installObtainUrl = "https://dotnet.microsoft.com/download/dotnet/scripts/v1" $uninstallObtainUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain" # Install for Linux and OS X @@ -2184,7 +2184,6 @@ function Install-Dotnet { $installArgs += @{ SkipNonVersionedFiles = $true } $installArgs | Out-String | Write-Verbose -Verbose - & ./$installScript @installArgs } else { From d5267d2ee661695e2dab15fdb651b4e23cd0503f Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 1 Oct 2025 18:52:12 -0400 Subject: [PATCH 075/378] Add `CodeQL` suppressions for `UpdatableHelp` and `NativeCommandProcessor` methods (#26132) --- .../engine/NativeCommandProcessor.cs | 2 ++ src/System.Management.Automation/help/UpdatableHelpSystem.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 7384a9385c3..11aaff1535f 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -854,6 +854,8 @@ private void InitNativeProcess() { startInfo.ArgumentList.RemoveAt(0); } + + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. startInfo.FileName = oldFileName; } } diff --git a/src/System.Management.Automation/help/UpdatableHelpSystem.cs b/src/System.Management.Automation/help/UpdatableHelpSystem.cs index 6ab8d469a97..14edabf9613 100644 --- a/src/System.Management.Automation/help/UpdatableHelpSystem.cs +++ b/src/System.Management.Automation/help/UpdatableHelpSystem.cs @@ -419,6 +419,7 @@ private string ResolveUri(string baseUri, bool verbose) using (HttpClient client = new HttpClient(handler)) { client.Timeout = new TimeSpan(0, 0, 30); // Set 30 second timeout + // codeql[cs/ssrf] - This is expected Poweshell behavior and the user assumes trust for the module they download and any URIs it references. The URIs are also not executables or scripts that would be invoked by this method. Task responseMessage = client.GetAsync(uri); using (HttpResponseMessage response = responseMessage.Result) { @@ -783,6 +784,7 @@ private bool DownloadHelpContentHttpClient(string uri, string fileName, Updatabl using (HttpClient client = new HttpClient(handler)) { client.Timeout = _defaultTimeout; + // codeql[cs/ssrf] - This is expected Poweshell behavior and the user assumes trust for the module they download and any URIs it references. The URIs are also not executables or scripts that would be invoked by this method. Task responseMsg = client.GetAsync(new Uri(uri), _cancelTokenSource.Token); // TODO: Should I use a continuation to write the stream to a file? From 253c68d13b4d473d643345a4cb3a20cae0f7d154 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 1 Oct 2025 17:47:52 -0700 Subject: [PATCH 076/378] Replace `ThreadJob` with `Microsoft.PowerShell.ThreadJob` (#26135) --- .pipelines/templates/windows-hosted-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 4472744d7b5..44b83ad20aa 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -272,7 +272,7 @@ jobs: 'Microsoft.PowerShell.PSResourceGet' 'Microsoft.PowerShell.Archive' 'PSReadLine' - 'ThreadJob' + 'Microsoft.PowerShell.ThreadJob' ) $sourceModulePath = Join-Path '$(GlobalToolArtifactPath)' 'publish' 'PowerShell.Windows.x64' 'release' 'Modules' From d6cca3f61f803fc9d5e10fabf59237cd873e75e4 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 2 Oct 2025 10:31:43 -0700 Subject: [PATCH 077/378] Fix the task name to not use the pre-release task (#26138) Use `MS-RDX-MRO.windows-store-publish.package-task.store-package` instead of `MS-RDX-MRO.windows-store-publish-dev.package-task.store-package`. --- .pipelines/templates/package-create-msix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 37a66362119..3d8676c0ae5 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -208,7 +208,7 @@ jobs: name: UpdateConfigs displayName: Update PDPs and SBConfig.json - - task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@3 + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package' inputs: serviceEndpoint: '$(ServiceConnection)' From be0542b1939de6a85ebf3e0e5ffd3c7c1429d0a8 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 3 Oct 2025 17:48:30 -0400 Subject: [PATCH 078/378] Add CodeQL suppresion for NativeCommandProcessor (#26145) --- .../engine/NativeCommandProcessor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 11aaff1535f..6b27c4542ab 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -1677,6 +1677,7 @@ private ProcessStartInfo GetProcessStartInfo( { using (ParameterBinderBase.bindingTracer.TraceScope("BIND argument [{0}]", NativeParameterBinderController.Arguments)) { + // codeql[cs/microsoft/command-line-injection ] - This is intended PowerShell behavior as NativeParameterBinderController.Arguments is what the native parameter binder generates based on the user input when invoking the command and cannot be injected externally. startInfo.Arguments = NativeParameterBinderController.Arguments; } } From 873db35125c74538a0547675941c3dc35d6e3c90 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 2 Oct 2025 10:56:22 -0700 Subject: [PATCH 079/378] Use StoreAppPublish-Preview explicitly Use BuildSources.Directory instead of reporoot Add powershell use sbConfigPath Add variable group store publish variables Use spaces in name Change the AppStoreName locID Output the PDP and config file Temporarily disable signing Use AppStore Xpath Use namespace xml Use AppID Upload SBLog.txt on failure Try powershell private Remove AppID addition --- .pipelines/store/SBConfig.json | 6 ++- .pipelines/templates/channelSelection.yml | 2 +- .pipelines/templates/package-create-msix.yml | 39 ++++++++++++++------ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/.pipelines/store/SBConfig.json b/.pipelines/store/SBConfig.json index 002333cba1d..a52d60b045f 100644 --- a/.pipelines/store/SBConfig.json +++ b/.pipelines/store/SBConfig.json @@ -4,7 +4,9 @@ "packageParameters": { "PDPRootPath": "", "Release": "", - "PDPInclude": [], + "PDPInclude": [ + "PDP.xml" + ], "PDPExclude": [], "LanguageExclude": [ "default", @@ -21,7 +23,7 @@ }, "appSubmission": { "productId": "", - "targetPublishMode": "NotSet", + "targetPublishMode": "Immediate", "targetPublishDate": null, "visibility": "NotSet", "pricing": { diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 0e352ef7558..3d1f445c559 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -1,7 +1,7 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable - $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json + $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json $LTS = $metadata.LTSRelease.Latest $Stable = $metadata.StableRelease.Latest $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 3d8676c0ae5..6573a04b9a7 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -93,13 +93,13 @@ jobs: displayName: Create MsixBundle retryCountOnTaskFailure: 1 - - task: onebranch.pipeline.signing@1 - displayName: Sign MsixBundle - inputs: - command: 'sign' - signing_profile: $(MSIXProfile) - files_to_sign: '**/*.msixbundle' - search_root: '$(BundleDir)' + # - task: onebranch.pipeline.signing@1 + # displayName: Sign MsixBundle + # inputs: + # command: 'sign' + # signing_profile: $(MSIXProfile) + # files_to_sign: '**/*.msixbundle' + # search_root: '$(BundleDir)' - pwsh: | $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File @@ -137,16 +137,19 @@ jobs: 'LTS' = @{ AppStoreName = 'PowerShell-LTS' ProductId = '$(productId-LTS)' + AppId = '$(AppID-LTS)' ServiceEndpoint = "StoreAppPublish-Stable" } 'Stable' = @{ AppStoreName = 'PowerShell' ProductId = '$(productId-Stable)' + AppId = '$(AppID-Stable)' ServiceEndpoint = "StoreAppPublish-Stable" } 'Preview' = @{ AppStoreName = 'PowerShell (Preview)' ProductId = '$(productId-Preview)' + AppId = '$(AppID-Preview)' ServiceEndpoint = "StoreAppPublish-Preview" } } @@ -171,16 +174,21 @@ jobs: [xml]$pdpXml = Get-Content $pdpPath -Raw - $appStoreNameElement = $pdpXml.SelectSingleNode("//AppStoreName[@_locID]") + # Create namespace manager for XML with default namespace + $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) + $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") + + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) if ($appStoreNameElement) { - $appStoreNameElement.InnerText = $config.AppStoreName - Write-Verbose -Verbose "Updated AppStoreName to: $($config.AppStoreName)" + $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) + Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" } else { Write-Warning "AppStoreName element not found in PDP file" } $pdpXml.Save($pdpPath) Write-Verbose -Verbose "PDP file updated successfully" + Get-Content -Path $pdpPath | Write-Verbose -Verbose } else { Write-Error "PDP file not found: $pdpPath" exit 1 @@ -198,20 +206,21 @@ jobs: $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 Write-Verbose -Verbose "SBConfig file updated successfully" + Get-Content -Path $sbConfigPath | Write-Verbose -Verbose } else { Write-Error "SBConfig file not found: $sbConfigPath" exit 1 } Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SBConfigPath]$($config.SBConfigPath)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" name: UpdateConfigs displayName: Update PDPs and SBConfig.json - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package' inputs: - serviceEndpoint: '$(ServiceConnection)' + serviceEndpoint: 'StoreAppPublish-Private' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' @@ -219,6 +228,12 @@ jobs: pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + - pwsh: | + Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | + Copy-Item -Destination "$(ob_outputDirectory)" -Verbose + displayName: Upload Store Failure Log + condition: failed() + - pwsh: | $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" From 9850bc90ace0ea070129d4912e0e43efa540a339 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:43:49 -0500 Subject: [PATCH 080/378] Add crescan and tsa files in job --- .config/suppress.csk | 6 ++++++ .pipelines/templates/package-create-msix.yml | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 .config/suppress.csk diff --git a/.config/suppress.csk b/.config/suppress.csk new file mode 100644 index 00000000000..d51c3fea55c --- /dev/null +++ b/.config/suppress.csk @@ -0,0 +1,6 @@ +# CredScan suppression file +# Test certificate with private key +\\test\\tools\\Modules\\WebListener\\ClientCert.pfx +\\test\\tools\\Modules\\WebListener\\ServerCert.pfx +# Test certificate with private key and inline suppression isn't working +\\test\\powershell\\Modules\\Microsoft.PowerShell.Security\\certificateCommon.psm1 \ No newline at end of file diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 6573a04b9a7..d9d06260f41 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -8,6 +8,10 @@ jobs: - group: msixTools - group: 'Azure Blob variable group' - group: 'Store Publish Variables' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' From b5279a25a1ea4fced17cf58244ae8a294a80dc35 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Sun, 5 Oct 2025 23:48:42 -0500 Subject: [PATCH 081/378] Correct handling of explicit -Empty:$false parameter value in New-Guid (#26140) --- .../commands/utility/NewGuidCommand.cs | 2 +- .../Modules/Microsoft.PowerShell.Utility/New-Guid.Tests.ps1 | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs index 3aa070bcd62..c384b2a2578 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs @@ -49,7 +49,7 @@ protected override void ProcessRecord() } else { - guid = ParameterSetName is "Empty" ? Guid.Empty : Guid.NewGuid(); + guid = Empty.ToBool() ? Guid.Empty : Guid.NewGuid(); } WriteObject(guid); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/New-Guid.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/New-Guid.Tests.ps1 index 54d609d2753..8756fed7726 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/New-Guid.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/New-Guid.Tests.ps1 @@ -17,6 +17,11 @@ Describe "New-Guid" -Tags "CI" { $guid.ToString() | Should -BeExactly "00000000-0000-0000-0000-000000000000" } + It "Should respect explicit false value for -Empty" { + $guid = New-Guid -Empty:$false + $guid.ToString() | Should -Not -BeExactly "00000000-0000-0000-0000-000000000000" + } + It "Should convert a string to a guid" { $guid1 = New-Guid $guid2 = New-Guid -InputObject $guid1.ToString() From c24752e496b011ecc9859df635094f335c0b5a69 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:06:15 -0500 Subject: [PATCH 082/378] Convert ADO variables to booleans --- .config/suppress.csk | 6 ------ .pipelines/templates/release-MSIX-Publish.yml | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 .config/suppress.csk diff --git a/.config/suppress.csk b/.config/suppress.csk deleted file mode 100644 index d51c3fea55c..00000000000 --- a/.config/suppress.csk +++ /dev/null @@ -1,6 +0,0 @@ -# CredScan suppression file -# Test certificate with private key -\\test\\tools\\Modules\\WebListener\\ClientCert.pfx -\\test\\tools\\Modules\\WebListener\\ServerCert.pfx -# Test certificate with private key and inline suppression isn't working -\\test\\powershell\\Modules\\Microsoft.PowerShell.Security\\certificateCommon.psm1 \ No newline at end of file diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 9a0dba8833f..245d756eeca 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -63,6 +63,11 @@ jobs: inputs: targetType: inline script: | + # Convert ADO variables to PowerShell boolean variables + $IsLTS = '$(LTS)' -eq 'true' + $IsStable = '$(STABLE)' -eq 'true' + $IsPreview = '$(PREVIEW)' -eq 'true' + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" # Define app configurations for each channel using secret variables From d57e0890f49b43c2e31ae448731b8b2d40c40a9a Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:11:31 -0500 Subject: [PATCH 083/378] Declare variables separately --- .pipelines/templates/release-MSIX-Publish.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 245d756eeca..c43ae1d8410 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -15,12 +15,15 @@ jobs: artifactName: drop_msixbundle_CreateMSIXBundle variables: - group: 'Store Publish Variables' + - name: LTS + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] + - name: STABLE + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] + - name: PREVIEW + value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - template: ./variable/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] - LTS: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsLTS'] ] - STABLE: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] - PREVIEW: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] steps: - task: PowerShell@2 inputs: From ba1256cd3160dd33de5d88da34bf5ff269d13654 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 6 Oct 2025 13:17:16 -0500 Subject: [PATCH 084/378] Use conditional tasks with hardcoded endpoints --- .pipelines/templates/release-MSIX-Publish.yml | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index c43ae1d8410..08123ea8074 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -22,8 +22,6 @@ jobs: - name: PREVIEW value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - template: ./variable/release-shared.yml@self - parameters: - RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: - task: PowerShell@2 inputs: @@ -71,25 +69,9 @@ jobs: $IsStable = '$(STABLE)' -eq 'true' $IsPreview = '$(PREVIEW)' -eq 'true' - Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(STABLE), Preview: $(PREVIEW)" - # Define app configurations for each channel using secret variables - $channelConfigs = @{ - 'LTS' = @{ - AppId = '$(AppID-LTS)' - ServiceEndpoint = 'StoreAppPublish-Stable' - } - 'Stable' = @{ - AppId = '$(AppID-Stable)' - ServiceEndpoint = 'StoreAppPublish-Stable' - } - 'Preview' = @{ - AppId = '$(AppID-Preview)' - ServiceEndpoint = 'StoreAppPublish-Preview' - } - } - - # Determine the current channel + # Determine the current channel for logging purposes $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -98,23 +80,42 @@ jobs: exit 1 } - $config = $channelConfigs[$currentChannel] Write-Verbose -Verbose "Selected channel: $currentChannel" - Write-Verbose -Verbose "App ID: $($config.AppId)" - Write-Verbose -Verbose "Service Endpoint: $($config.ServiceEndpoint)" - - # Set pipeline variables for use in the store-publish task - Write-Host "##vso[task.setvariable variable=SelectedAppId]$($config.AppId)" - Write-Host "##vso[task.setvariable variable=SelectedServiceEndpoint]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SelectedChannel]$currentChannel" - displayName: 'Set StoreBroker Configurations' + Write-Verbose -Verbose "Conditional tasks will handle the publishing based on channel variables" + displayName: 'Validate Channel Selection' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish LTS StoreBroker Package' - condition: ne('${{ parameters.skipMSIXPublish }}', 'true') + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID-LTS)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish Stable StoreBroker Package' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID-Stable)' + inputMethod: JsonAndZip + jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' + zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + numberOfPackagesToKeep: 2 + jsonZipUpdateMetadata: true + targetPublishMode: 'Immediate' + + - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 + displayName: 'Publish Preview StoreBroker Package' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) inputs: - serviceEndpoint: '$(SelectedServiceEndpoint)' - appId: '$(SelectedAppId)' + serviceEndpoint: 'StoreAppPublish-Preview' + appId: '$(AppID-Preview)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' From 92beb64c148ee64ebe63c1a2e0ae61fb5c2580fc Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 6 Oct 2025 11:57:03 -0700 Subject: [PATCH 085/378] Add Start-PSBootstrap to add installed dotnet to path --- .pipelines/templates/release-validate-globaltools.yml | 3 +++ .pipelines/templates/release-validate-sdk.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 4a7d23c8b4b..083c98c3930 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -43,6 +43,9 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "dotnet tool list -g" diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index 4089d54e51b..3b0442f65d6 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -51,6 +51,9 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)" + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + $env:DOTNET_NOLOGO=1 $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" From 60d4bc39bc5c2b8d1b7db41d86c06272788740ba Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 7 Oct 2025 10:28:19 +0100 Subject: [PATCH 086/378] Fix memory leak in `GetFileShares` (#25896) --- .../CommandCompletion/CompletionCompleters.cs | 58 +++++++++++-------- .../Interop/Windows/NetApiBufferFree.cs | 16 +++++ 2 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 src/System.Management.Automation/engine/Interop/Windows/NetApiBufferFree.cs diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 8ca133cf1c2..2b90bc02837 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -5204,38 +5204,48 @@ internal static List GetFileShares(string machine, bool ignoreHidden) uint numEntries = 0; uint totalEntries; uint resumeHandle = 0; - int result = Interop.Windows.NetShareEnum( - machine, - level: 1, - out shBuf, - Interop.Windows.MAX_PREFERRED_LENGTH, - out numEntries, - out totalEntries, - ref resumeHandle); - - var shares = new List(); - if (result == Interop.Windows.ERROR_SUCCESS || result == Interop.Windows.ERROR_MORE_DATA) + try { - for (int i = 0; i < numEntries; ++i) - { - nint curInfoPtr = shBuf + (Marshal.SizeOf() * i); - SHARE_INFO_1 shareInfo = Marshal.PtrToStructure(curInfoPtr); + int result = Interop.Windows.NetShareEnum( + machine, + level: 1, + out shBuf, + Interop.Windows.MAX_PREFERRED_LENGTH, + out numEntries, + out totalEntries, + ref resumeHandle); - if ((shareInfo.type & Interop.Windows.STYPE_MASK) != Interop.Windows.STYPE_DISKTREE) + var shares = new List(); + if (result == Interop.Windows.ERROR_SUCCESS || result == Interop.Windows.ERROR_MORE_DATA) + { + for (int i = 0; i < numEntries; ++i) { - continue; - } + nint curInfoPtr = shBuf + (Marshal.SizeOf() * i); + SHARE_INFO_1 shareInfo = Marshal.PtrToStructure(curInfoPtr); - if (ignoreHidden && shareInfo.netname.EndsWith('$')) - { - continue; + if ((shareInfo.type & Interop.Windows.STYPE_MASK) != Interop.Windows.STYPE_DISKTREE) + { + continue; + } + + if (ignoreHidden && shareInfo.netname.EndsWith('$')) + { + continue; + } + + shares.Add(shareInfo.netname); } + } - shares.Add(shareInfo.netname); + return shares; + } + finally + { + if (shBuf != nint.Zero) + { + Interop.Windows.NetApiBufferFree(shBuf); } } - - return shares; #endif } diff --git a/src/System.Management.Automation/engine/Interop/Windows/NetApiBufferFree.cs b/src/System.Management.Automation/engine/Interop/Windows/NetApiBufferFree.cs new file mode 100644 index 00000000000..4f7d0541872 --- /dev/null +++ b/src/System.Management.Automation/engine/Interop/Windows/NetApiBufferFree.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#nullable enable + +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static unsafe partial class Windows + { + + [LibraryImport("Netapi32.dll")] + internal static partial uint NetApiBufferFree(nint Buffer); + } +} From d042a280b621072958ceae703cdf116b9d35b34c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 7 Oct 2025 19:50:42 +0000 Subject: [PATCH 087/378] Merged PR 37066: Update the test image for SDK tests Update the test image for SDK tests ---- #### AI description (iteration 1) #### PR Classification This PR is a configuration update aimed at improving SDK test reliability by using an updated Ubuntu test image. #### PR Summary The pull request updates the pipeline configuration to reference a new test image version for SDK validation. - `.pipelines/PowerShell-Release-Official.yml`: Changed `imageName` from `PSMMSUbuntu20.04-Secure` to `PSMMSUbuntu22.04-Secure`. --- .pipelines/PowerShell-Release-Official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 36bee13a0c7..c54fc99a0b7 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -156,7 +156,7 @@ extends: parameters: jobName: "LinuxSDK" displayName: "Linux SDK Validation" - imageName: PSMMSUbuntu20.04-Secure + imageName: PSMMSUbuntu22.04-Secure poolName: $(ubuntuPool) - stage: gbltool From f1e2301e7fe384b7ee13fcc5d19dda17c808d101 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 7 Oct 2025 13:16:06 -0700 Subject: [PATCH 088/378] Add bootstrap to global tool validation step --- .pipelines/templates/release-validate-globaltools.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml index 083c98c3930..8c2031d5cc9 100644 --- a/.pipelines/templates/release-validate-globaltools.yml +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -78,6 +78,9 @@ jobs: - pwsh: | $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + Import-Module "$repoRoot/build.psm1" -Force -Verbose + Start-PSBootstrap -Scenario Dotnet + $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" From 06ddfe35af12e7ce2af61eef3cf73996a21d2c63 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 7 Oct 2025 13:52:34 -0700 Subject: [PATCH 089/378] Update ChangeLog for v7.6.0-preview.5 release (#26126) --- CHANGELOG/preview.md | 209 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 2663b2e5f0c..236e8da3918 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,214 @@ # Preview Changelog +## [7.6.0-preview.5] - 2025-09-30 + +### Engine Updates and Fixes + +- Allow opt-out of the named-pipe listener using the environment variable `POWERSHELL_DIAGNOSTICS_OPTOUT` (#26086) +- Ensure that socket timeouts are set only during the token validation (#26066) +- Fix race condition in `RemoteHyperVSocket` (#26057) +- Fix `stderr` output of console host to respect `NO_COLOR` (#24391) +- Update PSRP protocol to deprecate session key exchange between newer client and server (#25774) +- Fix the `ssh` PATH check in `SSHConnectionInfo` when the default Runspace is not available (#25780) (Thanks @jborean93!) +- Adding hex format for native command exit codes (#21067) (Thanks @sba923!) +- Fix infinite loop crash in variable type inference (#25696) (Thanks @MartinGC94!) +- Add `PSForEach` and `PSWhere` as aliases for the PowerShell intrinsic methods `Where` and `Foreach` (#25511) (Thanks @powercode!) + +### General Cmdlet Updates and Fixes + +- Remove `IsScreenReaderActive()` check from `ConsoleHost` (#26118) +- Fix `ConvertFrom-Json` to ignore comments inside array literals (#14553) (#26050) (Thanks @MatejKafka!) +- Fix `-Debug` to not trigger the `ShouldProcess` prompt (#26081) +- Add the parameter `Register-ArgumentCompleter -NativeFallback` to support registering a cover-all completer for native commands (#25230) +- Change the default feedback provider timeout from 300ms to 1000ms (#25910) +- Update PATH environment variable for package manager executable on Windows (#25847) +- Fix `Write-Host` to respect `OutputRendering = PlainText` (#21188) +- Improve the `$using` expression support in `Invoke-Command` (#24025) (Thanks @jborean93!) +- Use parameter `HelpMessage` for tool tip in parameter completion (#25108) (Thanks @jborean93!) +- Revert "Never load a module targeting the PSReadLine module's `SessionState`" (#25792) +- Fix debug tracing error with magic extents (#25726) (Thanks @jborean93!) +- Add `MethodInvocation` trace for overload tracing (#21320) (Thanks @jborean93!) +- Improve verbose and debug logging level messaging in web cmdlets (#25510) (Thanks @JustinGrote!) +- Fix quoting in completion if the path includes a double quote character (#25631) (Thanks @MartinGC94!) +- Fix the common parameter `-ProgressAction` for advanced functions (#24591) (Thanks @cmkb3!) +- Use absolute path in `FileSystemProvider.CreateDirectory` (#24615) (Thanks @Tadas!) +- Make inherited protected internal instance members accessible in PowerShell class scope (#25245) (Thanks @mawosoft!) +- Treat `-Target` as literal in `New-Item` (#25186) (Thanks @GameMicrowave!) +- Remove duplicate modules from completion results (#25538) (Thanks @MartinGC94!) +- Add completion for variables assigned in `ArrayLiteralAst` and `ParenExpressionAst` (#25303) (Thanks @MartinGC94!) +- Add support for thousands separators in `[bigint]` casting (#25396) (Thanks @AbishekPonmudi!) +- Add internal methods to check Preferences (#25514) (Thanks @iSazonov!) +- Improve debug logging of Web cmdlet request and response (#25479) (Thanks @JustinGrote!) +- Revert "Allow empty prefix string in 'Import-Module -Prefix' to override default prefix in manifest (#20409)" (#25462) (Thanks @MartinGC94!) +- Fix the `NullReferenceException` when writing progress records to console from multiple threads (#25440) (Thanks @kborowinski!) +- Update `Get-Service` to ignore common errors when retrieving non-critical properties for a service (#24245) (Thanks @jborean93!) +- Add single/double quote support for `Join-String` Argument Completer (#25283) (Thanks @ArmaanMcleod!) +- Fix tab completion for env/function variables (#25346) (Thanks @jborean93!) +- Fix `Out-GridView` by replacing use of obsolete `BinaryFormatter` with custom implementation (#25497) (Thanks @mawosoft!) +- Remove the use of Windows PowerShell ETW provider id from code base and update the `PSDiagnostics` module to work for PowerShell 7 (#25590) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @xtqqczze, @mawosoft, @ArmaanMcleod

    + +
    + +
      +
    • Enable CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types (#25813) (Thanks @xtqqczze!)
    • +
    • Remove some unused ConsoleControl structs (#26063) (Thanks @xtqqczze!)
    • +
    • Remove unused FileStreamBackReader.NativeMethods type (#26062) (Thanks @xtqqczze!)
    • +
    • Ensure data-serialization files end with one newline (#26039) (Thanks @xtqqczze!)
    • +
    • Remove unnecessary CS0618 suppressions from Variant APIs (#26006) (Thanks @xtqqczze!)
    • +
    • Ensure .cs files end with exactly one newline (#25968) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2105 rule suppression (#25938) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1703 rule suppression (#25955) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2240 rule suppression (#25957) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1701 rule suppression (#25948) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2233 rule suppression (#25951) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1026 rule suppression (#25934) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1059 rule suppression (#25940) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2118 rule suppression (#25924) (Thanks @xtqqczze!)
    • +
    • Remove redundant System.Runtime.Versioning attributes (#25926) (Thanks @xtqqczze!)
    • +
    • Seal internal types in Microsoft.PowerShell.Commands.Utility (#25892) (Thanks @xtqqczze!)
    • +
    • Seal internal types in Microsoft.PowerShell.Commands.Management (#25849) (Thanks @xtqqczze!)
    • +
    • Make the interface IDeepCloneable internal to minimize confusion (#25552)
    • +
    • Remove OnDeserialized and Serializable attributes from Microsoft.Management.UI.Internal project (#25548)
    • +
    • Refactor Tooltip/ListItemText mapping to use CompletionDisplayInfoMapper delegate (#25395) (Thanks @ArmaanMcleod!)
    • +
    + +
    + +### Tools + +- Add Codeql Suppressions (#25943, #26132) +- Update CODEOWNERS to add Justin as a maintainer (#25386) +- Do not run labels workflow in the internal repo (#25279) + +### Tests + +- Mark the 3 consistently failing tests as pending to unblock PRs (#26091) +- Make some tests less noisy on failure (#26035) (Thanks @xtqqczze!) +- Suppress false positive `PSScriptAnalyzer` warnings in tests and build scripts (#25864) +- Fix updatable help test for new content (#25819) +- Add more tests for `PSForEach` and `PSWhere` methods (#25519) +- Fix the isolated module test that was disabled previously (#25420) + +### Build and Packaging Improvements + +
    + + + +

    We thank the following contributors!

    +

    @alerickson, @senerh, @RichardSlater, @xtqqczze

    + +
    + +
      +
    • Update package references for the master branch (#26124)
    • +
    • Remove ThreadJob module and update PSReadLine to 2.4.4-beta4 (#26120)
    • +
    • Automate Store Publishing (#25725)
    • +
    • Add global config change detection to action (#26082)
    • +
    • Update outdated package references (#26069)
    • +
    • Ensure that the workflows are triggered on .globalconfig and other files at the root of the repo (#26034)
    • +
    • Update Microsoft.PowerShell.PSResourceGet to 1.2.0-preview3 (#26056) (Thanks @alerickson!)
    • +
    • Update metadata for Stable to v7.5.3 and LTS to v7.4.12 (#26054) (Thanks @senerh!)
    • +
    • Bump github/codeql-action from 3.30.2 to 3.30.3 (#26036)
    • +
    • Update version for the package Microsoft.PowerShell.Native (#26041)
    • +
    • Fix the APIScan pipeline (#26016)
    • +
    • Move PowerShell build to use .NET SDK 10.0.100-rc.1 (#26027)
    • +
    • fix(apt-package): add libicu76 dependency to support Debian 13 (#25866) (Thanks @RichardSlater!)
    • +
    • Bump github/codeql-action from 3.30.1 to 3.30.2 (#26029)
    • +
    • Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26025)
    • +
    • Bump github/codeql-action from 3.30.0 to 3.30.1 (#26008)
    • +
    • Bump actions/github-script from 7 to 8 (#25983)
    • +
    • Fix variable reference for release environment in pipeline (#26012)
    • +
    • Add LinuxHost Network configuration to PowerShell Packages pipeline (#26000)
    • +
    • Make logical template name consistent between pipelines (#25990)
    • +
    • Update container images to use mcr.microsoft.com for Linux and Azure GǪ (#25981)
    • +
    • Bump github/codeql-action from 3.29.11 to 3.30.0 (#25966)
    • +
    • Bump actions/setup-dotnet from 4 to 5 (#25978)
    • +
    • Add build to vPack Pipeline (#25915)
    • +
    • Replace DOTNET_SKIP_FIRST_TIME_EXPERIENCE with DOTNET_NOLOGO (#25946) (Thanks @xtqqczze!)
    • +
    • Bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#25930)
    • +
    • Bump github/codeql-action from 3.29.10 to 3.29.11 (#25889)
    • +
    • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25885)
    • +
    • Specify .NET Search by Build Type (#25837)
    • +
    • Update PowerShell to use .NET SDK v10-preview.7 (#25876)
    • +
    • Bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#25882)
    • +
    • Bump github/codeql-action from 3.29.9 to 3.29.10 (#25881)
    • +
    • Change the macos runner image to macos 15 large (#25867)
    • +
    • Bump actions/checkout from 4 to 5 (#25853)
    • +
    • Bump github/codeql-action from 3.29.7 to 3.29.9 (#25857)
    • +
    • Update to .NET 10 Preview 6 (#25828)
    • +
    • Bump agrc/create-reminder-action from 1.1.20 to 1.1.22 (#25808)
    • +
    • Bump agrc/reminder-action from 1.0.17 to 1.0.18 (#25807)
    • +
    • Bump github/codeql-action from 3.28.19 to 3.29.5 (#25797)
    • +
    • Bump super-linter/super-linter from 7.4.0 to 8.0.0 (#25770)
    • +
    • Update metadata for v7.5.2 and v7.4.11 releases (#25687)
    • +
    • Correct Capitalization Referencing Templates (#25669)
    • +
    • Change linux packaging tests to ubuntu latest (#25634)
    • +
    • Bump github/codeql-action from 3.28.18 to 3.28.19 (#25636)
    • +
    • Move to .NET 10 preview 4 and update package references (#25602)
    • +
    • Revert "Add windows signing for pwsh.exe" (#25586)
    • +
    • Bump ossf/scorecard-action from 2.4.1 to 2.4.2 (#25628)
    • +
    • Publish .msixbundle package as a VPack (#25612)
    • +
    • Bump agrc/reminder-action from 1.0.16 to 1.0.17 (#25573)
    • +
    • Bump agrc/create-reminder-action from 1.1.18 to 1.1.20 (#25572)
    • +
    • Bump github/codeql-action from 3.28.17 to 3.28.18 (#25580)
    • +
    • Bump super-linter/super-linter from 7.3.0 to 7.4.0 (#25563)
    • +
    • Bump actions/dependency-review-action from 4.7.0 to 4.7.1 (#25562)
    • +
    • Update metadata.json with 7.4.10 (#25554)
    • +
    • Bump github/codeql-action from 3.28.16 to 3.28.17 (#25508)
    • +
    • Bump actions/dependency-review-action from 4.6.0 to 4.7.0 (#25529)
    • +
    • Move MSIXBundle to Packages and Release to GitHub (#25512)
    • +
    • Update outdated package references (#25506)
    • +
    • Bump github/codeql-action from 3.28.15 to 3.28.16 (#25429)
    • +
    • Fix Conditional Parameter to Skip NuGet Publish (#25468)
    • +
    • Update metadata.json (#25438)
    • +
    • Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25437)
    • +
    • Use new variables template for vPack (#25434)
    • +
    • Bump agrc/create-reminder-action from 1.1.17 to 1.1.18 (#25416)
    • +
    • Add PSScriptAnalyzer (#25423)
    • +
    • Update outdated package references (#25392)
    • +
    • Use GitHubReleaseTask instead of custom script (#25398)
    • +
    • Update APIScan to use new symbols server (#25388)
    • +
    • Retry ClearlyDefined operations (#25385)
    • +
    • Update to .NET 10.0.100-preview.3 (#25358)
    • +
    • Enhance path filters action to set outputs for all changes when not a PR (#25367)
    • +
    • Combine GitHub and Nuget Release Stage (#25318)
    • +
    • Add Windows Store Signing to MSIX bundle (#25296)
    • +
    • Bump skitionek/notify-microsoft-teams from 190d4d92146df11f854709774a4dae6eaf5e2aa3 to e7a2493ac87dad8aa7a62f079f295e54ff511d88 (#25366)
    • +
    • Add CodeQL suppressions for PowerShell intended behavior (#25359)
    • +
    • Migrate MacOS Signing to OneBranch (#25295)
    • +
    • Bump github/codeql-action from 3.28.13 to 3.28.15 (#25290)
    • +
    • Update test result processing to use NUnitXml format and enhance logging for better clarity (#25288)
    • +
    • Fix R2R for fxdependent packaging (#26131)
    • +
    • Remove UseDotnet task and use the dotnet-install script (#26093)
    • +
    + +
    + +### Documentation and Help Content + +- Fix a typo in the 7.4 changelog (#26038) (Thanks @VbhvGupta!) +- Add 7.4.12 Changelog (#26011) +- Add v7.5.3 Changelog (#25994) +- Fix typo in CHANGELOG for script filename suggestion (#25962) +- Update CHANGELOG for v7.5.2 (#25668) +- Update CHANGELOG for v7.4.11 (#25667) +- Update build documentation with instruction of dev terminal (#25587) +- Update links and contribution guide in documentation (#25532) (Thanks @JustinGrote!) +- Add 7.4.10 Changelog (#25520) +- Add 7.5.1 Change log (#25382) + +[7.6.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.4...v7.6.0-preview.5 + ## [7.6.0-preview.4] ### Breaking Changes From 0ef738b36f71bc1cfacd9f5149e6af325153302b Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Wed, 8 Oct 2025 08:34:15 +1000 Subject: [PATCH 090/378] Add property and event for debug attach (#25788) Adds the `IsRemoteDebuggerAttached` property to `Runspace` that indicates whether a debugger is attached to the Runspace through the `Debug-Runspace` cmdlet. Also adds a new engine event `PowerShell.OnDebugAttach` that is emitted when the debugger is attached. --- .../commands/utility/DebugRunspaceCommand.cs | 10 +++++++ .../engine/EventManager.cs | 7 ++++- .../engine/hostifaces/Connection.cs | 6 +++++ .../Debug-Runspace.Tests.ps1 | 27 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs index f5d84dfd195..756afff13de 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs @@ -265,6 +265,15 @@ private void WaitAndReceiveRunspaceOutput() // Set up host script debugger to debug the runspace. _debugger.DebugRunspace(_runspace, breakAll: BreakAll); + _runspace.IsRemoteDebuggerAttached = true; + _runspace.Events?.GenerateEvent( + PSEngineEvent.OnDebugAttach, + sender: null, + args: Array.Empty(), + extraData: null, + processInCurrentThread: true, + waitForCompletionInCurrentThread: false); + while (_debugging) { // Wait for running script. @@ -307,6 +316,7 @@ private void WaitAndReceiveRunspaceOutput() { _runspace.AvailabilityChanged -= HandleRunspaceAvailabilityChanged; _debugger.NestedDebuggingCancelledEvent -= HandleDebuggerNestedDebuggingCancelledEvent; + _runspace.IsRemoteDebuggerAttached = false; _debugger.StopDebugRunspace(_runspace); _newRunningScriptEvent.Dispose(); } diff --git a/src/System.Management.Automation/engine/EventManager.cs b/src/System.Management.Automation/engine/EventManager.cs index 75538135b92..e72a34cef1c 100644 --- a/src/System.Management.Automation/engine/EventManager.cs +++ b/src/System.Management.Automation/engine/EventManager.cs @@ -1830,6 +1830,11 @@ private PSEngineEvent() { } /// public const string OnIdle = "PowerShell.OnIdle"; + /// + /// Called when Debug-Runspace has attached a debugger to the current runspace. + /// + public const string OnDebugAttach = "PowerShell.OnDebugAttach"; + /// /// Called during scriptblock invocation. /// @@ -1843,7 +1848,7 @@ private PSEngineEvent() { } /// /// A HashSet that contains all engine event names. /// - internal static readonly HashSet EngineEvents = new HashSet(StringComparer.OrdinalIgnoreCase) { Exiting, OnIdle, OnScriptBlockInvoke }; + internal static readonly HashSet EngineEvents = new HashSet(StringComparer.OrdinalIgnoreCase) { Exiting, OnIdle, OnDebugAttach, OnScriptBlockInvoke }; } /// diff --git a/src/System.Management.Automation/engine/hostifaces/Connection.cs b/src/System.Management.Automation/engine/hostifaces/Connection.cs index 3f5911d1c62..ccb918c7dd9 100644 --- a/src/System.Management.Automation/engine/hostifaces/Connection.cs +++ b/src/System.Management.Automation/engine/hostifaces/Connection.cs @@ -761,6 +761,12 @@ public string Name /// Gets the Runspace Id. /// public int Id { get; } + + /// + /// Gets and sets a boolean indicating whether the runspace has a + /// debugger attached with Debug-Runspace. + /// + public bool IsRemoteDebuggerAttached { get; internal set; } /// /// Returns protocol version that the remote server uses for PS remoting. diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Debug-Runspace.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Debug-Runspace.Tests.ps1 index 8aa28b00aef..2b517e4f301 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Debug-Runspace.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Debug-Runspace.Tests.ps1 @@ -31,6 +31,33 @@ Describe "Debug-Runspace" -Tag "CI" { $rs1.Debugger.SetDebugMode("None") { Debug-Runspace -Runspace $rs1 -ErrorAction stop } | Should -Throw -ErrorId "InvalidOperation,Microsoft.PowerShell.Commands.DebugRunspaceCommand" } + + It "Should write attach event and mark runspace as having a remote debugger attached" { + $onAttachName = [System.Management.Automation.PSEngineEvent]::OnDebugAttach + + $debugTarget = [PowerShell]::Create() + $null = $debugTarget.AddCommand('Wait-Event').AddParameter('SourceIdentifier', $onAttachName) + $waitTask = $debugTarget.BeginInvoke() + $debugTarget.Runspace.IsRemoteDebuggerAttached | Should -BeFalse + + $debugger = [PowerShell]::Create() + $null = $debugger.AddCommand('Debug-Runspace').AddParameter('Id', $debugTarget.Runspace.Id) + $debugTask = $debugger.BeginInvoke() + + $waitTask.AsyncWaitHandle.WaitOne(5000) | Should -BeTrue + $waitInfo = $debugTarget.EndInvoke($waitTask) + $waitInfo.SourceIdentifier | Should -Be $onAttachName + + $debugTarget.Runspace.IsRemoteDebuggerAttached | Should -BeTrue + + $debugger.Stop() + $exp = { + $debugger.EndInvoke($debugTask) + } | Should -Throw -PassThru + $exp.FullyQualifiedErrorId | Should -Be "PipelineStoppedException" + + $debugTarget.Runspace.IsRemoteDebuggerAttached | Should -BeFalse + } } From 5cdafbc4c7840dedfd5c9490ddb2e0619d0a2a23 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 8 Oct 2025 04:22:54 +0100 Subject: [PATCH 091/378] Enable CA1858: Use 'StartsWith' instead of 'IndexOf' (#26107) --- .globalconfig | 4 ++++ .../security/SecureStringCommands.cs | 3 +-- .../namespaces/FileSystemProvider.cs | 2 +- .../namespaces/LocationGlobber.cs | 4 ++-- src/System.Management.Automation/security/Authenticode.cs | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.globalconfig b/.globalconfig index fe6b1a03a95..6929917b659 100644 --- a/.globalconfig +++ b/.globalconfig @@ -510,6 +510,10 @@ dotnet_diagnostic.CA1846.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1847 dotnet_diagnostic.CA1847.severity = warning +# CA1858: Use 'StartsWith' instead of 'IndexOf' +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1858 +dotnet_diagnostic.CA1858.severity = warning + # CA1868: Unnecessary call to 'Contains' for sets # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1868 dotnet_diagnostic.CA1868.severity = warning diff --git a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs index c727476c0a3..29179a7046d 100644 --- a/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/SecureStringCommands.cs @@ -311,8 +311,7 @@ protected override void ProcessRecord() byte[] iv = null; // If this is a V2 package - if (String.IndexOf(SecureStringHelper.SecureStringExportHeader, - StringComparison.OrdinalIgnoreCase) == 0) + if (String.StartsWith(SecureStringHelper.SecureStringExportHeader, StringComparison.OrdinalIgnoreCase)) { try { diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index c5df7a9339a..56c8a074334 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8286,7 +8286,7 @@ internal static void DeleteFileStream(string path, string streamName) ArgumentNullException.ThrowIfNull(streamName); string adjustedStreamName = streamName.Trim(); - if (adjustedStreamName.IndexOf(':') != 0) + if (!adjustedStreamName.StartsWith(':')) { adjustedStreamName = ":" + adjustedStreamName; } diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index 19377985c81..65c28f1586d 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -4539,7 +4539,7 @@ internal static bool IsHomePath(string path) } } - if (path.IndexOf(StringLiterals.HomePath, StringComparison.Ordinal) == 0) + if (path.StartsWith(StringLiterals.HomePath, StringComparison.Ordinal)) { // Support the single "~" if (path.Length == 1) @@ -4638,7 +4638,7 @@ internal string GetHomeRelativePath(string path) } } - if (path.IndexOf(StringLiterals.HomePath, StringComparison.Ordinal) == 0) + if (path.StartsWith(StringLiterals.HomePath, StringComparison.Ordinal)) { // Strip of the ~ and the \ or / if present diff --git a/src/System.Management.Automation/security/Authenticode.cs b/src/System.Management.Automation/security/Authenticode.cs index 591f64d6298..3a7720616d1 100644 --- a/src/System.Management.Automation/security/Authenticode.cs +++ b/src/System.Management.Automation/security/Authenticode.cs @@ -115,8 +115,8 @@ internal static Signature SignFile(SigningOption option, if (!string.IsNullOrEmpty(timeStampServerUrl)) { if ((timeStampServerUrl.Length <= 7) || ( - (timeStampServerUrl.IndexOf("http://", StringComparison.OrdinalIgnoreCase) != 0) && - (timeStampServerUrl.IndexOf("https://", StringComparison.OrdinalIgnoreCase) != 0))) + !timeStampServerUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && + !timeStampServerUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))) { throw PSTraceSource.NewArgumentException( nameof(certificate), From db77d2ede54e54f0bca8a59d88a0ba217156b028 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 8 Oct 2025 05:10:48 +0100 Subject: [PATCH 092/378] Enable CA1860: Avoid using 'Enumerable.Any()' extension method (#26109) --- .globalconfig | 4 ++++ src/System.Management.Automation/engine/MshObject.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index 6929917b659..c0035a9bfd8 100644 --- a/.globalconfig +++ b/.globalconfig @@ -514,6 +514,10 @@ dotnet_diagnostic.CA1847.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1858 dotnet_diagnostic.CA1858.severity = warning +# CA1860: Avoid using 'Enumerable.Any()' extension method +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1860 +dotnet_diagnostic.CA1860.severity = warning + # CA1868: Unnecessary call to 'Contains' for sets # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1868 dotnet_diagnostic.CA1868.severity = warning diff --git a/src/System.Management.Automation/engine/MshObject.cs b/src/System.Management.Automation/engine/MshObject.cs index 8303058759d..d788a8a3b43 100644 --- a/src/System.Management.Automation/engine/MshObject.cs +++ b/src/System.Management.Automation/engine/MshObject.cs @@ -1611,7 +1611,7 @@ public virtual PSObject Copy() bool needToReAddInstanceMembersAndTypeNames = !object.ReferenceEquals(GetKeyForResurrectionTables(this), GetKeyForResurrectionTables(returnValue)); if (needToReAddInstanceMembersAndTypeNames) { - Diagnostics.Assert(!returnValue.InstanceMembers.Any(), "needToReAddInstanceMembersAndTypeNames should mean that the new object has a fresh/empty list of instance members"); + Diagnostics.Assert(returnValue.InstanceMembers.Count == 0, "needToReAddInstanceMembersAndTypeNames should mean that the new object has a fresh/empty list of instance members"); foreach (PSMemberInfo member in this.InstanceMembers) { if (member.IsHidden) From 571537c34fc16b08dc85213fb73eee8a90925f33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:40:01 -0700 Subject: [PATCH 093/378] Bump github/codeql-action from 3.30.3 to 4.30.7 (#26159) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 30f5acd5619..5c2118ef7be 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -192,7 +192,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -218,7 +218,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 237a05d3479..a9879816135 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + uses: github/codeql-action/upload-sarif@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 with: sarif_file: results.sarif From f247d802dd89495d786994a47eb2ee8f852bc97d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 21:03:36 +0000 Subject: [PATCH 094/378] Bump ossf/scorecard-action from 2.4.2 to 2.4.3 (#26128) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a9879816135..a168f12319f 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif From d581baabd4e70c89e0370fb95d0f81aefbf06463 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:41:08 +0100 Subject: [PATCH 095/378] Check for `GetWindowPlacement` success (#26122) --- test/powershell/Host/ConsoleHost.Tests.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index fffd959654b..ee501a83b63 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -985,7 +985,12 @@ public static WINDOWPLACEMENT GetPlacement(IntPtr hwnd) { WINDOWPLACEMENT placement = new WINDOWPLACEMENT(); placement.length = Marshal.SizeOf(placement); - GetWindowPlacement(hwnd, ref placement); + + if (!GetWindowPlacement(hwnd, ref placement)) + { + throw new System.ComponentModel.Win32Exception(); + } + return placement; } From e562d3f39a84f5f6c0350a956db4f09bde347040 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Thu, 9 Oct 2025 05:48:52 -0500 Subject: [PATCH 096/378] Correct handling of explicit -Since:$false parameter value in Get-Uptime (#26141) --- .../commands/utility/GetUptime.cs | 17 ++++++++--------- .../Get-Uptime.Tests.ps1 | 4 ++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs index e8dcfbe254a..c21165301e2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetUptime.cs @@ -36,16 +36,15 @@ protected override void ProcessRecord() { TimeSpan uptime = TimeSpan.FromSeconds(Stopwatch.GetTimestamp() / Stopwatch.Frequency); - switch (ParameterSetName) + if (Since) { - case TimespanParameterSet: - // return TimeSpan of time since the system started up - WriteObject(uptime); - break; - case SinceParameterSet: - // return Datetime when the system started up - WriteObject(DateTime.Now.Subtract(uptime)); - break; + // Output the time of the last system boot. + WriteObject(DateTime.Now.Subtract(uptime)); + } + else + { + // Output the time elapsed since the last system boot. + WriteObject(uptime); } } else diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Uptime.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Uptime.Tests.ps1 index aff5e4d50af..b3275a61f2a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Uptime.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Uptime.Tests.ps1 @@ -25,6 +25,10 @@ Describe "Get-Uptime" -Tags "CI" { $upt = Get-Uptime -Since $upt | Should -BeOfType DateTime } + It "Get-Uptime -Since:`$false return TimeSpan" { + $upt = Get-Uptime -Since:$false + $upt | Should -BeOfType TimeSpan + } It "Get-Uptime throw if IsHighResolution == false" { # Enable the test hook [system.management.automation.internal.internaltesthooks]::SetTestHook('StopwatchIsNotHighResolution', $true) From a842b2ba11f7e17be738709c982f5e794070886a Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:34:49 +0100 Subject: [PATCH 097/378] Enable CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' (#26106) --- .globalconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.globalconfig b/.globalconfig index c0035a9bfd8..a0501d4cfa4 100644 --- a/.globalconfig +++ b/.globalconfig @@ -510,6 +510,10 @@ dotnet_diagnostic.CA1846.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1847 dotnet_diagnostic.CA1847.severity = warning +# CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1853 +dotnet_diagnostic.CA1853.severity = warning + # CA1858: Use 'StartsWith' instead of 'IndexOf' # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1858 dotnet_diagnostic.CA1858.severity = warning From cad2949d744eaf0f6618cf3d58b2c3c90bbcbd8c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Oct 2025 16:48:32 -0700 Subject: [PATCH 098/378] Update `metadata.json` for v7.6.0-preview.5 release (#26158) --- tools/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index 377b6ead763..f9339e276f2 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,10 +1,10 @@ { "StableReleaseTag": "v7.5.3", - "PreviewReleaseTag": "v7.6.0-preview.4", + "PreviewReleaseTag": "v7.6.0-preview.5", "ServicingReleaseTag": "v7.0.13", "ReleaseTag": "v7.5.3", "LTSReleaseTag" : ["v7.4.12"], - "NextReleaseTag": "v7.6.0-preview.5", + "NextReleaseTag": "v7.6.0-preview.6", "LTSRelease": { "Latest": false, "Package": false }, "StableRelease": { "Latest": false, "Package": false } } From 3207a744b5c86ffcfe68af201be30d449bfe1f34 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 10 Oct 2025 05:45:47 +0100 Subject: [PATCH 099/378] Disable IDE0049: PreferBuiltInOrFrameworkType (#26094) --- .globalconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index a0501d4cfa4..7e345757abf 100644 --- a/.globalconfig +++ b/.globalconfig @@ -1342,7 +1342,7 @@ dotnet_diagnostic.IDE0048.severity = suggestion # IDE0049: PreferBuiltInOrFrameworkType # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0049 -dotnet_diagnostic.IDE0049.severity = warning +dotnet_diagnostic.IDE0049.severity = suggestion # IDE0050: ConvertAnonymousTypeToTuple # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0050 From 38f7f937d27ec773376c64c0748ffbcb1133204f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:02:43 +0100 Subject: [PATCH 100/378] Enable `SA1206`: Declaration keywords should follow order (#24973) --- .globalconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index 7e345757abf..b125f70e254 100644 --- a/.globalconfig +++ b/.globalconfig @@ -1850,7 +1850,7 @@ dotnet_diagnostic.SA1205.severity = warning # SA1206: Declaration keywords should follow order # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1206.md -dotnet_diagnostic.SA1206.severity = none +dotnet_diagnostic.SA1206.severity = warning # SA1207: Protected should come before internal # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1207.md From 5e051759984c7be3c2274810ad3befb46cc76d03 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:51:44 -0500 Subject: [PATCH 101/378] Make MSIX publish stage dependent on SetReleaseTagandContainerName stage --- .pipelines/PowerShell-Release-Official.yml | 6 ++++-- .pipelines/templates/package-create-msix.yml | 14 +++++++------- .pipelines/templates/release-MSIX-Publish.yml | 17 ++++++++++++----- .pipelines/templates/release-githubNuget.yml | 4 ++-- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index c54fc99a0b7..ca6b79335dd 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -365,10 +365,12 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: PushGitTagAndMakeDraftPublic + dependsOn: + - setReleaseTagAndChangelog + - PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store variables: - ob_release_environment: Production + ob_release_environment: ${{ variables.releaseEnvironment }} jobs: - template: /.pipelines/templates/release-MSIX-Publish.yml@self parameters: diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index d9d06260f41..e464b612234 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -97,13 +97,13 @@ jobs: displayName: Create MsixBundle retryCountOnTaskFailure: 1 - # - task: onebranch.pipeline.signing@1 - # displayName: Sign MsixBundle - # inputs: - # command: 'sign' - # signing_profile: $(MSIXProfile) - # files_to_sign: '**/*.msixbundle' - # search_root: '$(BundleDir)' + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' - pwsh: | $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 08123ea8074..4d3e0cb41c8 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -22,6 +22,8 @@ jobs: - name: PREVIEW value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - template: ./variable/release-shared.yml@self + parameters: + RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: - task: PowerShell@2 inputs: @@ -41,14 +43,14 @@ jobs: } $middleURL = '' $tagString = "$(ReleaseTag)" - if ($tagString -match '-') { + if ($tagString -match '-preview') { $middleURL = "preview" } elseif ($tagString -match '(\d+\.\d+)') { $middleURL = $matches[1] } - $endURL = $tagString -replace '[v\.]','' + $endURL = $tagString -replace '^v|\.', '' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -88,7 +90,7 @@ jobs: displayName: 'Publish LTS StoreBroker Package' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Stable' + serviceEndpoint: 'StoreAppPublish-Private' appId: '$(AppID-LTS)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' @@ -101,7 +103,7 @@ jobs: displayName: 'Publish Stable StoreBroker Package' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Stable' + serviceEndpoint: 'StoreAppPublish-Private' appId: '$(AppID-Stable)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' @@ -114,7 +116,7 @@ jobs: displayName: 'Publish Preview StoreBroker Package' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Preview' + serviceEndpoint: 'StoreAppPublish-Private' appId: '$(AppID-Preview)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' @@ -122,3 +124,8 @@ jobs: numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + + - pwsh: | + Get-Content -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue + displayName: Upload Store Failure Log + condition: failed() diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index a8a874619a4..5f67ce6a9e4 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -121,13 +121,13 @@ jobs: $middleURL = '' $tagString = "$(ReleaseTag)" Write-Verbose -Verbose "Use the following command to push the tag:" - if ($tagString -match '-') { + if ($tagString -match '-preview') { $middleURL = "preview" } elseif ($tagString -match '(\d+\.\d+)') { $middleURL = $matches[1] } - $endURL = $tagString -replace '[v\.]','' + $endURL = $tagString -replace '^v|\.', '' $message = "https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "git tag -a $(ReleaseTag) $env:BUILD_SOURCEVERSION -m $message" displayName: Git Push Tag Command From 644f15eeef1a066aca0900ef67aa9bf15267a44c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 10 Oct 2025 15:06:44 -0700 Subject: [PATCH 102/378] Fix lint errors in preview.md --- CHANGELOG/preview.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 236e8da3918..0985f0decf4 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -45,7 +45,7 @@ - Add single/double quote support for `Join-String` Argument Completer (#25283) (Thanks @ArmaanMcleod!) - Fix tab completion for env/function variables (#25346) (Thanks @jborean93!) - Fix `Out-GridView` by replacing use of obsolete `BinaryFormatter` with custom implementation (#25497) (Thanks @mawosoft!) -- Remove the use of Windows PowerShell ETW provider id from code base and update the `PSDiagnostics` module to work for PowerShell 7 (#25590) +- Remove the use of Windows PowerShell ETW provider ID from codebase and update the `PSDiagnostics` module to work for PowerShell 7 (#25590) ### Code Cleanup @@ -87,7 +87,7 @@ - Add Codeql Suppressions (#25943, #26132) - Update CODEOWNERS to add Justin as a maintainer (#25386) -- Do not run labels workflow in the internal repo (#25279) +- Do not run labels workflow in the internal repository (#25279) ### Tests @@ -197,15 +197,15 @@ ### Documentation and Help Content - Fix a typo in the 7.4 changelog (#26038) (Thanks @VbhvGupta!) -- Add 7.4.12 Changelog (#26011) -- Add v7.5.3 Changelog (#25994) +- Add 7.4.12 changelog (#26011) +- Add v7.5.3 changelog (#25994) - Fix typo in CHANGELOG for script filename suggestion (#25962) - Update CHANGELOG for v7.5.2 (#25668) - Update CHANGELOG for v7.4.11 (#25667) - Update build documentation with instruction of dev terminal (#25587) - Update links and contribution guide in documentation (#25532) (Thanks @JustinGrote!) -- Add 7.4.10 Changelog (#25520) -- Add 7.5.1 Change log (#25382) +- Add 7.4.10 changelog (#25520) +- Add 7.5.1 changelog (#25382) [7.6.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.4...v7.6.0-preview.5 @@ -467,7 +467,7 @@ name, the **ThreadJob** v2.1.0 module is a proxy module that points to the ### Tools -- Added Justin Chung as Powershell team memeber on releaseTools.psm1 (#24672) +- Added Justin Chung as PowerShell team memeber on releaseTools.psm1 (#24672) ### Tests From 8a723f8b19ed5ae387aaf1a8cc106d6111dee6f1 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 10 Oct 2025 15:36:45 -0700 Subject: [PATCH 103/378] Fix a couple more lint errors --- CHANGELOG/preview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 0985f0decf4..3648f4cc121 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -199,9 +199,9 @@ - Fix a typo in the 7.4 changelog (#26038) (Thanks @VbhvGupta!) - Add 7.4.12 changelog (#26011) - Add v7.5.3 changelog (#25994) -- Fix typo in CHANGELOG for script filename suggestion (#25962) -- Update CHANGELOG for v7.5.2 (#25668) -- Update CHANGELOG for v7.4.11 (#25667) +- Fix typo in changelog for script filename suggestion (#25962) +- Update changelog for v7.5.2 (#25668) +- Update changelog for v7.4.11 (#25667) - Update build documentation with instruction of dev terminal (#25587) - Update links and contribution guide in documentation (#25532) (Thanks @JustinGrote!) - Add 7.4.10 changelog (#25520) From 659c73ffd30d8309910cbd4b809f2238fe2603e4 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 12 Oct 2025 11:57:10 +0100 Subject: [PATCH 104/378] Avoid possible multiple enumerations in ImportModuleCommand.IsPs1xmlFileHelper_IsPresentInEntries (#26104) --- .../engine/Modules/ImportModuleCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs index 15e8bfe6a9a..05357bbb5e5 100644 --- a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs @@ -1371,7 +1371,7 @@ private void ImportModule_RemotelyViaCimSession( } } - private bool IsPs1xmlFileHelper_IsPresentInEntries(RemoteDiscoveryHelper.CimModuleFile cimModuleFile, IEnumerable manifestEntries) + private bool IsPs1xmlFileHelper_IsPresentInEntries(RemoteDiscoveryHelper.CimModuleFile cimModuleFile, List manifestEntries) { const string ps1xmlExt = ".ps1xml"; string fileName = cimModuleFile.FileName; From 26bb188c8be0cda6cb548ce1a12840ebf67e1331 Mon Sep 17 00:00:00 2001 From: Jorge Suarez Date: Sun, 12 Oct 2025 23:55:20 -0700 Subject: [PATCH 105/378] Improve ValidateLength error message consistency and refactor validation tests (#25806) --- .../resources/Metadata.resx | 2 +- .../engine/Basic/ValidateAttributes.Tests.ps1 | 182 ++++++++++++------ 2 files changed, 124 insertions(+), 60 deletions(-) diff --git a/src/System.Management.Automation/resources/Metadata.resx b/src/System.Management.Automation/resources/Metadata.resx index de0a30f77e2..b8dc3ea4eb4 100644 --- a/src/System.Management.Automation/resources/Metadata.resx +++ b/src/System.Management.Automation/resources/Metadata.resx @@ -175,7 +175,7 @@ The character length ({1}) of the argument is too short. Specify an argument with a length that is greater than or equal to "{0}", and then try the command again. - The character length of the {1} argument is too long. Shorten the character length of the argument so it is fewer than or equal to "{0}" characters, and then try the command again. + The character length ({1}) of the argument is too long. Specify an argument with a length that is shorter than or equal to "{0}", and then try the command again. The argument "{0}" does not belong to the set "{1}" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. diff --git a/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 b/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 index c8d56786d51..ff4ad0ebcac 100644 --- a/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 +++ b/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 @@ -6,33 +6,33 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { BeforeAll { $testCases = @( @{ - ScriptBlock = { function foo { param([ValidateCount(-1,2)] [string[]] $bar) }; foo } + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(-1,2)] [string[]] $Items) }; Test-ArrayCount } FullyQualifiedErrorId = "ExceptionConstructingAttribute" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateCount(1,-1)] [string[]] $bar) }; foo } + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(1,-1)] [string[]] $Items) }; Test-ArrayCount } FullyQualifiedErrorId = "ExceptionConstructingAttribute" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateCount(2, 1)] [string[]] $bar) }; foo } + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(2, 1)] [string[]] $Items) }; Test-ArrayCount } FullyQualifiedErrorId = "ValidateRangeMaxLengthSmallerThanMinLength" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateCount(2, 2)] [string[]] $bar) }; foo 1 } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(2, 2)] [string[]] $Items) }; Test-ArrayCount 1 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-ArrayCount" InnerErrorId = "ValidateCountExactFailure" } @{ - ScriptBlock = { function foo { param([ValidateCount(2, 3)] [string[]] $bar) }; foo 1 } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(2, 3)] [string[]] $Items) }; Test-ArrayCount 1 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-ArrayCount" InnerErrorId = "ValidateCountMinMaxFailure" } @{ - ScriptBlock = { function foo { param([ValidateCount(2, 3)] [string[]] $bar) }; foo 1,2,3,4 } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-ArrayCount { param([ValidateCount(2, 3)] [string[]] $Items) }; Test-ArrayCount 1,2,3,4 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-ArrayCount" InnerErrorId = "ValidateCountMinMaxFailure" } ) @@ -41,14 +41,14 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { It 'Exception: :' -TestCases $testCases { param($ScriptBlock, $FullyQualifiedErrorId, $InnerErrorId) - $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId + $err = $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -PassThru if ($InnerErrorId) { - $error[0].exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId + $err.exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId } } It 'No Exception: valid argument count' { - { function foo { param([ValidateCount(2, 4)] [string[]] $bar) }; foo 1,2,3,4 } | Should -Not -Throw + { function Test-ArrayCount { param([ValidateCount(2, 4)] [string[]] $Items) }; Test-ArrayCount 1,2,3,4 } | Should -Not -Throw } } @@ -56,22 +56,22 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { BeforeAll { $testCases = @( @{ - ScriptBlock = { function foo { param([ValidateRange('xPositive')] $bar) }; foo } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('xPositive')] $Number) }; Test-NumericRange } FullyQualifiedErrorId = "ExceptionConstructingAttribute" InnerErrorId = "SubstringDisambiguationEnumParseThrewAnException" } @{ - ScriptBlock = { function foo { param([ValidateRange(2,1)] [int] $bar) }; foo } + ScriptBlock = { function Test-NumericRange { param([ValidateRange(2,1)] [int] $Number) }; Test-NumericRange } FullyQualifiedErrorId = "MaxRangeSmallerThanMinRange" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateRange("one",10)] $bar) }; foo } + ScriptBlock = { function Test-NumericRange { param([ValidateRange("one",10)] $Number) }; Test-NumericRange } FullyQualifiedErrorId = "MinRangeNotTheSameTypeOfMaxRange" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateRange(1,"two")] $bar) }; foo } + ScriptBlock = { function Test-NumericRange { param([ValidateRange(1,"two")] $Number) }; Test-NumericRange } FullyQualifiedErrorId = "MinRangeNotTheSameTypeOfMaxRange" InnerErrorId = "" } @@ -81,9 +81,9 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { It 'Exception: :' -TestCases $testCases { param($ScriptBlock, $FullyQualifiedErrorId, $InnerErrorId) - $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId + $err = $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -PassThru if ($InnerErrorId) { - $error[0].exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId + $err.exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId } } } @@ -91,25 +91,25 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { BeforeAll { $testCases = @( @{ - ScriptBlock = { function foo { param([ValidateRange(1,10)] [int] $bar) }; foo -1 } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-NumericRange { param([ValidateRange(1,10)] [int] $Number) }; Test-NumericRange -1 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeTooSmall" } @{ - ScriptBlock = { function foo { param([ValidateRange(1,10)] [int] $bar) }; foo 11 } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-NumericRange { param([ValidateRange(1,10)] [int] $Number) }; Test-NumericRange 11 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeTooBig" } @{ - ScriptBlock = { function foo { param([ValidateRange(1,10)] $bar) }; foo "one" } - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + ScriptBlock = { function Test-NumericRange { param([ValidateRange(1,10)] $Number) }; Test-NumericRange "one" } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidationRangeElementType" } ) $validTestCases = @( @{ - ScriptBlock = { function foo { param([ValidateRange(1,10)] [int] $bar) }; foo 5 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange(1,10)] [int] $Number) }; Test-NumericRange 5 } } ) } @@ -117,9 +117,9 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { It 'Exception: :' -TestCases $testCases { param($ScriptBlock, $FullyQualifiedErrorId, $InnerErrorId) - $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId + $err = $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -PassThru if ($InnerErrorId) { - $error[0].exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId + $err.exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId } } @@ -133,115 +133,115 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { BeforeAll { $testCases = @( @{ - ScriptBlock = { function foo { param([ValidateRange("Positive")] [int] $bar) }; foo -1 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange("Positive")] [int] $Number) }; Test-NumericRange -1 } RangeType = "Positive" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangePositiveFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange("Positive")] [int] $bar) }; foo 0 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange("Positive")] [int] $Number) }; Test-NumericRange 0 } RangeType = "Positive" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangePositiveFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange("Positive")] $bar) }; foo "one" } + ScriptBlock = { function Test-NumericRange { param([ValidateRange("Positive")] $Number) }; Test-NumericRange "one" } RangeType = "Positive" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateRange('NonNegative')] [int] $bar) }; foo -1 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonNegative')] [int] $Number) }; Test-NumericRange -1 } RangeType = "NonNegative" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeNonNegativeFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange('NonNegative')] $bar) }; foo "one" } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonNegative')] $Number) }; Test-NumericRange "one" } RangeType = "NonNegative" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateRange('Negative')] [int] $bar) }; foo 1 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('Negative')] [int] $Number) }; Test-NumericRange 1 } RangeType = "Negative" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeNegativeFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange('Negative')] [int] $bar) }; foo 0 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('Negative')] [int] $Number) }; Test-NumericRange 0 } RangeType = "Negative" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeNegativeFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange('Negative')] $bar) }; foo "one" } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('Negative')] $Number) }; Test-NumericRange "one" } RangeType = "Negative" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "" } @{ - ScriptBlock = { function foo { param([ValidateRange('NonPositive')] $bar) }; foo 1 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonPositive')] $Number) }; Test-NumericRange 1 } RangeType = "NonPositive" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "ValidateRangeNonPositiveFailure" } @{ - ScriptBlock = { function foo { param([ValidateRange('NonPositive')] $bar) }; foo "one" } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonPositive')] $Number) }; Test-NumericRange "one" } RangeType = "NonPositive" - FullyQualifiedErrorId = "ParameterArgumentValidationError,foo" + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-NumericRange" InnerErrorId = "" } ) $validTestCases = @( @{ - ScriptBlock = { function foo { param([ValidateRange("Positive")] [int] $bar) }; foo 15 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange("Positive")] [int] $Number) }; Test-NumericRange 15 } RangeType = "Positive" TestValue = 15 } @{ - ScriptBlock = { function foo { param([ValidateRange("Positive")] [double]$bar) }; foo ([double]::MaxValue) }; + ScriptBlock = { function Test-NumericRange { param([ValidateRange("Positive")] [double]$Number) }; Test-NumericRange ([double]::MaxValue) }; RangeType = "Positive" TestValue = [double]::MaxValue } @{ - ScriptBlock = { function foo { param([ValidateRange('NonNegative')] [int] $bar) }; foo 0 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonNegative')] [int] $Number) }; Test-NumericRange 0 } RangeType = "NonNegative" TestValue = 0 } @{ - ScriptBlock = { function foo { param([ValidateRange('NonNegative')] [int] $bar) }; foo 15 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonNegative')] [int] $Number) }; Test-NumericRange 15 } RangeType = "NonNegative" TestValue = 15 } @{ - ScriptBlock = { function foo { param([ValidateRange('NonNegative')] [double]$bar) }; foo ([double]::MaxValue) }; + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonNegative')] [double]$Number) }; Test-NumericRange ([double]::MaxValue) }; RangeType = "NonNegative" TestValue = [double]::MaxValue } @{ - ScriptBlock = { function foo { param([ValidateRange('Negative')] [int] $bar) }; foo -15 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('Negative')] [int] $Number) }; Test-NumericRange -15 } RangeType = "Negative" TestValue = -15 } @{ - ScriptBlock = { function foo { param([ValidateRange('Negative')] [double]$bar) }; foo ([double]::MinValue) }; + ScriptBlock = { function Test-NumericRange { param([ValidateRange('Negative')] [double]$Number) }; Test-NumericRange ([double]::MinValue) }; TestValue = [double]::MinValue RangeType = "Negative" } @{ - ScriptBlock = { function foo { param([ValidateRange('NonPositive')] [int] $bar) }; foo 0 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonPositive')] [int] $Number) }; Test-NumericRange 0 } RangeType = "NonPositive" TestValue = 0 } @{ - ScriptBlock = { function foo { param([ValidateRange('NonPositive')] [int] $bar) }; foo -15 } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonPositive')] [int] $Number) }; Test-NumericRange -15 } RangeType = "NonPositive" TestValue = -15 } @{ - ScriptBlock = { function foo { param([ValidateRange('NonPositive')] [double]$bar) }; foo ([double]::MinValue) } + ScriptBlock = { function Test-NumericRange { param([ValidateRange('NonPositive')] [double]$Number) }; Test-NumericRange ([double]::MinValue) } RangeType = "NonPositive" TestValue = [double]::MinValue } @@ -251,9 +251,9 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { It 'Exception: :, RangeType: ' -TestCases $testCases { param($ScriptBlock, $RangeType, $FullyQualifiedErrorId, $InnerErrorId) - $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId + $err = $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -PassThru if ($InnerErrorId) { - $error[0].exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId + $err.exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId } } @@ -263,6 +263,70 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { } } + Context "ValidateLength" { + BeforeAll { + $testCases = @( + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] [string] $InputString) }; Test-StringLength "a" } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-StringLength" + InnerErrorId = "ValidateLengthMinLengthFailure" + } + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] [string] $InputString) }; Test-StringLength "abcdef" } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-StringLength" + InnerErrorId = "ValidateLengthMaxLengthFailure" + } + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] $InputString) }; Test-StringLength 123 } + FullyQualifiedErrorId = "ParameterArgumentValidationError,Test-StringLength" + InnerErrorId = "ValidateLengthNotString" + } + ) + + $validTestCases = @( + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] [string] $InputString) }; Test-StringLength "abc" } + } + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] [string] $InputString) }; Test-StringLength "ab" } + } + @{ + ScriptBlock = { function Test-StringLength { param([ValidateLength(2, 5)] [string] $InputString) }; Test-StringLength "abcde" } + } + ) + } + + It 'Exception: :' -TestCases $testCases { + param($ScriptBlock, $FullyQualifiedErrorId, $InnerErrorId) + + $err = $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -PassThru + if ($InnerErrorId) { + $err.exception.innerexception.errorrecord.FullyQualifiedErrorId | Should -Be $InnerErrorId + } + } + + It 'No Exception: valid string length' -TestCases $validTestCases { + param($ScriptBlock) + $ScriptBlock | Should -Not -Throw + } + + It 'ValidateLength error message should be properly formatted' { + function Test-ValidateLengthMax { param([ValidateLength(0,2)] [string] $Value) $Value } + function Test-ValidateLengthMin { param([ValidateLength(5,10)] [string] $Value) $Value } + + $TestStringTooLong = "11111" + $TestStringTooShort = "123" + $ExpectedMaxLength = 2 + $ExpectedMinLength = 5 + + $err = { Test-ValidateLengthMax $TestStringTooLong } | Should -Throw -ErrorId "ParameterArgumentValidationError,Test-ValidateLengthMax" -PassThru + $err.Exception.InnerException.Message | Should -Match ".+\($($TestStringTooLong.Length)\).+\`"$ExpectedMaxLength\`"" + + $err = { Test-ValidateLengthMin $TestStringTooShort } | Should -Throw -ErrorId "ParameterArgumentValidationError,Test-ValidateLengthMin" -PassThru + $err.Exception.InnerException.Message | Should -Match ".+\($($TestStringTooShort.Length)\).+\`"$ExpectedMinLength\`"" + } + } + Context "ValidateNotNull, ValidateNotNullOrEmpty, ValidateNotNullOrWhiteSpace and Not-Null-Or-Empty check for Mandatory parameter" { BeforeAll { From 47e38beda56c0e7fafed4142e4c1c7bcf1a67d2a Mon Sep 17 00:00:00 2001 From: Ryan Yates Date: Wed, 15 Oct 2025 17:31:04 +0100 Subject: [PATCH 106/378] Properly Expand Aliases to their actual ResolvedCommand (#25763) --- .../engine/TypeTable_Types_Ps1Xml.cs | 10 ++-------- .../Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 | 10 ++++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs b/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs index c1a134cdfbf..26e3621c240 100644 --- a/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs +++ b/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs @@ -565,9 +565,7 @@ private void Process_Types_Ps1Xml(string filePath, ConcurrentBag errors) typeName, new PSScriptProperty( @"DisplayName", - GetScriptBlock(@"if ($this.Name.IndexOf('-') -lt 0) - { - if ($null -ne $this.ResolvedCommand) + GetScriptBlock(@"if ($null -ne $this.ResolvedCommand) { $this.Name + "" -> "" + $this.ResolvedCommand.Name } @@ -575,11 +573,7 @@ private void Process_Types_Ps1Xml(string filePath, ConcurrentBag errors) { $this.Name + "" -> "" + $this.Definition } - } - else - { - $this.Name - }"), + "), setterScript: null, shouldCloneOnAccess: true), typeMembers, diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 index edccb912ca7..a5b0b039d00 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 @@ -155,6 +155,16 @@ Describe "Get-Alias DRT Unit Tests" -Tags "CI" { $returnObject[$i].Definition | Should -Be 'Get-Command' } } + + It "Get-Alias DisplayName should always show AliasName -> ResolvedCommand for all aliases" { + Set-Alias -Name Test-MyAlias -Value Get-Command -Force + Set-Alias -Name tma -Value Test-MyAlias -force + $aliases = Get-Alias Test-MyAlias, tma + $aliases | ForEach-Object { + $_.DisplayName | Should -Be "$($_.Name) -> Get-Command" + } + $aliases.Name.foreach{Remove-Item Alias:$_ -ErrorAction SilentlyContinue} + } } Describe "Get-Alias" -Tags "CI" { From b77c80ec2f9c7ac69e10cc77ad3be0dfb2d18256 Mon Sep 17 00:00:00 2001 From: Amrit Anand <64958314+amritanand-py@users.noreply.github.com> Date: Wed, 15 Oct 2025 22:06:24 +0530 Subject: [PATCH 107/378] Replace custom method with File.ReadAllText() in ScriptAnalysis.cs (#26060) --- .../engine/Modules/ScriptAnalysis.cs | 15 +-------------- src/System.Management.Automation/utils/PsUtils.cs | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ScriptAnalysis.cs b/src/System.Management.Automation/engine/Modules/ScriptAnalysis.cs index 7207a7292c0..892d7375387 100644 --- a/src/System.Management.Automation/engine/Modules/ScriptAnalysis.cs +++ b/src/System.Management.Automation/engine/Modules/ScriptAnalysis.cs @@ -40,7 +40,7 @@ internal static ScriptAnalysis Analyze(string path, ExecutionContext context) // So eat the invalid operation } - string scriptContent = ReadScript(path); + string scriptContent = File.ReadAllText(path, Encoding.Default); ParseError[] errors; var moduleAst = (new Parser()).Parse(path, scriptContent, null, out errors, ParseMode.ModuleAnalysis); @@ -89,19 +89,6 @@ internal static ScriptAnalysis Analyze(string path, ExecutionContext context) return result; } - internal static string ReadScript(string path) - { - using (FileStream readerStream = new FileStream(path, FileMode.Open, FileAccess.Read)) - { - Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle = readerStream.SafeFileHandle; - - using (StreamReader scriptReader = new StreamReader(readerStream, Encoding.Default)) - { - return scriptReader.ReadToEnd(); - } - } - } - internal List DiscoveredExports { get; set; } internal Dictionary DiscoveredAliases { get; set; } diff --git a/src/System.Management.Automation/utils/PsUtils.cs b/src/System.Management.Automation/utils/PsUtils.cs index d404581bf1f..ff2d0ade5ea 100644 --- a/src/System.Management.Automation/utils/PsUtils.cs +++ b/src/System.Management.Automation/utils/PsUtils.cs @@ -340,7 +340,7 @@ internal static Hashtable EvaluatePowerShellDataFile( internal static Hashtable GetModuleManifestProperties(string psDataFilePath, string[] keys) { - string dataFileContents = ScriptAnalysis.ReadScript(psDataFilePath); + string dataFileContents = File.ReadAllText(psDataFilePath, Encoding.Default); ParseError[] parseErrors; var ast = (new Parser()).Parse(psDataFilePath, dataFileContents, null, out parseErrors, ParseMode.ModuleAnalysis); if (parseErrors.Length > 0) From 9c5ac7d6223a0c96e3b0b866bfa623f656e0c679 Mon Sep 17 00:00:00 2001 From: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> Date: Wed, 15 Oct 2025 18:50:37 +0200 Subject: [PATCH 108/378] Add Delimiter parameter to Get-Clipboard (#26134) --- .../management/GetClipboardCommand.cs | 42 ++++++++++++++++++- .../Clipboard.Tests.ps1 | 7 ++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs index dd878bd72ce..a2b7f03ce70 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs @@ -2,8 +2,10 @@ // Licensed under the MIT License. using System; +using System.Collections; using System.Collections.Generic; using System.Management.Automation; +using System.Management.Automation.Language; using Microsoft.PowerShell.Commands.Internal; namespace Microsoft.PowerShell.Commands @@ -34,6 +36,13 @@ public SwitchParameter Raw } } + /// + /// Gets or sets the delimiters to use when splitting the clipboard content. + /// + [Parameter] + [ArgumentCompleter(typeof(DelimiterCompleter))] + public string[] Delimiter { get; set; } = [Environment.NewLine]; + private bool _raw; /// @@ -68,11 +77,40 @@ private List GetClipboardContentAsText() } else { - string[] splitSymbol = { Environment.NewLine }; - result.AddRange(textContent.Split(splitSymbol, StringSplitOptions.None)); + result.AddRange(textContent.Split(Delimiter, StringSplitOptions.None)); } return result; } } + + /// + /// Provides argument completion for the Delimiter parameter. + /// + public sealed class DelimiterCompleter : IArgumentCompleter + { + /// + /// Provides argument completion for the Delimiter parameter. + /// + /// The name of the command that is being completed. + /// The name of the parameter that is being completed. + /// The input text to filter the results by. + /// The ast of the command that triggered the completion. + /// The parameters bound to the command. + /// Completion results. + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + wordToComplete ??= string.Empty; + var pattern = new WildcardPattern(wordToComplete + '*', WildcardOptions.IgnoreCase); + if (pattern.IsMatch("CRLF") || pattern.IsMatch("Windows")) + { + yield return new CompletionResult("\"`r`n\"", "CRLF", CompletionResultType.ParameterValue, "Windows (CRLF)"); + } + + if (pattern.IsMatch("LF") || pattern.IsMatch("Unix") || pattern.IsMatch("Linux")) + { + yield return new CompletionResult("\"`n\"", "LF", CompletionResultType.ParameterValue, "UNIX (LF)"); + } + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 index 7cd4f492bfa..62f8d77a44c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 @@ -36,6 +36,13 @@ Describe 'Clipboard cmdlet tests' -Tag CI { Get-Clipboard -Raw | Should -BeExactly "1$([Environment]::NewLine)2" } + It 'Get-Clipboard -Delimiter should return items based on the delimiter' { + Set-Clipboard -Value "Line1`r`nLine2`nLine3" + $result = Get-Clipboard -Delimiter "`r`n", "`n" + $result.Count | Should -Be 3 + $result | ForEach-Object -Process {$_.Length | Should -Be "LineX".Length} + } + It 'Set-Clipboard -Append will add text' { 'hello' | Set-Clipboard 'world' | Set-Clipboard -Append From 0e90b57e63a6c58e0288cdd26ca58356ade57966 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Oct 2025 12:33:31 -0700 Subject: [PATCH 109/378] Github Workflow cleanup (#26193) --- .github/workflows/AssignPrs.yml | 30 --------------- .github/workflows/createReminders.yml | 21 ---------- .github/workflows/markdownLink.yml | 51 ------------------------- .github/workflows/markdownLinkDaily.yml | 33 ---------------- .github/workflows/processReminders.yml | 21 ---------- tools/download.sh | 4 +- tools/install-powershell.sh | 6 ++- 7 files changed, 7 insertions(+), 159 deletions(-) delete mode 100644 .github/workflows/AssignPrs.yml delete mode 100644 .github/workflows/createReminders.yml delete mode 100644 .github/workflows/markdownLink.yml delete mode 100644 .github/workflows/markdownLinkDaily.yml delete mode 100644 .github/workflows/processReminders.yml diff --git a/.github/workflows/AssignPrs.yml b/.github/workflows/AssignPrs.yml deleted file mode 100644 index a01c0bb0950..00000000000 --- a/.github/workflows/AssignPrs.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Auto Assign PR Maintainer -on: - issues: - types: [opened, edited] -permissions: - contents: read - -jobs: - run: - if: github.repository_owner == 'PowerShell' - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: wow-actions/auto-assign@67fafa03df61d7e5f201734a2fa60d1ab111880d # v3.0.2 - if: github.event.issue.pull_request - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # using the `org/team_slug` or `/team_slug` syntax to add git team as reviewers - assignees: | - TravisEz13 - daxian-dbw - adityapatwardhan - iSazonov - SeeminglyScience - skipDraft: true - skipKeywords: wip, draft - addReviewers: false - numberOfAssignees: 1 diff --git a/.github/workflows/createReminders.yml b/.github/workflows/createReminders.yml deleted file mode 100644 index bab5342fe0b..00000000000 --- a/.github/workflows/createReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Create reminder' - -on: - issue_comment: - types: [created, edited] - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - - permissions: - issues: write # for agrc/create-reminder-action to set reminders on issues - pull-requests: write # for agrc/create-reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check for reminder - uses: agrc/create-reminder-action@30624e347adbc7ff2dd287ad0632499552e048e8 # v1.1.22 diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml deleted file mode 100644 index 5ad78cf84d4..00000000000 --- a/.github/workflows/markdownLink.yml +++ /dev/null @@ -1,51 +0,0 @@ -on: - pull_request: - branches: - - master - -name: Check modified markdown files -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository_owner == 'PowerShell' - - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - check-modified-files-only: 'yes' - config-file: .github/workflows/markdown-link/config.json - markdown-lint: - permissions: - contents: read - packages: read - statuses: write - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - # Full git history is needed to get a proper - # list of changed files within `super-linter` - fetch-depth: 0 - - name: Load super-linter configuration - # Use grep inverse matching to exclude eventual comments in the .env file - # because the GitHub Actions command to set environment variables doesn't - # support comments. - # Ref: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable - run: grep -v '^#' tools/super-linter/config/super-linter.env >> "$GITHUB_ENV" - - name: Lint Markdown - uses: super-linter/super-linter@5119dcd8011e92182ce8219d9e9efc82f16fddb6 # v8.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Super-Linter correction instructions - if: failure() - uses: actions/github-script@v8 - with: - script: | - const message = "Super-Linter found issues in the changed files. Please check the logs for details. You can run the linter locally using the command: `./tools/super-lister/super-lister.ps1`."; - core.setFailed(message); diff --git a/.github/workflows/markdownLinkDaily.yml b/.github/workflows/markdownLinkDaily.yml deleted file mode 100644 index 7f5789ed96d..00000000000 --- a/.github/workflows/markdownLinkDaily.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT license. - -name: PowerShell Daily Markdown Link Verification - -on: - workflow_dispatch: - schedule: - # At 13:00 UTC every day. - - cron: '0 13 * * *' - -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository == 'PowerShell/PowerShell' - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Check Links - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - config-file: .github/workflows/markdown-link/config.json - - name: Microsoft Teams Notifier - uses: skitionek/notify-microsoft-teams@e7a2493ac87dad8aa7a62f079f295e54ff511d88 # master - if: failure() - with: - webhook_url: ${{ secrets.PS_BUILD_TEAMS_CHANNEL }} - overwrite: "{title: `Failure in .github/markdownLinkDaily.yml validating links. Look at ${workflow_link}`}" diff --git a/.github/workflows/processReminders.yml b/.github/workflows/processReminders.yml deleted file mode 100644 index 18de16159ac..00000000000 --- a/.github/workflows/processReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Process reminders' - -on: - schedule: - - cron: '*/15 * * * *' - workflow_dispatch: - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - permissions: - issues: write # for agrc/reminder-action to set reminders on issues - pull-requests: write # for agrc/reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check reminders and notify - uses: agrc/reminder-action@3095f64f8f0c26c751bee802cb1008ece5953078 # v1.0.18 diff --git a/tools/download.sh b/tools/download.sh index 6a6c6436b4b..f1e8c42cdc3 100644 --- a/tools/download.sh +++ b/tools/download.sh @@ -1 +1,3 @@ -bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) +# Pin to specific commit for security (OpenSSF Scorecard requirement) +# Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) +bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331/tools/install-powershell.sh) diff --git a/tools/install-powershell.sh b/tools/install-powershell.sh index 128f5664483..91425c183a8 100755 --- a/tools/install-powershell.sh +++ b/tools/install-powershell.sh @@ -26,7 +26,9 @@ install(){ #gitrepo paths are overrideable to run from your own fork or branch for testing or private distribution local VERSION="1.2.0" - local gitreposubpath="PowerShell/PowerShell/master" + # Pin to specific commit for security (OpenSSF Scorecard requirement) + # Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) + local gitreposubpath="PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331" local gitreposcriptroot="https://raw.githubusercontent.com/$gitreposubpath/tools" local gitscriptname="install-powershell.psh" @@ -125,7 +127,7 @@ install(){ if [[ $osname = *SUSE* ]]; then DistroBasedOn='suse' REV=$(source /etc/os-release; echo $VERSION_ID) - fi + fi OS=$(lowercase $OS) DistroBasedOn=$(lowercase $DistroBasedOn) fi From de7fd463ba5fb60c649922a5a60daaa664fe8e4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 12:37:02 -0700 Subject: [PATCH 110/378] Bump github/codeql-action from 4.30.7 to 4.30.8 (#26184) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 5c2118ef7be..b58b75c64a4 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -192,7 +192,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 + uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -218,7 +218,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 + uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a168f12319f..2a12425a829 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e296a935590eb16afc0c0108289f68c87e2a89a5 # v3.29.5 + uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 with: sarif_file: results.sarif From 59a85e04afd16b6e11b2e6ab448eb4399f877767 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:35:42 -0700 Subject: [PATCH 111/378] Bump actions/dependency-review-action from 4.7.3 to 4.8.1 (#26183) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c0f2e6e0092..c3cc0624c45 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3 + uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1 From 7e081b30b886a57c2ee47d95fdce8880142aa514 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 15 Oct 2025 14:06:00 -0700 Subject: [PATCH 112/378] Update vPack name (#26090) --- .pipelines/PowerShell-vPack-Official.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index f110ff0366a..3b151127cb1 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -11,8 +11,9 @@ parameters: # parameters are shown up in ADO UI in a build queue time - name: vPackName type: string displayName: 'VPack Name:' - default: 'PowerShell' + default: 'PowerShell.BuildTool' values: + - PowerShell.BuildTool - PowerShell - PowerShellDoNotUse - name: 'ReleaseTagVar' From e733fd7343f88e79534746393995201f79b47869 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 16 Oct 2025 05:17:47 +0100 Subject: [PATCH 113/378] Fix mismatched indentation in `.config/suppress.json` (#26192) Co-authored-by: Travis Plunk --- .config/suppress.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.config/suppress.json b/.config/suppress.json index 55e607b1b0c..9be220b291e 100644 --- a/.config/suppress.json +++ b/.config/suppress.json @@ -1,17 +1,17 @@ { - "tool": "Credential Scanner", - "suppressions": [ - { - "file": "\\test\\tools\\Modules\\WebListener\\ClientCert.pfx", - "_justification": "Test certificate with private key" - }, - { - "file": "\\test\\tools\\Modules\\WebListener\\ServerCert.pfx", - "_justification": "Test certificate with private key" - }, - { - "file": "\\test\\powershell\\Modules\\Microsoft.PowerShell.Security\\certificateCommon.psm1", - "_justification": "Test certificate with private key and inline suppression isn't working" - } - ] + "tool": "Credential Scanner", + "suppressions": [ + { + "file": "\\test\\tools\\Modules\\WebListener\\ClientCert.pfx", + "_justification": "Test certificate with private key" + }, + { + "file": "\\test\\tools\\Modules\\WebListener\\ServerCert.pfx", + "_justification": "Test certificate with private key" + }, + { + "file": "\\test\\powershell\\Modules\\Microsoft.PowerShell.Security\\certificateCommon.psm1", + "_justification": "Test certificate with private key and inline suppression isn't working" + } + ] } From 123b4504438597863a0381eae4fe9d86ee7d8f0b Mon Sep 17 00:00:00 2001 From: mikkas456 Date: Thu, 16 Oct 2025 07:09:49 +0200 Subject: [PATCH 114/378] Handle null reference exception in CsvCommands.cs: ConvertPSObjectToCSV (#26144) --- .../commands/utility/CsvCommands.cs | 2 +- .../ConvertTo-Csv.Tests.ps1 | 8 ++++++ .../Export-Csv.Tests.ps1 | 28 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 414b472e640..0ff52372864 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -1044,7 +1044,7 @@ internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyN { if (dictionary.Contains(propertyName)) { - value = dictionary[propertyName].ToString(); + value = dictionary[propertyName]?.ToString(); } else if (mshObject.Properties[propertyName] is PSPropertyInfo property) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 index 0d484260813..298b8140468 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 @@ -212,6 +212,7 @@ Describe "ConvertTo-Csv" -Tags "CI" { [ordered]@{ Number = $_; Letter = $Letters[$_] } } $CsvString = $Items | ConvertTo-Csv + $TestHashTable = [ordered]@{ 'first' = 'value1'; 'second' = $null; 'third' = 'value3' } } It 'should treat dictionary entries as properties' { @@ -235,5 +236,12 @@ Describe "ConvertTo-Csv" -Tags "CI" { $NewCsvString[0] | Should -MatchExactly 'Extra' $NewCsvString | Select-Object -Skip 1 | Should -MatchExactly 'Surprise!' } + + It 'should properly convert hashtable with null and non-null values'{ + $CsvResult = $TestHashTable | ConvertTo-Csv + + $CsvResult[0] | Should -BeExactly "`"first`",`"second`",`"third`"" + $CsvResult[1] | Should -BeExactly "`"value1`",$null,`"value3`"" + } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 index 67234f24c58..db5c6aff9e3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 @@ -11,6 +11,7 @@ Describe "Export-Csv" -Tags "CI" { $P1 = [pscustomobject]@{"P1" = "first"} $P2 = [pscustomobject]@{"P2" = "second"} $P11 = [pscustomobject]@{"P1" = "eleventh"} + $testHashTable = @{ 'first' = "value1"; 'second' = $null; 'third' = "value3" } } AfterEach { @@ -249,6 +250,33 @@ Describe "Export-Csv" -Tags "CI" { $contents[1].Contains($delimiter) | Should -BeTrue } + It "Should not throw when exporting hashtable with property that has null value"{ + { $testHashTable | Export-Csv -Path $testCsv } | Should -Not -Throw + } + + It "Should not throw when exporting PSCustomObject with property that has null value"{ + $testObject = [pscustomobject]$testHashTable + { $testObject | Export-Csv -Path $testCsv } | Should -Not -Throw + } + + It "Export hashtable with null and non-null values"{ + $testHashTable | Export-Csv -Path $testCsv + $result2 = Import-CSV -Path $testCsv + + $result2.first | Should -BeExactly "value1" + $result2.second | Should -BeNullOrEmpty + $result2.third | Should -BeExactly "value3" + } + + It "Export hashtable with non-null values"{ + $testTable = @{ 'first' = "value1"; 'second' = "value2" } + $testTable | Export-Csv -Path $testCsv + $results = Import-CSV -Path $testCsv + + $results.first | Should -BeExactly "value1" + $results.second | Should -BeExactly "value2" + } + Context "UseQuotes parameter" { # A minimum of tests. The rest are in ConvertTo-Csv.Tests.ps1 From 380758aff41407d1bfe481345b16d5075a27c471 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 16 Oct 2025 06:16:24 +0100 Subject: [PATCH 115/378] Enable IDE0019: InlineAsTypeCheck (#25920) --- .globalconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index b125f70e254..68fb0a66b2d 100644 --- a/.globalconfig +++ b/.globalconfig @@ -1222,7 +1222,7 @@ dotnet_diagnostic.IDE0018.severity = silent # IDE0019: InlineAsTypeCheck # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0019 -dotnet_diagnostic.IDE0019.severity = silent +dotnet_diagnostic.IDE0019.severity = warning # IDE0020: InlineIsTypeCheck # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0020 From d2d0defd5fe46eadc472eb3f4ea0655aef8e0dae Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 16 Oct 2025 06:23:32 +0100 Subject: [PATCH 116/378] Fix CA1852: Seal internal types. Part 1 (#26205) --- .../NewWinEventCommand.cs | 2 +- .../PdhHelper.cs | 2 +- .../management/GetComputerInfoCommand.cs | 26 +++++++++---------- .../commands/management/Process.cs | 4 +-- .../CurrentConfigurations.cs | 2 +- src/Microsoft.WSMan.Management/WsManHelper.cs | 4 +-- test/xUnit/csharp/test_AstDefaultVisit.cs | 6 ++--- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs index b0b102870c4..cdddba939f3 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/NewWinEventCommand.cs @@ -323,7 +323,7 @@ protected override void EndProcessing() } } - internal class EventWriteException : Exception + internal sealed class EventWriteException : Exception { internal EventWriteException(string msg, Exception innerException) : base(msg, innerException) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs index b761aa6e30b..6f5d8f6e5ec 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs @@ -190,7 +190,7 @@ internal struct CounterHandleNInstance public string InstanceName; } - internal class PdhHelper : IDisposable + internal sealed class PdhHelper : IDisposable { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct PDH_COUNTER_PATH_ELEMENTS diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs index 3de7c723745..e355be6f3ff 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs @@ -1335,7 +1335,7 @@ protected static string GetLanguageName(uint? lcid) #pragma warning disable 649 // fields and properties in these class are assigned dynamically [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiBaseBoard + internal sealed class WmiBaseBoard { public string Caption; public string[] ConfigOptions; @@ -1368,7 +1368,7 @@ internal class WmiBaseBoard } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiBios : WmiClassBase + internal sealed class WmiBios : WmiClassBase { public ushort[] BiosCharacteristics; public string[] BIOSVersion; @@ -1403,7 +1403,7 @@ internal class WmiBios : WmiClassBase } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiComputerSystem + internal sealed class WmiComputerSystem { public ushort? AdminPasswordStatus; public bool? AutomaticManagedPagefile; @@ -1486,7 +1486,7 @@ public PowerManagementCapabilities[] GetPowerManagementCapabilities() } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiDeviceGuard + internal sealed class WmiDeviceGuard { public uint[] AvailableSecurityProperties; public uint? CodeIntegrityPolicyEnforcementStatus; @@ -1561,7 +1561,7 @@ public DeviceGuard AsOutputType } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiKeyboard + internal sealed class WmiKeyboard { public ushort? Availability; public string Caption; @@ -1588,14 +1588,14 @@ internal class WmiKeyboard } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WMiLogicalMemory + internal sealed class WMiLogicalMemory { // TODO: fill this in!!! public uint? TotalPhysicalMemory; } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiMsftNetAdapter + internal sealed class WmiMsftNetAdapter { public string Caption; public string Description; @@ -1683,7 +1683,7 @@ internal class WmiMsftNetAdapter } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiNetworkAdapter + internal sealed class WmiNetworkAdapter { public string AdapterType; public ushort? AdapterTypeID; @@ -1727,7 +1727,7 @@ internal class WmiNetworkAdapter } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiNetworkAdapterConfiguration + internal sealed class WmiNetworkAdapterConfiguration { public bool? ArpAlwaysSourceRoute; public bool? ArpUseEtherSNAP; @@ -1793,7 +1793,7 @@ internal class WmiNetworkAdapterConfiguration } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiOperatingSystem : WmiClassBase + internal sealed class WmiOperatingSystem : WmiClassBase { #region Fields public string BootDevice; @@ -1900,7 +1900,7 @@ private static OSProductSuite[] MakeProductSuites(uint? suiteMask) } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiPageFileUsage + internal sealed class WmiPageFileUsage { public uint? AllocatedBaseSize; public string Caption; @@ -1914,7 +1914,7 @@ internal class WmiPageFileUsage } [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Class is instantiated directly from a CIM instance")] - internal class WmiProcessor + internal sealed class WmiProcessor { public ushort? AddressWidth; public ushort? Architecture; @@ -1977,7 +1977,7 @@ internal class WmiProcessor #endregion Intermediate WMI classes #region Other Intermediate classes - internal class RegWinNtCurrentVersion + internal sealed class RegWinNtCurrentVersion { public string BuildLabEx; public string CurrentVersion; diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index 2e07a945a00..c959cfcb33e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -2841,7 +2841,7 @@ internal struct PROCESS_INFORMATION } [StructLayout(LayoutKind.Sequential)] - internal class SECURITY_ATTRIBUTES + internal sealed class SECURITY_ATTRIBUTES { public int nLength; public SafeLocalMemHandle lpSecurityDescriptor; @@ -2879,7 +2879,7 @@ protected override bool ReleaseHandle() } [StructLayout(LayoutKind.Sequential)] - internal class STARTUPINFO + internal sealed class STARTUPINFO { public int cb; public IntPtr lpReserved; diff --git a/src/Microsoft.WSMan.Management/CurrentConfigurations.cs b/src/Microsoft.WSMan.Management/CurrentConfigurations.cs index f4c252c4d1d..3182c04c535 100644 --- a/src/Microsoft.WSMan.Management/CurrentConfigurations.cs +++ b/src/Microsoft.WSMan.Management/CurrentConfigurations.cs @@ -11,7 +11,7 @@ namespace Microsoft.WSMan.Management /// Class that queries the server and gets current configurations. /// Also provides a generic way to update the configurations. /// - internal class CurrentConfigurations + internal sealed class CurrentConfigurations { /// /// Prefix used to add NameSpace of root element to namespace manager. diff --git a/src/Microsoft.WSMan.Management/WsManHelper.cs b/src/Microsoft.WSMan.Management/WsManHelper.cs index 482f24aa9c1..9249c7f4b88 100644 --- a/src/Microsoft.WSMan.Management/WsManHelper.cs +++ b/src/Microsoft.WSMan.Management/WsManHelper.cs @@ -22,7 +22,7 @@ namespace Microsoft.WSMan.Management { [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")] - internal class WSManHelper + internal sealed class WSManHelper { // regular expressions private const string PTRN_URI_LAST = @"([a-z_][-a-z0-9._]*)$"; @@ -89,7 +89,7 @@ internal class WSManHelper // // // Below class is just a static container which would release sessions in case this DLL is unloaded. - internal class Sessions + internal sealed class Sessions { /// /// Dictionary object to store the connection. diff --git a/test/xUnit/csharp/test_AstDefaultVisit.cs b/test/xUnit/csharp/test_AstDefaultVisit.cs index 283c1f73071..41f3ff1ce56 100644 --- a/test/xUnit/csharp/test_AstDefaultVisit.cs +++ b/test/xUnit/csharp/test_AstDefaultVisit.cs @@ -8,17 +8,17 @@ namespace PSTests.Parallel { - internal class MyICustomAstVisitor2 : ICustomAstVisitor2 + internal sealed class MyICustomAstVisitor2 : ICustomAstVisitor2 { public object DefaultVisit(Ast ast) => ast.GetType().Name; } - internal class MyDefaultCustomAstVisitor2 : DefaultCustomAstVisitor2 + internal sealed class MyDefaultCustomAstVisitor2 : DefaultCustomAstVisitor2 { public override object DefaultVisit(Ast ast) => ast.GetType().Name; } - internal class MyAstVisitor2 : AstVisitor2 + internal sealed class MyAstVisitor2 : AstVisitor2 { public List Commands { get; } From 250144e92d1d0e7f7931ce6a7d57498c94255782 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 16 Oct 2025 06:24:06 +0100 Subject: [PATCH 117/378] Fix IDE0083: UseNotPattern (#26209) --- .../CimAsyncOperation.cs | 4 +- .../CimSessionProxy.cs | 4 +- .../cmdletization/cim/cimChildJobBase.cs | 4 +- .../cmdletization/cim/cimWrapper.cs | 2 +- .../cmdletization/cim/clientSideQuery.cs | 4 +- .../commands/utility/CustomSerialization.cs | 2 +- .../FormatAndOutput/OutGridView/ColumnInfo.cs | 2 +- .../commands/utility/Get-PSBreakpoint.cs | 4 +- .../utility/ImplicitRemotingCommands.cs | 4 +- .../commands/utility/ObjectCommandComparer.cs | 2 +- .../commands/utility/OrderObjectBase.cs | 2 +- .../commands/utility/WebCmdlet/JsonObject.cs | 2 +- .../security/AclCommands.cs | 6 +-- .../common/DisplayDatabase/typeDataQuery.cs | 2 +- .../common/FormattingObjectsDeserializer.cs | 4 +- .../other/ciminstancetypeadapter.cs | 4 +- .../engine/ArgumentTypeConverterAttribute.cs | 2 +- .../engine/Attributes.cs | 4 +- .../engine/CmdletParameterBinderController.cs | 10 ++--- .../CommandCompletion/CompletionAnalysis.cs | 2 +- .../CommandCompletion/CompletionCompleters.cs | 12 ++--- .../engine/CommandProcessor.cs | 2 +- .../engine/CoreAdapter.cs | 4 +- .../engine/ErrorPackage.cs | 2 +- .../engine/InternalCommands.cs | 2 +- .../engine/LanguagePrimitives.cs | 8 ++-- .../engine/ManagementObjectAdapter.cs | 4 +- .../engine/Modules/AnalysisCache.cs | 4 +- .../engine/MshCommandRuntime.cs | 2 +- .../engine/MshObject.cs | 8 ++-- .../engine/MshObjectTypeDescriptor.cs | 4 +- .../engine/PSVersionInfo.cs | 2 +- .../engine/SessionStateContainer.cs | 6 +-- .../engine/SessionStateProviderAPIs.cs | 20 ++++----- ...SessionStateSecurityDescriptorInterface.cs | 2 +- .../engine/TypeTable.cs | 2 +- .../engine/debugger/debugger.cs | 6 +-- .../engine/hostifaces/History.cs | 2 +- .../engine/hostifaces/HostUtilities.cs | 2 +- .../engine/hostifaces/InternalHost.cs | 2 +- .../engine/hostifaces/ListModifier.cs | 2 +- .../engine/hostifaces/PSDataCollection.cs | 2 +- .../engine/hostifaces/PowerShell.cs | 4 +- .../engine/interpreter/LightCompiler.cs | 2 +- .../engine/lang/parserutils.cs | 4 +- .../engine/runtime/CompiledScriptBlock.cs | 8 ++-- .../engine/runtime/ScriptBlockToPowerShell.cs | 2 +- .../engine/serialization.cs | 20 ++++----- .../namespaces/ProviderBase.cs | 44 +++++++++---------- .../utils/PsUtils.cs | 6 +-- .../utils/RuntimeException.cs | 2 +- 51 files changed, 131 insertions(+), 131 deletions(-) diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs index 023bf652b1d..e794fd929d1 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimAsyncOperation.cs @@ -381,7 +381,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re if (value is PSReference cimReference) { object baseObject = GetBaseObject(cimReference.Value); - if (!(baseObject is CimInstance cimInstance)) + if (baseObject is not CimInstance cimInstance) { return null; } @@ -403,7 +403,7 @@ protected object GetReferenceOrReferenceArrayObject(object value, ref CimType re CimInstance[] cimInstanceArray = new CimInstance[cimReferenceArray.Length]; for (int i = 0; i < cimReferenceArray.Length; i++) { - if (!(cimReferenceArray[i] is PSReference tempCimReference)) + if (cimReferenceArray[i] is not PSReference tempCimReference) { return null; } diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs index 630bb34dfb1..5cdc168ae24 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs @@ -2041,7 +2041,7 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) } CimWriteResultObject writeResultObject = args.Action as CimWriteResultObject; - if (!(writeResultObject.Result is CimClass cimClass)) + if (writeResultObject.Result is not CimClass cimClass) { return true; } @@ -2200,7 +2200,7 @@ protected override bool PreNewActionEvent(CmdletActionEventArgs args) } CimWriteResultObject writeResultObject = args.Action as CimWriteResultObject; - if (!(writeResultObject.Result is CimInstance cimInstance)) + if (writeResultObject.Result is not CimInstance cimInstance) { return true; } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs index d787389e9f0..6bd2bee7fee 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs @@ -84,7 +84,7 @@ private enum WsManErrorCode : uint private static bool IsWsManQuotaReached(Exception exception) { - if (!(exception is CimException cimException)) + if (exception is not CimException cimException) { return false; } @@ -1002,7 +1002,7 @@ private CimResponseType PromptUserCallback(string message, CimPromptType promptT internal static bool IsShowComputerNameMarkerPresent(CimInstance cimInstance) { PSObject pso = PSObject.AsPSObject(cimInstance); - if (!(pso.InstanceMembers[RemotingConstants.ShowComputerNameNoteProperty] is PSPropertyInfo psShowComputerNameProperty)) + if (pso.InstanceMembers[RemotingConstants.ShowComputerNameNoteProperty] is not PSPropertyInfo psShowComputerNameProperty) { return false; } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs index c812778456a..472046b192f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimWrapper.cs @@ -168,7 +168,7 @@ private CimJobContext CreateJobContext(CimSession session, object targetObject) /// object that performs a query against the wrapped object model. internal override StartableJob CreateQueryJob(CimSession session, QueryBuilder baseQuery) { - if (!(baseQuery is CimQuery query)) + if (baseQuery is not CimQuery query) { throw new ArgumentNullException(nameof(baseQuery)); } diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs index c8cee5d0111..c1a8552db8c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/clientSideQuery.cs @@ -569,7 +569,7 @@ private static bool ActualValueGreaterThanOrEqualToExpectedValue(string property { try { - if (!(expectedPropertyValue is IComparable expectedComparable)) + if (expectedPropertyValue is not IComparable expectedComparable) { return false; } @@ -604,7 +604,7 @@ private static bool ActualValueLessThanOrEqualToExpectedValue(string propertyNam { try { - if (!(actualPropertyValue is IComparable actualComparable)) + if (actualPropertyValue is not IComparable actualComparable) { return false; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs index f8a39cce096..6d224d29007 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs @@ -704,7 +704,7 @@ private void WriteMemberInfoCollection( continue; } - if (!(info is PSPropertyInfo property)) + if (info is not PSPropertyInfo property) { continue; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs index a42462737ea..65efee78a28 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/OutGridView/ColumnInfo.cs @@ -48,7 +48,7 @@ internal Type GetValueType(PSObject liveObject, out object columnValue) /// The source string limited in the number of lines. internal static object LimitString(object src) { - if (!(src is string srcString)) + if (src is not string srcString) { return src; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs index 85bb8fa53b7..c675a0f6dc1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Get-PSBreakpoint.cs @@ -115,7 +115,7 @@ protected override void ProcessRecord() Command, (Breakpoint breakpoint, string command) => { - if (!(breakpoint is CommandBreakpoint commandBreakpoint)) + if (breakpoint is not CommandBreakpoint commandBreakpoint) { return false; } @@ -130,7 +130,7 @@ protected override void ProcessRecord() Variable, (Breakpoint breakpoint, string variable) => { - if (!(breakpoint is VariableBreakpoint variableBreakpoint)) + if (breakpoint is not VariableBreakpoint variableBreakpoint) { return false; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs index 16b7db47d41..d01d144caca 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs @@ -2620,7 +2620,7 @@ private string GenerateConnectionStringForNewRunspace() private string GenerateAllowRedirectionParameter() { - if (!(_remoteRunspaceInfo.Runspace.ConnectionInfo is WSManConnectionInfo wsmanConnectionInfo)) + if (_remoteRunspaceInfo.Runspace.ConnectionInfo is not WSManConnectionInfo wsmanConnectionInfo) { return string.Empty; } @@ -2646,7 +2646,7 @@ private string GenerateAuthenticationMechanismParameter() return string.Empty; } - if (!(_remoteRunspaceInfo.Runspace.ConnectionInfo is WSManConnectionInfo wsmanConnectionInfo)) + if (_remoteRunspaceInfo.Runspace.ConnectionInfo is not WSManConnectionInfo wsmanConnectionInfo) { return string.Empty; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs index fd01768d5a8..13b0234a02b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ObjectCommandComparer.cs @@ -77,7 +77,7 @@ internal CultureInfo Culture /// True if both the objects are same or else returns false. public override bool Equals(object inputObject) { - if (!(inputObject is ObjectCommandPropertyValue objectCommandPropertyValueObject)) + if (inputObject is not ObjectCommandPropertyValue objectCommandPropertyValueObject) { return false; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs index 178eaa12f62..596bbcaafc6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/OrderObjectBase.cs @@ -358,7 +358,7 @@ internal static string[] GetDefaultKeyPropertySet(PSObject mshObj) return null; } - if (!(standardNames.Members["DefaultKeyPropertySet"] is PSPropertySet defaultKeys)) + if (standardNames.Members["DefaultKeyPropertySet"] is not PSPropertySet defaultKeys) { return null; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs index b626fd71db8..6506f2bd2ce 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs @@ -662,7 +662,7 @@ private static object ProcessValue(object obj, int currentDepth, in ConvertToJso /// private static object AddPsProperties(object psObj, object obj, int depth, bool isPurePSObj, bool isCustomObj, in ConvertToJsonContext context) { - if (!(psObj is PSObject pso)) + if (psObj is not PSObject pso) { return obj; } diff --git a/src/Microsoft.PowerShell.Security/security/AclCommands.cs b/src/Microsoft.PowerShell.Security/security/AclCommands.cs index 1b5beffa49e..e39b296d154 100644 --- a/src/Microsoft.PowerShell.Security/security/AclCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/AclCommands.cs @@ -207,7 +207,7 @@ public static string GetOwner(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is ObjectSecurity sd)) + if (instance.BaseObject is not ObjectSecurity sd) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } @@ -246,7 +246,7 @@ public static string GetGroup(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is ObjectSecurity sd)) + if (instance.BaseObject is not ObjectSecurity sd) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } @@ -570,7 +570,7 @@ public static string GetSddl(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is ObjectSecurity sd)) + if (instance.BaseObject is not ObjectSecurity sd) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } diff --git a/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/typeDataQuery.cs b/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/typeDataQuery.cs index c759cabd2a1..de6df333951 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/typeDataQuery.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/typeDataQuery.cs @@ -606,7 +606,7 @@ internal static AppliesTo GetAllApplicableTypes(TypeInfoDataBase db, AppliesTo a else { // check if we have a type group reference - if (!(r is TypeGroupReference tgr)) + if (r is not TypeGroupReference tgr) continue; // find the type group definition the reference points to diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormattingObjectsDeserializer.cs b/src/System.Management.Automation/FormatAndOutput/common/FormattingObjectsDeserializer.cs index 00923a103ec..7ae144702ba 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormattingObjectsDeserializer.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormattingObjectsDeserializer.cs @@ -54,7 +54,7 @@ fid is GroupEndData || return false; } - if (!(GetProperty(so, FormatInfoData.classidProperty) is string classId)) + if (GetProperty(so, FormatInfoData.classidProperty) is not string classId) { // it's not one of the objects derived from FormatInfoData return false; @@ -109,7 +109,7 @@ fid is GroupEndData || return so; } - if (!(GetProperty(so, FormatInfoData.classidProperty) is string classId)) + if (GetProperty(so, FormatInfoData.classidProperty) is not string classId) { // it's not one of the objects derived from FormatInfoData, // just return it as is diff --git a/src/System.Management.Automation/cimSupport/other/ciminstancetypeadapter.cs b/src/System.Management.Automation/cimSupport/other/ciminstancetypeadapter.cs index 9a3e5f137ad..202c3e98e48 100644 --- a/src/System.Management.Automation/cimSupport/other/ciminstancetypeadapter.cs +++ b/src/System.Management.Automation/cimSupport/other/ciminstancetypeadapter.cs @@ -267,7 +267,7 @@ private static List GetInheritanceChain(CimInstance cimInstance) /// public override Collection GetTypeNameHierarchy(object baseObject) { - if (!(baseObject is CimInstance cimInstance)) + if (baseObject is not CimInstance cimInstance) { throw new ArgumentNullException(nameof(baseObject)); } @@ -343,7 +343,7 @@ public override bool IsSettable(PSAdaptedProperty adaptedProperty) return false; } - if (!(adaptedProperty.Tag is CimProperty cimProperty)) + if (adaptedProperty.Tag is not CimProperty cimProperty) { return false; } diff --git a/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs b/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs index a2c2cd8321e..596a4142e93 100644 --- a/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs +++ b/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs @@ -65,7 +65,7 @@ internal object Transform(EngineIntrinsics engineIntrinsics, object inputData, b else temp = result; - if (!(temp is PSReference reference)) + if (temp is not PSReference reference) { throw new PSInvalidCastException("InvalidCastExceptionReferenceTypeExpected", null, ExtendedTypeSystem.ReferenceTypeExpected); diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index 2f7de2a2149..31c520498c0 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -844,7 +844,7 @@ public sealed class ValidateLengthAttribute : ValidateEnumeratedArgumentsAttribu /// For invalid arguments. protected override void ValidateElement(object element) { - if (!(element is string objectString)) + if (element is not string objectString) { throw new ValidationMetadataException( "ValidateLengthNotString", @@ -1956,7 +1956,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin Metadata.ValidateNotNullFailure); } - if (!(arguments is string path)) + if (arguments is not string path) { throw new ValidationMetadataException( "PathArgumentIsNotValid", diff --git a/src/System.Management.Automation/engine/CmdletParameterBinderController.cs b/src/System.Management.Automation/engine/CmdletParameterBinderController.cs index 88fadc3342d..b9cf67b29e6 100644 --- a/src/System.Management.Automation/engine/CmdletParameterBinderController.cs +++ b/src/System.Management.Automation/engine/CmdletParameterBinderController.cs @@ -622,7 +622,7 @@ private Dictionary GetDefaultParameterVa foreach (DictionaryEntry entry in DefaultParameterValues) { - if (!(entry.Key is string key)) + if (entry.Key is not string key) { continue; } @@ -4386,7 +4386,7 @@ public override bool ContainsKey(object key) throw PSTraceSource.NewArgumentNullException(nameof(key)); } - if (!(key is string strKey)) + if (key is not string strKey) { return false; } @@ -4415,7 +4415,7 @@ private void AddImpl(object key, object value, bool isSelfIndexing) throw PSTraceSource.NewArgumentNullException(nameof(key)); } - if (!(key is string strKey)) + if (key is not string strKey) { throw PSTraceSource.NewArgumentException(nameof(key), ParameterBinderStrings.StringValueKeyExpected, key, key.GetType().FullName); } @@ -4463,7 +4463,7 @@ public override object this[object key] throw PSTraceSource.NewArgumentNullException(nameof(key)); } - if (!(key is string strKey)) + if (key is not string strKey) { return null; } @@ -4489,7 +4489,7 @@ public override void Remove(object key) throw PSTraceSource.NewArgumentNullException(nameof(key)); } - if (!(key is string strKey)) + if (key is not string strKey) { return; } diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs index 42a60ab7e0e..e4d8203a63b 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs @@ -262,7 +262,7 @@ private static bool CompleteAgainstSwitchFile(Ast lastAst, Token tokenBeforeCurs if (lastAst.Parent is CommandExpressionAst) { // Handle "switch -file m" or "switch -file *.ps1" - if (!(lastAst.Parent.Parent is PipelineAst pipeline)) + if (lastAst.Parent.Parent is not PipelineAst pipeline) { return false; } diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 2b90bc02837..16b0d1edac4 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -602,7 +602,7 @@ internal static List CompleteCommandParameter(CompletionContex else { // No CommandParameterAst is found. It could be a StringConstantExpressionAst "-" - if (!(context.RelatedAsts[context.RelatedAsts.Count - 1] is StringConstantExpressionAst dashAst)) + if (context.RelatedAsts[context.RelatedAsts.Count - 1] is not StringConstantExpressionAst dashAst) return result; if (!dashAst.Value.Trim().Equals("-", StringComparison.OrdinalIgnoreCase)) return result; @@ -3130,7 +3130,7 @@ private static void NativeCompletionCimNamespace( continue; } - if (!(namespaceNameProperty.Value is string childNamespace)) + if (namespaceNameProperty.Value is not string childNamespace) { continue; } @@ -6059,7 +6059,7 @@ internal static List CompleteComment(CompletionContext context for (int index = psobjs.Count - 1; index >= 0; index--) { var psobj = psobjs[index]; - if (!(PSObject.Base(psobj) is HistoryInfo historyInfo)) continue; + if (PSObject.Base(psobj) is not HistoryInfo historyInfo) continue; var commandLine = historyInfo.CommandLine; if (!string.IsNullOrEmpty(commandLine) && pattern.IsMatch(commandLine)) @@ -8560,7 +8560,7 @@ internal static bool IsPathSafelyExpandable(ExpandableStringExpressionAst expand var varValues = new List(); foreach (ExpressionAst nestedAst in expandableStringAst.NestedExpressions) { - if (!(nestedAst is VariableExpressionAst variableAst)) { return false; } + if (nestedAst is not VariableExpressionAst variableAst) { return false; } string strValue = CombineVariableWithPartialPath(variableAst, null, executionContext); if (strValue != null) @@ -8688,7 +8688,7 @@ internal static void CompleteMemberHelper( IEnumerable members; if (@static) { - if (!(PSObject.Base(value) is Type type)) + if (PSObject.Base(value) is not Type type) { return; } @@ -8754,7 +8754,7 @@ internal static void CompleteMemberHelper( var pattern = WildcardPattern.Get(memberName, WildcardOptions.IgnoreCase); foreach (DictionaryEntry entry in dictionary) { - if (!(entry.Key is string key)) + if (entry.Key is not string key) continue; if (pattern.IsMatch(key)) diff --git a/src/System.Management.Automation/engine/CommandProcessor.cs b/src/System.Management.Automation/engine/CommandProcessor.cs index d9758cea2fa..d1ef250d717 100644 --- a/src/System.Management.Automation/engine/CommandProcessor.cs +++ b/src/System.Management.Automation/engine/CommandProcessor.cs @@ -101,7 +101,7 @@ internal CommandProcessor(IScriptCommandInfo scriptCommandInfo, ExecutionContext /// internal ParameterBinderController NewParameterBinderController(InternalCommand command) { - if (!(command is Cmdlet cmdlet)) + if (command is not Cmdlet cmdlet) { throw PSTraceSource.NewArgumentException(nameof(command)); } diff --git a/src/System.Management.Automation/engine/CoreAdapter.cs b/src/System.Management.Automation/engine/CoreAdapter.cs index 907060bfe49..136083d04d7 100644 --- a/src/System.Management.Automation/engine/CoreAdapter.cs +++ b/src/System.Management.Automation/engine/CoreAdapter.cs @@ -1723,7 +1723,7 @@ internal static void SetReferences(object[] arguments, MethodInformation methodI // It still might be an PSObject wrapping an PSReference if (originalArgumentReference == null) { - if (!(originalArgument is PSObject originalArgumentObj)) + if (originalArgument is not PSObject originalArgumentObj) { continue; } @@ -3860,7 +3860,7 @@ internal void AddAllDynamicMembers(object obj, PSMemberInfoInternalCollection private static bool PropertyIsStatic(PSProperty property) { - if (!(property.adapterData is PropertyCacheEntry entry)) + if (property.adapterData is not PropertyCacheEntry entry) { return false; } diff --git a/src/System.Management.Automation/engine/ErrorPackage.cs b/src/System.Management.Automation/engine/ErrorPackage.cs index b20da137590..baa2dd215de 100644 --- a/src/System.Management.Automation/engine/ErrorPackage.cs +++ b/src/System.Management.Automation/engine/ErrorPackage.cs @@ -1665,7 +1665,7 @@ private string GetInvocationTypeName() return commandInfo.Name; } - if (!(commandInfo is CmdletInfo cmdletInfo)) + if (commandInfo is not CmdletInfo cmdletInfo) { return string.Empty; } diff --git a/src/System.Management.Automation/engine/InternalCommands.cs b/src/System.Management.Automation/engine/InternalCommands.cs index 39556db9cca..844a965ac1e 100644 --- a/src/System.Management.Automation/engine/InternalCommands.cs +++ b/src/System.Management.Automation/engine/InternalCommands.cs @@ -2018,7 +2018,7 @@ private void CheckLanguageMode() private object GetLikeRHSOperand(object operand) { - if (!(operand is string val)) + if (operand is not string val) { return operand; } diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs index 6644223d7c6..fa9e68f5c24 100644 --- a/src/System.Management.Automation/engine/LanguagePrimitives.cs +++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs @@ -636,7 +636,7 @@ public static bool Equals(object first, object second, bool ignoreCase, IFormatP formatProvider ??= CultureInfo.InvariantCulture; - if (!(formatProvider is CultureInfo culture)) + if (formatProvider is not CultureInfo culture) { throw PSTraceSource.NewArgumentException(nameof(formatProvider)); } @@ -780,7 +780,7 @@ public static int Compare(object first, object second, bool ignoreCase, IFormatP { formatProvider ??= CultureInfo.InvariantCulture; - if (!(formatProvider is CultureInfo culture)) + if (formatProvider is not CultureInfo culture) { throw PSTraceSource.NewArgumentException(nameof(formatProvider)); } @@ -1036,7 +1036,7 @@ internal static bool IsTrue(IList objectArray) // but since we don't want this to recurse indefinitely // we explicitly check the case where it would recurse // and deal with it. - if (!(PSObject.Base(objectArray[0]) is IList firstElement)) + if (PSObject.Base(objectArray[0]) is not IList firstElement) { return IsTrue(objectArray[0]); } @@ -2100,7 +2100,7 @@ public override object ConvertFrom(object sourceValue, Type destinationType, IFo protected static object BaseConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase, bool multipleValues) { Diagnostics.Assert(sourceValue != null, "the type converter has a special case for null source values"); - if (!(sourceValue is string sourceValueString)) + if (sourceValue is not string sourceValueString) { throw new PSInvalidCastException("InvalidCastEnumFromTypeNotAString", null, ExtendedTypeSystem.InvalidCastException, diff --git a/src/System.Management.Automation/engine/ManagementObjectAdapter.cs b/src/System.Management.Automation/engine/ManagementObjectAdapter.cs index aa1c151e0e3..9b69ee168d7 100644 --- a/src/System.Management.Automation/engine/ManagementObjectAdapter.cs +++ b/src/System.Management.Automation/engine/ManagementObjectAdapter.cs @@ -172,7 +172,7 @@ protected override T GetMember(object obj, string memberName) { tracer.WriteLine("Getting member with name {0}", memberName); - if (!(obj is ManagementBaseObject mgmtObject)) + if (obj is not ManagementBaseObject mgmtObject) { return null; } @@ -364,7 +364,7 @@ protected override object PropertyGet(PSProperty property) /// Instructs the adapter to convert before setting, if the adapter supports conversion. protected override void PropertySet(PSProperty property, object setValue, bool convertIfPossible) { - if (!(property.baseObject is ManagementBaseObject mObj)) + if (property.baseObject is not ManagementBaseObject mObj) { throw new SetValueInvocationException("CannotSetNonManagementObjectMsg", null, diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 44dc9f1b610..79085041abd 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -194,7 +194,7 @@ internal static bool ModuleIsEditionIncompatible(string modulePath, Hashtable mo internal static bool ModuleAnalysisViaGetModuleRequired(object modulePathObj, bool hadCmdlets, bool hadFunctions, bool hadAliases) { - if (!(modulePathObj is string modulePath)) + if (modulePathObj is not string modulePath) return true; if (modulePath.EndsWith(StringLiterals.PowerShellModuleFileExtension, StringComparison.OrdinalIgnoreCase)) @@ -256,7 +256,7 @@ private static bool CheckModulesTypesInManifestAgainstExportedCommands(Hashtable return ModuleAnalysisViaGetModuleRequired(nestedModule, hadCmdlets, hadFunctions, hadAliases); } - if (!(nestedModules is object[] nestedModuleArray)) + if (nestedModules is not object[] nestedModuleArray) return true; foreach (var element in nestedModuleArray) diff --git a/src/System.Management.Automation/engine/MshCommandRuntime.cs b/src/System.Management.Automation/engine/MshCommandRuntime.cs index 2e5cdb455b7..d5f821bc930 100644 --- a/src/System.Management.Automation/engine/MshCommandRuntime.cs +++ b/src/System.Management.Automation/engine/MshCommandRuntime.cs @@ -2360,7 +2360,7 @@ internal AllowWrite(InternalCommand permittedToWrite, bool permittedToWriteToPip { if (permittedToWrite == null) throw PSTraceSource.NewArgumentNullException(nameof(permittedToWrite)); - if (!(permittedToWrite.commandRuntime is MshCommandRuntime mcr)) + if (permittedToWrite.commandRuntime is not MshCommandRuntime mcr) throw PSTraceSource.NewArgumentNullException("permittedToWrite.CommandRuntime"); _pp = mcr.PipelineProcessor; if (_pp == null) diff --git a/src/System.Management.Automation/engine/MshObject.cs b/src/System.Management.Automation/engine/MshObject.cs index d788a8a3b43..c5e8bbac443 100644 --- a/src/System.Management.Automation/engine/MshObject.cs +++ b/src/System.Management.Automation/engine/MshObject.cs @@ -592,7 +592,7 @@ protected PSObject(SerializationInfo info, StreamingContext context) throw PSTraceSource.NewArgumentNullException(nameof(info)); } - if (!(info.GetValue("CliXml", typeof(string)) is string serializedData)) + if (info.GetValue("CliXml", typeof(string)) is not string serializedData) { throw PSTraceSource.NewArgumentNullException(nameof(info)); } @@ -980,7 +980,7 @@ public static implicit operator PSObject(bool valueToConvert) /// internal static object Base(object obj) { - if (!(obj is PSObject mshObj)) + if (obj is not PSObject mshObj) { return obj; } @@ -1064,7 +1064,7 @@ internal static PSObject AsPSObject(object obj, bool storeTypeNameAndInstanceMem /// internal static object GetKeyForResurrectionTables(object obj) { - if (!(obj is PSObject pso)) + if (obj is not PSObject pso) { return obj; } @@ -1851,7 +1851,7 @@ internal static object GetNoteSettingValue(PSMemberSet settings, string noteName settings.ReplicateInstance(ownerObject); } - if (!(settings.Members[noteName] is PSNoteProperty note)) + if (settings.Members[noteName] is not PSNoteProperty note) { return defaultValue; } diff --git a/src/System.Management.Automation/engine/MshObjectTypeDescriptor.cs b/src/System.Management.Automation/engine/MshObjectTypeDescriptor.cs index 11955713c7e..113161748c9 100644 --- a/src/System.Management.Automation/engine/MshObjectTypeDescriptor.cs +++ b/src/System.Management.Automation/engine/MshObjectTypeDescriptor.cs @@ -219,7 +219,7 @@ private static PSObject GetComponentPSObject(object component) PSObject mshObj = component as PSObject; if (mshObj == null) { - if (!(component is PSObjectTypeDescriptor descriptor)) + if (component is not PSObjectTypeDescriptor descriptor) { throw PSTraceSource.NewArgumentException(nameof(component), ExtendedTypeSystem.InvalidComponent, "component", @@ -464,7 +464,7 @@ public override PropertyDescriptorCollection GetProperties(Attribute[] attribute /// True if the Instance property of is equal to the current Instance; otherwise, false. public override bool Equals(object obj) { - if (!(obj is PSObjectTypeDescriptor other)) + if (obj is not PSObjectTypeDescriptor other) { return false; } diff --git a/src/System.Management.Automation/engine/PSVersionInfo.cs b/src/System.Management.Automation/engine/PSVersionInfo.cs index 75f75cc112f..eef9819a568 100644 --- a/src/System.Management.Automation/engine/PSVersionInfo.cs +++ b/src/System.Management.Automation/engine/PSVersionInfo.cs @@ -795,7 +795,7 @@ public int CompareTo(object version) return 1; } - if (!(version is SemanticVersion v)) + if (version is not SemanticVersion v) { throw PSTraceSource.NewArgumentException(nameof(version)); } diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index e97d62c87d1..fa8884b92e8 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -1839,7 +1839,7 @@ private void ProcessPathItems( return; } - if (!(childNameObjects[index].BaseObject is string childName)) + if (childNameObjects[index].BaseObject is not string childName) { continue; } @@ -2584,7 +2584,7 @@ private void DoGetChildNamesManually( return; } - if (!(result.BaseObject is string name)) + if (result.BaseObject is not string name) { continue; } @@ -2632,7 +2632,7 @@ private void DoGetChildNamesManually( return; } - if (!(result.BaseObject is string name)) + if (result.BaseObject is not string name) { continue; } diff --git a/src/System.Management.Automation/engine/SessionStateProviderAPIs.cs b/src/System.Management.Automation/engine/SessionStateProviderAPIs.cs index 0c94c9ea059..3ad2ed99e31 100644 --- a/src/System.Management.Automation/engine/SessionStateProviderAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateProviderAPIs.cs @@ -350,7 +350,7 @@ internal DriveCmdletProvider GetDriveProviderInstance(string providerId) throw PSTraceSource.NewArgumentNullException(nameof(providerId)); } - if (!(GetProviderInstance(providerId) is DriveCmdletProvider driveCmdletProvider)) + if (GetProviderInstance(providerId) is not DriveCmdletProvider driveCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); @@ -382,7 +382,7 @@ internal DriveCmdletProvider GetDriveProviderInstance(ProviderInfo provider) throw PSTraceSource.NewArgumentNullException(nameof(provider)); } - if (!(GetProviderInstance(provider) is DriveCmdletProvider driveCmdletProvider)) + if (GetProviderInstance(provider) is not DriveCmdletProvider driveCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); @@ -414,7 +414,7 @@ private static DriveCmdletProvider GetDriveProviderInstance(CmdletProvider provi throw PSTraceSource.NewArgumentNullException(nameof(providerInstance)); } - if (!(providerInstance is DriveCmdletProvider driveCmdletProvider)) + if (providerInstance is not DriveCmdletProvider driveCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); @@ -449,7 +449,7 @@ internal ItemCmdletProvider GetItemProviderInstance(string providerId) throw PSTraceSource.NewArgumentNullException(nameof(providerId)); } - if (!(GetProviderInstance(providerId) is ItemCmdletProvider itemCmdletProvider)) + if (GetProviderInstance(providerId) is not ItemCmdletProvider itemCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); @@ -481,7 +481,7 @@ internal ItemCmdletProvider GetItemProviderInstance(ProviderInfo provider) throw PSTraceSource.NewArgumentNullException(nameof(provider)); } - if (!(GetProviderInstance(provider) is ItemCmdletProvider itemCmdletProvider)) + if (GetProviderInstance(provider) is not ItemCmdletProvider itemCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); @@ -513,7 +513,7 @@ private static ItemCmdletProvider GetItemProviderInstance(CmdletProvider provide throw PSTraceSource.NewArgumentNullException(nameof(providerInstance)); } - if (!(providerInstance is ItemCmdletProvider itemCmdletProvider)) + if (providerInstance is not ItemCmdletProvider itemCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); @@ -548,7 +548,7 @@ internal ContainerCmdletProvider GetContainerProviderInstance(string providerId) throw PSTraceSource.NewArgumentNullException(nameof(providerId)); } - if (!(GetProviderInstance(providerId) is ContainerCmdletProvider containerCmdletProvider)) + if (GetProviderInstance(providerId) is not ContainerCmdletProvider containerCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); @@ -580,7 +580,7 @@ internal ContainerCmdletProvider GetContainerProviderInstance(ProviderInfo provi throw PSTraceSource.NewArgumentNullException(nameof(provider)); } - if (!(GetProviderInstance(provider) is ContainerCmdletProvider containerCmdletProvider)) + if (GetProviderInstance(provider) is not ContainerCmdletProvider containerCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); @@ -612,7 +612,7 @@ private static ContainerCmdletProvider GetContainerProviderInstance(CmdletProvid throw PSTraceSource.NewArgumentNullException(nameof(providerInstance)); } - if (!(providerInstance is ContainerCmdletProvider containerCmdletProvider)) + if (providerInstance is not ContainerCmdletProvider containerCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); @@ -644,7 +644,7 @@ internal NavigationCmdletProvider GetNavigationProviderInstance(ProviderInfo pro throw PSTraceSource.NewArgumentNullException(nameof(provider)); } - if (!(GetProviderInstance(provider) is NavigationCmdletProvider navigationCmdletProvider)) + if (GetProviderInstance(provider) is not NavigationCmdletProvider navigationCmdletProvider) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.NavigationCmdletProvider_NotSupported); diff --git a/src/System.Management.Automation/engine/SessionStateSecurityDescriptorInterface.cs b/src/System.Management.Automation/engine/SessionStateSecurityDescriptorInterface.cs index 16ebe0fc3b5..08635c7efe1 100644 --- a/src/System.Management.Automation/engine/SessionStateSecurityDescriptorInterface.cs +++ b/src/System.Management.Automation/engine/SessionStateSecurityDescriptorInterface.cs @@ -35,7 +35,7 @@ internal static ISecurityDescriptorCmdletProvider GetPermissionProviderInstance( throw PSTraceSource.NewArgumentNullException(nameof(providerInstance)); } - if (!(providerInstance is ISecurityDescriptorCmdletProvider permissionCmdletProvider)) + if (providerInstance is not ISecurityDescriptorCmdletProvider permissionCmdletProvider) { throw PSTraceSource.NewNotSupportedException( diff --git a/src/System.Management.Automation/engine/TypeTable.cs b/src/System.Management.Automation/engine/TypeTable.cs index bffeb9e0ceb..a0eead95e23 100644 --- a/src/System.Management.Automation/engine/TypeTable.cs +++ b/src/System.Management.Automation/engine/TypeTable.cs @@ -3922,7 +3922,7 @@ internal Collection GetSpecificProperties(ConsolidatedString types) } PSMemberSet settings = typeMembers[PSStandardMembers] as PSMemberSet; - if (!(settings?.Members[PropertySerializationSet] is PSPropertySet typeProperties)) + if (settings?.Members[PropertySerializationSet] is not PSPropertySet typeProperties) { continue; } diff --git a/src/System.Management.Automation/engine/debugger/debugger.cs b/src/System.Management.Automation/engine/debugger/debugger.cs index bdad4960ac0..e093210f960 100644 --- a/src/System.Management.Automation/engine/debugger/debugger.cs +++ b/src/System.Management.Automation/engine/debugger/debugger.cs @@ -2368,7 +2368,7 @@ public override DebuggerCommandResults ProcessCommand(PSCommand command, PSDataC // // Otherwise let root script debugger handle it. // - if (!(_context.CurrentRunspace is LocalRunspace localRunspace)) + if (_context.CurrentRunspace is not LocalRunspace localRunspace) { throw new PSInvalidOperationException( DebuggerStrings.CannotProcessDebuggerCommandNotStopped, @@ -3829,7 +3829,7 @@ private void HandleMonitorRunningRSDebuggerStop(object sender, DebuggerStopEvent } // Get nested debugger runspace info. - if (!(senderDebugger is NestedRunspaceDebugger nestedDebugger)) { return; } + if (senderDebugger is not NestedRunspaceDebugger nestedDebugger) { return; } PSMonitorRunspaceType runspaceType = nestedDebugger.RunspaceType; @@ -4686,7 +4686,7 @@ protected override void HandleDebuggerStop(object sender, DebuggerStopEventArgs private object DrainAndBlockRemoteOutput() { // We do this only for remote runspaces. - if (!(_runspace is RemoteRunspace remoteRunspace)) { return null; } + if (_runspace is not RemoteRunspace remoteRunspace) { return null; } var runningPowerShell = remoteRunspace.GetCurrentBasePowerShell(); if (runningPowerShell != null) diff --git a/src/System.Management.Automation/engine/hostifaces/History.cs b/src/System.Management.Automation/engine/hostifaces/History.cs index 3b503f2fade..00a090d4b22 100644 --- a/src/System.Management.Automation/engine/hostifaces/History.cs +++ b/src/System.Management.Automation/engine/hostifaces/History.cs @@ -1436,7 +1436,7 @@ void ProcessRecord() } // Read CommandLine property - if (!(GetPropertyValue(mshObject, "CommandLine") is string commandLine)) + if (GetPropertyValue(mshObject, "CommandLine") is not string commandLine) { break; } diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 003625791b1..ba71fef0443 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -284,7 +284,7 @@ internal static string GetMaxLines(string source, int maxLines) internal static List GetSuggestion(Runspace runspace) { - if (!(runspace is LocalRunspace localRunspace)) + if (runspace is not LocalRunspace localRunspace) { return new List(); } diff --git a/src/System.Management.Automation/engine/hostifaces/InternalHost.cs b/src/System.Management.Automation/engine/hostifaces/InternalHost.cs index 450941b4b63..c60bff90303 100644 --- a/src/System.Management.Automation/engine/hostifaces/InternalHost.cs +++ b/src/System.Management.Automation/engine/hostifaces/InternalHost.cs @@ -448,7 +448,7 @@ public override void NotifyEndApplication() /// private IHostSupportsInteractiveSession GetIHostSupportsInteractiveSession() { - if (!(_externalHostRef.Value is IHostSupportsInteractiveSession host)) + if (_externalHostRef.Value is not IHostSupportsInteractiveSession host) { throw new PSNotImplementedException(); } diff --git a/src/System.Management.Automation/engine/hostifaces/ListModifier.cs b/src/System.Management.Automation/engine/hostifaces/ListModifier.cs index db089b68333..aab1cb2e777 100644 --- a/src/System.Management.Automation/engine/hostifaces/ListModifier.cs +++ b/src/System.Management.Automation/engine/hostifaces/ListModifier.cs @@ -216,7 +216,7 @@ public void ApplyTo(object collectionToUpdate) collectionToUpdate = PSObject.Base(collectionToUpdate); - if (!(collectionToUpdate is IList list)) + if (collectionToUpdate is not IList list) { throw PSTraceSource.NewInvalidOperationException(PSListModifierStrings.UpdateFailed); } diff --git a/src/System.Management.Automation/engine/hostifaces/PSDataCollection.cs b/src/System.Management.Automation/engine/hostifaces/PSDataCollection.cs index eb1a796d0e7..a0945e21df1 100644 --- a/src/System.Management.Automation/engine/hostifaces/PSDataCollection.cs +++ b/src/System.Management.Automation/engine/hostifaces/PSDataCollection.cs @@ -335,7 +335,7 @@ protected PSDataCollection(SerializationInfo info, StreamingContext context) throw PSTraceSource.NewArgumentNullException(nameof(info)); } - if (!(info.GetValue("Data", typeof(IList)) is IList listToUse)) + if (info.GetValue("Data", typeof(IList)) is not IList listToUse) { throw PSTraceSource.NewArgumentNullException(nameof(info)); } diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs index 7d29ffa5223..7073437d7e9 100644 --- a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs +++ b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs @@ -1369,7 +1369,7 @@ public PowerShell AddParameters(IDictionary parameters) foreach (DictionaryEntry entry in parameters) { - if (!(entry.Key is string parameterName)) + if (entry.Key is not string parameterName) { throw PSTraceSource.NewArgumentException(nameof(parameters), PowerShellStrings.KeyMustBeString); } @@ -3348,7 +3348,7 @@ public Task> InvokeAsync(PSDataColle /// private IAsyncResult BeginBatchInvoke(PSDataCollection input, PSDataCollection output, PSInvocationSettings settings, AsyncCallback callback, object state) { - if (!((object)output is PSDataCollection asyncOutput)) + if ((object)output is not PSDataCollection asyncOutput) { throw PSTraceSource.NewInvalidOperationException(); } diff --git a/src/System.Management.Automation/engine/interpreter/LightCompiler.cs b/src/System.Management.Automation/engine/interpreter/LightCompiler.cs index a006b7e0f4f..c117fbff33a 100644 --- a/src/System.Management.Automation/engine/interpreter/LightCompiler.cs +++ b/src/System.Management.Automation/engine/interpreter/LightCompiler.cs @@ -1298,7 +1298,7 @@ private bool TryPushLabelBlock(Expression node) private void DefineBlockLabels(Expression node) { - if (!(node is BlockExpression block)) + if (node is not BlockExpression block) { return; } diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index eb438a8a057..184c82c6815 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -1466,7 +1466,7 @@ internal static string GetTypeFullName(object obj) return string.Empty; } - if (!(obj is PSObject mshObj)) + if (obj is not PSObject mshObj) { return obj.GetType().FullName; } @@ -1570,7 +1570,7 @@ internal static object CallMethod( // not really a method call. if (valueToSet != AutomationNull.Value) { - if (!(targetMethod is PSParameterizedProperty propertyToSet)) + if (targetMethod is not PSParameterizedProperty propertyToSet) { throw InterpreterError.NewInterpreterException(methodName, typeof(RuntimeException), errorPosition, "ParameterizedPropertyAssignmentFailed", ParserStrings.ParameterizedPropertyAssignmentFailed, GetTypeFullName(target), methodName); diff --git a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs index 2569dd3a492..f4829bc3547 100644 --- a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs +++ b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs @@ -196,7 +196,7 @@ private void ReallyCompile(bool optimize) private void PerformSecurityChecks() { - if (!(Ast is ScriptBlockAst scriptBlockAst)) + if (Ast is not ScriptBlockAst scriptBlockAst) { // Checks are only needed at the top level. return; @@ -266,12 +266,12 @@ bool IsScriptBlockInFactASafeHashtable() return false; } - if (!(endBlock.Statements[0] is PipelineAst pipelineAst)) + if (endBlock.Statements[0] is not PipelineAst pipelineAst) { return false; } - if (!(pipelineAst.GetPureExpression() is HashtableAst hashtableAst)) + if (pipelineAst.GetPureExpression() is not HashtableAst hashtableAst) { return false; } @@ -769,7 +769,7 @@ private PipelineAst GetSimplePipeline(Func errorHandler) return errorHandler(AutomationExceptions.CantConvertScriptBlockWithTrap); } - if (!(statements[0] is PipelineAst pipeAst)) + if (statements[0] is not PipelineAst pipeAst) { return errorHandler(AutomationExceptions.CanOnlyConvertOnePipeline); } diff --git a/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs b/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs index b0017080571..d0b7ef20680 100644 --- a/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs +++ b/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs @@ -542,7 +542,7 @@ private static Tuple, object[]> GetUsingValues( if (variables != null) { - if (!(usingAst.SubExpression is VariableExpressionAst variableAst)) + if (usingAst.SubExpression is not VariableExpressionAst variableAst) { throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException), usingAst.Extent, "CantGetUsingExpressionValueWithSpecifiedVariableDictionary", AutomationExceptions.CantGetUsingExpressionValueWithSpecifiedVariableDictionary, usingAst.Extent.Text); diff --git a/src/System.Management.Automation/engine/serialization.cs b/src/System.Management.Automation/engine/serialization.cs index 3cffd998d49..add0eab25dc 100644 --- a/src/System.Management.Automation/engine/serialization.cs +++ b/src/System.Management.Automation/engine/serialization.cs @@ -2018,7 +2018,7 @@ int depth foreach (PSMemberInfo info in propertyCollection) { - if (!(info is PSProperty prop)) + if (info is not PSProperty prop) { continue; } @@ -3373,28 +3373,28 @@ private CimClass RehydrateCimClass(PSPropertyInfo classMetadataProperty) PSObject psoDeserializedClass = PSObject.AsPSObject(deserializedClass); - if (!(psoDeserializedClass.InstanceMembers[InternalDeserializer.CimNamespaceProperty] is PSPropertyInfo namespaceProperty)) + if (psoDeserializedClass.InstanceMembers[InternalDeserializer.CimNamespaceProperty] is not PSPropertyInfo namespaceProperty) { return null; } string cimNamespace = namespaceProperty.Value as string; - if (!(psoDeserializedClass.InstanceMembers[InternalDeserializer.CimClassNameProperty] is PSPropertyInfo classNameProperty)) + if (psoDeserializedClass.InstanceMembers[InternalDeserializer.CimClassNameProperty] is not PSPropertyInfo classNameProperty) { return null; } string cimClassName = classNameProperty.Value as string; - if (!(psoDeserializedClass.InstanceMembers[InternalDeserializer.CimServerNameProperty] is PSPropertyInfo computerNameProperty)) + if (psoDeserializedClass.InstanceMembers[InternalDeserializer.CimServerNameProperty] is not PSPropertyInfo computerNameProperty) { return null; } string computerName = computerNameProperty.Value as string; - if (!(psoDeserializedClass.InstanceMembers[InternalDeserializer.CimHashCodeProperty] is PSPropertyInfo hashCodeProperty)) + if (psoDeserializedClass.InstanceMembers[InternalDeserializer.CimHashCodeProperty] is not PSPropertyInfo hashCodeProperty) { return null; } @@ -3511,7 +3511,7 @@ private PSObject RehydrateCimInstance(PSObject deserializedObject) { foreach (PSMemberInfo deserializedMemberInfo in deserializedObject.AdaptedMembers) { - if (!(deserializedMemberInfo is PSPropertyInfo deserializedProperty)) + if (deserializedMemberInfo is not PSPropertyInfo deserializedProperty) { continue; } @@ -3531,7 +3531,7 @@ private PSObject RehydrateCimInstance(PSObject deserializedObject) // process properties that were originally "extended" properties foreach (PSMemberInfo deserializedMemberInfo in deserializedObject.InstanceMembers) { - if (!(deserializedMemberInfo is PSPropertyInfo deserializedProperty)) + if (deserializedMemberInfo is not PSPropertyInfo deserializedProperty) { continue; } @@ -7345,7 +7345,7 @@ public static UInt32 GetParameterSetMetadataFlags(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is ParameterSetMetadata parameterSetMetadata)) + if (instance.BaseObject is not ParameterSetMetadata parameterSetMetadata) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } @@ -7366,7 +7366,7 @@ public static PSObject GetInvocationInfo(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is DebuggerStopEventArgs dbgStopEventArgs)) + if (instance.BaseObject is not DebuggerStopEventArgs dbgStopEventArgs) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } @@ -7625,7 +7625,7 @@ public static Guid GetFormatViewDefinitionInstanceId(PSObject instance) throw PSTraceSource.NewArgumentNullException(nameof(instance)); } - if (!(instance.BaseObject is FormatViewDefinition formatViewDefinition)) + if (instance.BaseObject is not FormatViewDefinition formatViewDefinition) { throw PSTraceSource.NewArgumentNullException(nameof(instance)); } diff --git a/src/System.Management.Automation/namespaces/ProviderBase.cs b/src/System.Management.Automation/namespaces/ProviderBase.cs index 07be68dc3ec..4345ec9f8ec 100644 --- a/src/System.Management.Automation/namespaces/ProviderBase.cs +++ b/src/System.Management.Automation/namespaces/ProviderBase.cs @@ -260,7 +260,7 @@ internal void GetProperty( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -298,7 +298,7 @@ internal object GetPropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { return null; } @@ -327,7 +327,7 @@ internal void SetProperty( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -365,7 +365,7 @@ internal object SetPropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { return null; } @@ -397,7 +397,7 @@ internal void ClearProperty( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -435,7 +435,7 @@ internal object ClearPropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IPropertyCmdletProvider propertyProvider)) + if (this is not IPropertyCmdletProvider propertyProvider) { return null; } @@ -479,7 +479,7 @@ internal void NewProperty( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -524,7 +524,7 @@ internal object NewPropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { return null; } @@ -556,7 +556,7 @@ internal void RemoveProperty( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -593,7 +593,7 @@ internal object RemovePropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { return null; } @@ -629,7 +629,7 @@ internal void RenameProperty( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -670,7 +670,7 @@ internal object RenamePropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { return null; } @@ -710,7 +710,7 @@ internal void CopyProperty( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -755,7 +755,7 @@ internal object CopyPropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { return null; } @@ -795,7 +795,7 @@ internal void MoveProperty( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { throw PSTraceSource.NewNotSupportedException( @@ -840,7 +840,7 @@ internal object MovePropertyDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IDynamicPropertyCmdletProvider propertyProvider)) + if (this is not IDynamicPropertyCmdletProvider propertyProvider) { return null; } @@ -871,7 +871,7 @@ internal IContentReader GetContentReader( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { throw PSTraceSource.NewNotSupportedException( @@ -904,7 +904,7 @@ internal object GetContentReaderDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { return null; } @@ -931,7 +931,7 @@ internal IContentWriter GetContentWriter( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { throw PSTraceSource.NewNotSupportedException( @@ -964,7 +964,7 @@ internal object GetContentWriterDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { return null; } @@ -988,7 +988,7 @@ internal void ClearContent( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { throw PSTraceSource.NewNotSupportedException( @@ -1021,7 +1021,7 @@ internal object ClearContentDynamicParameters( { Context = cmdletProviderContext; - if (!(this is IContentCmdletProvider contentProvider)) + if (this is not IContentCmdletProvider contentProvider) { return null; } diff --git a/src/System.Management.Automation/utils/PsUtils.cs b/src/System.Management.Automation/utils/PsUtils.cs index ff2d0ade5ea..0a4682bcdd6 100644 --- a/src/System.Management.Automation/utils/PsUtils.cs +++ b/src/System.Management.Automation/utils/PsUtils.cs @@ -308,7 +308,7 @@ internal static Hashtable EvaluatePowerShellDataFile( ex.Message); } - if (!(evaluationResult is Hashtable retResult)) + if (evaluationResult is not Hashtable retResult) { throw PSTraceSource.NewInvalidOperationException( ParserStrings.InvalidPowerShellDataFile, @@ -453,14 +453,14 @@ internal static object[] Base64ToArgsConverter(string base64) throw PSTraceSource.NewArgumentException(MinishellParameterBinderController.ArgsParameter); } - if (!(dso is PSObject mo)) + if (dso is not PSObject mo) { // This helper function should move the host. Provide appropriate error message. // Format of args parameter is not correct. throw PSTraceSource.NewArgumentException(MinishellParameterBinderController.ArgsParameter); } - if (!(mo.BaseObject is ArrayList argsList)) + if (mo.BaseObject is not ArrayList argsList) { // This helper function should move the host. Provide appropriate error message. // Format of args parameter is not correct. diff --git a/src/System.Management.Automation/utils/RuntimeException.cs b/src/System.Management.Automation/utils/RuntimeException.cs index 4cfdc31bcb6..61a3a345eff 100644 --- a/src/System.Management.Automation/utils/RuntimeException.cs +++ b/src/System.Management.Automation/utils/RuntimeException.cs @@ -221,7 +221,7 @@ internal static string RetrieveMessage(Exception e) if (e == null) return string.Empty; - if (!(e is IContainsErrorRecord icer)) + if (e is not IContainsErrorRecord icer) return e.Message; ErrorRecord er = icer.ErrorRecord; if (er == null) From a10ff105c987c7ca3400dfdba05ca80a9688e89b Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:58:28 +0100 Subject: [PATCH 118/378] Fix `SA1028`: Code should not contain trailing whitespace. Part 1. (#26203) --- .../ManagementList/ColumnPicker.xaml.cs | 2 +- .../cmdletization/cim/CimJobException.cs | 2 +- .../cimSupport/cmdletization/cim/cimQuery.cs | 2 +- .../commands/management/CIMHelper.cs | 2 +- .../commands/management/Eventlog.cs | 4 +- .../management/GetComputerInfoCommand.cs | 2 +- .../commands/management/ResolvePathCommand.cs | 2 +- .../commands/management/TestPathCommand.cs | 2 +- .../commands/management/WebServiceProxy.cs | 2 +- .../commands/utility/CsvCommands.cs | 10 ++--- .../commands/utility/Import-LocalizedData.cs | 2 +- .../commands/utility/Measure-Object.cs | 2 +- .../commands/utility/New-Object.cs | 4 +- .../commands/utility/NewGuidCommand.cs | 2 +- .../commands/utility/StartSleepCommand.cs | 2 +- .../Common/HttpVersionCompletionsAttribute.cs | 2 +- .../utility/WebCmdlet/ConvertToJsonCommand.cs | 2 +- .../utility/WebCmdlet/CoreCLR/WebProxy.cs | 2 +- .../utility/trace/TraceExpressionCommand.cs | 2 +- .../WindowsTaskbarJumpList/HResult.cs | 12 +++--- .../host/msh/Executor.cs | 2 +- .../host/msh/StopTranscriptCmdlet.cs | 2 +- src/Microsoft.WSMan.Management/CredSSP.cs | 2 +- .../DscSupport/CimDSCParser.cs | 2 +- .../common/DisplayDatabase/FormatTable.cs | 2 +- ...lets-over-objects.xmlSerializer.autogen.cs | 2 +- .../CommandCompletion/CompletionAnalysis.cs | 4 +- .../CommandCompletion/CompletionCompleters.cs | 14 +++---- .../CommandCompletion/CompletionHelpers.cs | 6 +-- .../engine/CommandPathSearch.cs | 2 +- .../engine/CommandSearcher.cs | 2 +- .../engine/EventManager.cs | 2 +- .../engine/GetCommandCommand.cs | 2 +- .../engine/LanguagePrimitives.cs | 4 +- .../engine/Modules/GetModuleCommand.cs | 2 +- .../engine/Modules/ModuleCmdletBase.cs | 4 +- .../engine/NativeCommandParameterBinder.cs | 4 +- .../engine/debugger/debugger.cs | 6 +-- .../engine/hostifaces/LocalConnection.cs | 4 +- .../engine/hostifaces/PSTask.cs | 2 +- .../engine/hostifaces/Pipeline.cs | 2 +- .../engine/hostifaces/PowerShell.cs | 8 ++-- .../engine/hostifaces/RunspacePool.cs | 2 +- .../engine/hostifaces/RunspacePoolInternal.cs | 2 +- .../engine/regex.cs | 4 +- .../engine/runtime/ScriptBlockToPowerShell.cs | 14 +++---- .../namespaces/RegistryProvider.cs | 2 +- .../config/MshSnapinLoadException.cs | 2 +- .../utils/CommandDiscoveryExceptions.cs | 6 +-- .../utils/CommandProcessorExceptions.cs | 2 +- .../utils/ExecutionExceptions.cs | 42 +++++++++---------- .../utils/HostInterfacesExceptions.cs | 6 +-- .../utils/MshArgumentException.cs | 2 +- .../utils/MshArgumentNullException.cs | 4 +- .../utils/MshArgumentOutOfRangeException.cs | 4 +- .../utils/MshInvalidOperationException.cs | 2 +- .../utils/MshNotImplementedException.cs | 4 +- .../utils/MshNotSupportedException.cs | 4 +- .../utils/ParameterBinderExceptions.cs | 12 +++--- .../utils/RuntimeException.cs | 4 +- .../EtwActivityReverterMethodInvoker.cs | 2 +- .../utils/tracing/PSEtwLogProvider.cs | 2 +- test/perf/benchmarks/Engine.Compiler.cs | 2 +- .../BenchmarkDotNet.Extensions/Extensions.cs | 2 +- .../PartitionFilter.cs | 4 +- .../TooManyTestCasesValidator.cs | 4 +- .../UniqueArgumentsValidator.cs | 2 +- .../ValuesGenerator.cs | 6 +-- test/perf/dotnet-tools/Reporting/Reporter.cs | 8 ++-- .../dotnet-tools/ResultsComparer/Program.cs | 2 +- .../assets/ExpTest/ExpTest.cs | 2 +- test/xUnit/csharp/test_CryptoUtils.cs | 2 +- test/xUnit/csharp/test_FileSystemProvider.cs | 2 +- test/xUnit/csharp/test_PSConfiguration.cs | 2 +- 74 files changed, 151 insertions(+), 151 deletions(-) diff --git a/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ColumnPicker.xaml.cs b/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ColumnPicker.xaml.cs index 8a919959968..05151330ea2 100644 --- a/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ColumnPicker.xaml.cs +++ b/src/Microsoft.Management.UI.Internal/ManagementList/ManagementList/ColumnPicker.xaml.cs @@ -60,7 +60,7 @@ internal ColumnPicker( : this() { ArgumentNullException.ThrowIfNull(columns); - + ArgumentNullException.ThrowIfNull(availableColumns); // Add visible columns to Selected list, preserving order diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs index 675c6c71404..935cc960c6c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/CimJobException.cs @@ -49,7 +49,7 @@ public CimJobException(string message, Exception inner) : base(message, inner) /// /// The that holds the serialized object data about the exception being thrown. /// The that contains contextual information about the source or destination. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected CimJobException( SerializationInfo info, StreamingContext context) diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs index c9f1cc5cafa..f08c2ab3c11 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs @@ -315,7 +315,7 @@ public override void FilterByAssociatedInstance(object associatedInstance, strin public override void AddQueryOption(string optionName, object optionValue) { ArgumentException.ThrowIfNullOrEmpty(optionName); - ArgumentNullException.ThrowIfNull(optionValue); + ArgumentNullException.ThrowIfNull(optionValue); this.queryOptions[optionName] = optionValue; } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs index 035d5b17bbe..688b6362e16 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CIMHelper.cs @@ -132,7 +132,7 @@ internal static string WqlQueryAll(string from) internal static T[] GetAll(CimSession session, string nameSpace, string wmiClassName) where T : class, new() { ArgumentException.ThrowIfNullOrEmpty(wmiClassName); - + var rv = new List(); try diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs index ffd69951c61..c667116fdd0 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Eventlog.cs @@ -555,7 +555,7 @@ private bool FiltersMatch(EventLogEntry entry) } } - if (!usernamematch) + if (!usernamematch) { return usernamematch; } @@ -595,7 +595,7 @@ private bool FiltersMatch(EventLogEntry entry) } } - if (!datematch) + if (!datematch) { return datematch; } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs index e355be6f3ff..87f96c436ea 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetComputerInfoCommand.cs @@ -3685,7 +3685,7 @@ public enum DeviceGuardHardwareSecure /// Secure Memory Overwrite. /// SecureMemoryOverwrite = 4, - + /// /// UEFI Code Readonly. /// diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs index 3d1b66933d2..d0f5fecf495 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ResolvePathCommand.cs @@ -81,7 +81,7 @@ public SwitchParameter Relative /// [Parameter] public string RelativeBasePath - { + { get { return _relativeBasePath; diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestPathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestPathCommand.cs index d8748b6ef9c..50765c0e0ae 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestPathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestPathCommand.cs @@ -200,7 +200,7 @@ protected override void ProcessRecord() { WriteObject(result); } - + continue; } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs index 3fc313fe222..3f91d597e57 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/WebServiceProxy.cs @@ -475,7 +475,7 @@ private object InstantiateWebServiceProxy(Assembly assembly) break; } - if (proxyType != null) + if (proxyType != null) { break; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 0ff52372864..fa49c33d2ab 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -959,7 +959,7 @@ internal static IList BuildPropertyNames(PSObject source, IList /// Converted string. internal string ConvertPropertyNamesCSV(IList propertyNames) { - ArgumentNullException.ThrowIfNull(propertyNames); + ArgumentNullException.ThrowIfNull(propertyNames); _outputString.Clear(); bool first = true; @@ -994,7 +994,7 @@ internal string ConvertPropertyNamesCSV(IList propertyNames) AppendStringWithEscapeAlways(_outputString, propertyName); break; case BaseCsvWritingCommand.QuoteKind.AsNeeded: - + if (propertyName.AsSpan().IndexOfAny(_delimiter, '\n', '"') != -1) { AppendStringWithEscapeAlways(_outputString, propertyName); @@ -1023,7 +1023,7 @@ internal string ConvertPropertyNamesCSV(IList propertyNames) /// internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyNames) { - ArgumentNullException.ThrowIfNull(propertyNames); + ArgumentNullException.ThrowIfNull(propertyNames); _outputString.Clear(); bool first = true; @@ -1109,7 +1109,7 @@ internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyN /// ToString() value. internal static string GetToStringValueForProperty(PSPropertyInfo property) { - ArgumentNullException.ThrowIfNull(property); + ArgumentNullException.ThrowIfNull(property); string value = null; try @@ -1271,7 +1271,7 @@ internal sealed class ImportCsvHelper internal ImportCsvHelper(PSCmdlet cmdlet, char delimiter, IList header, string typeName, StreamReader streamReader) { - ArgumentNullException.ThrowIfNull(cmdlet); + ArgumentNullException.ThrowIfNull(cmdlet); ArgumentNullException.ThrowIfNull(streamReader); _cmdlet = cmdlet; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs index 1f43670531d..c4e423ffd1d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs @@ -158,7 +158,7 @@ protected override void ProcessRecord() ThrowTerminatingError( new ErrorRecord(nse, "CannotDefineSupportedCommand", ErrorCategory.PermissionDenied, null)); } - + SystemPolicy.LogWDACAuditMessage( context: Context, title: ImportLocalizedDataStrings.WDACLogTitle, diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs index cf483b16a93..1e741758270 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Measure-Object.cs @@ -824,7 +824,7 @@ protected override void EndProcessing() string errorId = (IsMeasuringGeneric) ? "GenericMeasurePropertyNotFound" : "TextMeasurePropertyNotFound"; WritePropertyNotFoundError(propertyName, errorId); } - + continue; } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs index f2c31faf400..0ea312f2963 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-Object.cs @@ -196,12 +196,12 @@ protected override void BeginProcessing() { ThrowTerminatingError( new ErrorRecord( - new PSNotSupportedException(NewObjectStrings.CannotCreateTypeConstrainedLanguage), + new PSNotSupportedException(NewObjectStrings.CannotCreateTypeConstrainedLanguage), "CannotCreateTypeConstrainedLanguage", ErrorCategory.PermissionDenied, targetObject: null)); } - + SystemPolicy.LogWDACAuditMessage( context: Context, title: NewObjectStrings.TypeWDACLogTitle, diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs index c384b2a2578..0e466f86d3f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/NewGuidCommand.cs @@ -45,7 +45,7 @@ protected override void ProcessRecord() { ErrorRecord error = new(ex, "StringNotRecognizedAsGuid", ErrorCategory.InvalidArgument, null); WriteError(error); - } + } } else { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index df1c8b76fb8..839a0b7c051 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -110,7 +110,7 @@ protected override void ProcessRecord() case "Milliseconds": sleepTime = Milliseconds; break; - + case "FromTimeSpan": if (Duration.TotalMilliseconds > int.MaxValue) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/HttpVersionCompletionsAttribute.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/HttpVersionCompletionsAttribute.cs index 05eb8ed96b6..903ff4d8f80 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/HttpVersionCompletionsAttribute.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/HttpVersionCompletionsAttribute.cs @@ -46,6 +46,6 @@ static HttpVersionCompletionsAttribute() /// public HttpVersionCompletionsAttribute() : base(AllowedVersions) { - } + } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs index eb8c3e3cc08..173d999b06d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs @@ -98,7 +98,7 @@ protected virtual void Dispose(bool disposing) _cancellationSource.Dispose(); } } - + private readonly List _inputObjects = new(); /// diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs index c7400e75f9d..c8fed859771 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs @@ -31,7 +31,7 @@ public bool Equals(WebProxy? other) return false; } - // _proxyAddress cannot be null as it is set in the constructor + // _proxyAddress cannot be null as it is set in the constructor return other._credentials == _credentials && _proxyAddress.Equals(other._proxyAddress) && BypassProxyOnLocal == other.BypassProxyOnLocal; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs index 2bf7045cbed..1eadd4934b3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/trace/TraceExpressionCommand.cs @@ -330,7 +330,7 @@ internal TracePipelineWriter( bool writeError, Collection matchingSources) { - ArgumentNullException.ThrowIfNull(cmdlet); + ArgumentNullException.ThrowIfNull(cmdlet); ArgumentNullException.ThrowIfNull(matchingSources); _cmdlet = cmdlet; diff --git a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs index e23f0810ea1..4789bcef06f 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/WindowsTaskbarJumpList/HResult.cs @@ -4,18 +4,18 @@ namespace Microsoft.PowerShell { /// - /// HRESULT Wrapper - /// + /// HRESULT Wrapper + /// internal enum HResult { - /// - /// S_OK - /// + /// + /// S_OK + /// Ok = 0x0000, /// /// S_FALSE. - /// + /// False = 0x0001, /// diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs index 38924f3e397..354c61fb8f3 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/Executor.cs @@ -15,7 +15,7 @@ namespace Microsoft.PowerShell /// /// Executor wraps a Pipeline instance, and provides helper methods for executing commands in that pipeline. It is used to /// provide bookkeeping and structure to the use of pipeline in such a way that they can be interrupted and cancelled by a - /// break event handler, and to track nesting of pipelines (which happens with interrupted input loops (aka subshells) and + /// break event handler, and to track nesting of pipelines (which happens with interrupted input loops (aka subshells) and /// use of tab-completion in prompts). The bookkeeping is necessary because the break handler is static and global, and /// there is no means for tying a break handler to an instance of an object. /// diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs index 71e90854dc4..093f7c147dc 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/StopTranscriptCmdlet.cs @@ -25,7 +25,7 @@ protected override { return; } - + try { string outFilename = Host.UI.StopTranscribing(); diff --git a/src/Microsoft.WSMan.Management/CredSSP.cs b/src/Microsoft.WSMan.Management/CredSSP.cs index 03c71f0edb1..a8457ab5bc2 100644 --- a/src/Microsoft.WSMan.Management/CredSSP.cs +++ b/src/Microsoft.WSMan.Management/CredSSP.cs @@ -514,7 +514,7 @@ private void EnableClientSideSettings() try { XmlDocument xmldoc = new XmlDocument(); - + // push the xml string with credssp enabled xmldoc.LoadXml(m_SessionObj.Put(helper.CredSSP_RUri, newxmlcontent, 0)); diff --git a/src/System.Management.Automation/DscSupport/CimDSCParser.cs b/src/System.Management.Automation/DscSupport/CimDSCParser.cs index 6160577beb2..417f1931c8a 100644 --- a/src/System.Management.Automation/DscSupport/CimDSCParser.cs +++ b/src/System.Management.Automation/DscSupport/CimDSCParser.cs @@ -3252,7 +3252,7 @@ public static bool ImportCimKeywordsFromModule(PSModuleInfo module, string resou string tempSchemaFilepath = schemaFiles.FirstOrDefault(); Debug.Assert(schemaFiles.Count() == 1, "A valid DSCResource module can have only one schema mof file"); - + if (tempSchemaFilepath is not null) { var classes = GetCachedClassByFileName(tempSchemaFilepath) ?? ImportClasses(tempSchemaFilepath, new Tuple(module.Name, module.Version), errors); diff --git a/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/FormatTable.cs b/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/FormatTable.cs index a1e34424950..2ae4ac2626e 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/FormatTable.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/DisplayDatabase/FormatTable.cs @@ -20,7 +20,7 @@ namespace System.Management.Automation.Runspaces /// /// This exception is used by Formattable constructor to indicate errors /// occurred during construction time. - /// + /// [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "FormatTable")] public class FormatTableLoadException : RuntimeException { diff --git a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs index b8d0e88905c..dd1c6023cdb 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/xml/cmdlets-over-objects.xmlSerializer.autogen.cs @@ -760,7 +760,7 @@ private void Write12_Item(string n, string ns, global::Microsoft.PowerShell.Cmdl { WriteXsiType(@"CmdletParameterMetadataForGetCmdletFilteringParameter", @"http://schemas.microsoft.com/cmdlets-over-objects/2009/11"); } - + if (o.@IsMandatorySpecified) { WriteAttribute(@"IsMandatory", @"", System.Xml.XmlConvert.ToString((global::System.Boolean)((global::System.Boolean)o.@IsMandatory))); diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs index e4d8203a63b..8aafa939d84 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs @@ -1503,7 +1503,7 @@ private static bool TryGetInferredCompletionsForAssignment(Ast expression, Compl { return false; } - + if (inferredTypes.Count == 0) { return false; @@ -2613,7 +2613,7 @@ private static List CompleteLoopLabel(CompletionContext comple return result; } - + private static List CompleteUsingKeywords(int cursorOffset, Token[] tokens, ref int replacementIndex, ref int replacementLength) { var result = new List(); diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 16b0d1edac4..80ba4545ff4 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -448,12 +448,12 @@ internal static List CompleteModuleName(CompletionContext cont // eg: Host finds Microsoft.PowerShell.Host // If the user has entered a manual wildcard, or a module name that contains a "." we assume they only want results that matches the input exactly. bool shortNameSearch = wordToComplete.Length > 0 && !WildcardPattern.ContainsWildcardCharacters(wordToComplete) && !wordToComplete.Contains('.'); - + if (!wordToComplete.EndsWith('*')) { wordToComplete += "*"; } - + string[] moduleNames; WildcardPattern shortNamePattern; if (shortNameSearch) @@ -848,7 +848,7 @@ private static bool TryGetParameterHelpMessage( [NotNullWhen(true)] out string? message) { message = null; - + if (attr.HelpMessage is not null) { message = attr.HelpMessage; @@ -926,7 +926,7 @@ private static List GetParameterCompletionResults( addCommonParameters = false; break; } - + if (helpMessage is null && TryGetParameterHelpMessage(pattr, commandAssembly, out string attrHelpMessage)) { helpMessage = $" - {attrHelpMessage}"; @@ -4772,7 +4772,7 @@ private static List GetFileSystemProviderResults( var resultType = isContainer ? CompletionResultType.ProviderContainer : CompletionResultType.ProviderItem; - + bool leafQuotesNeeded; var completionText = NewPathCompletionText( basePath, @@ -4996,7 +4996,7 @@ private static string RebuildPathWithVars( for (int i = 0; i < path.Length; i++) { // on Windows, we need to preserve the expanded home path as native commands don't understand it -#if UNIX +#if UNIX if (i == homeIndex) { _ = sb.Append('~'); @@ -8628,7 +8628,7 @@ internal static string CombineVariableWithPartialPath(VariableExpressionAst vari /// The parameters to add. /// Collection of command info objects. internal static Collection GetCommandInfo( - IDictionary fakeBoundParameters, + IDictionary fakeBoundParameters, params string[] parametersToAdd) { using var ps = PowerShell.Create(RunspaceMode.CurrentRunspace); diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionHelpers.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionHelpers.cs index d54f4d5dc87..edf31e8e97a 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionHelpers.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionHelpers.cs @@ -129,7 +129,7 @@ internal static string NormalizeToExpandableString(string value) /// true if the value matches the word as a wildcard pattern; otherwise, false. /// /// - /// Wildcard pattern matching allows for flexible matching, where wilcards can represent + /// Wildcard pattern matching allows for flexible matching, where wilcards can represent /// multiple characters in the input. This strategy is case-insensitive. /// internal static readonly MatchStrategy WildcardPatternMatchIgnoreCase = (value, wordToComplete) @@ -141,11 +141,11 @@ internal static string NormalizeToExpandableString(string value) /// Determines if the given value matches the specified word considering wildcard characters literally. /// /// - /// true if the value matches either the literal normalized word or the wildcard pattern with escaping; + /// true if the value matches either the literal normalized word or the wildcard pattern with escaping; /// otherwise, false. /// /// - /// This strategy first attempts a literal prefix match for performance and, if unsuccessful, escapes the word to complete to + /// This strategy first attempts a literal prefix match for performance and, if unsuccessful, escapes the word to complete to /// handle any problematic wildcard characters before performing a wildcard match. /// internal static readonly MatchStrategy WildcardPatternEscapeMatch = (value, wordToComplete) diff --git a/src/System.Management.Automation/engine/CommandPathSearch.cs b/src/System.Management.Automation/engine/CommandPathSearch.cs index 92a533e6ec0..12c494ad8ea 100644 --- a/src/System.Management.Automation/engine/CommandPathSearch.cs +++ b/src/System.Management.Automation/engine/CommandPathSearch.cs @@ -111,7 +111,7 @@ private void ResolveCurrentDirectoryInLookupPaths() sessionState.IsProviderLoaded(fileSystemProviderName); string? environmentCurrentDirectory = null; - + try { environmentCurrentDirectory = Directory.GetCurrentDirectory(); diff --git a/src/System.Management.Automation/engine/CommandSearcher.cs b/src/System.Management.Automation/engine/CommandSearcher.cs index 1d945094004..638ccd4ac79 100644 --- a/src/System.Management.Automation/engine/CommandSearcher.cs +++ b/src/System.Management.Automation/engine/CommandSearcher.cs @@ -951,7 +951,7 @@ private static bool ShouldSkipCommandResolutionForConstrainedLanguage(CommandInf if (result != null) { - var formatString = result switch + var formatString = result switch { FilterInfo => "Filter found: {0}", ConfigurationInfo => "Configuration found: {0}", diff --git a/src/System.Management.Automation/engine/EventManager.cs b/src/System.Management.Automation/engine/EventManager.cs index e72a34cef1c..1c5de607321 100644 --- a/src/System.Management.Automation/engine/EventManager.cs +++ b/src/System.Management.Automation/engine/EventManager.cs @@ -2050,7 +2050,7 @@ public override bool Equals(object obj) { return obj is PSEventSubscriber es && Equals(es); } - + /// /// Determines if two PSEventSubscriber instances are equal /// diff --git a/src/System.Management.Automation/engine/GetCommandCommand.cs b/src/System.Management.Automation/engine/GetCommandCommand.cs index 2ecf19ccaa9..10e8334021b 100644 --- a/src/System.Management.Automation/engine/GetCommandCommand.cs +++ b/src/System.Management.Automation/engine/GetCommandCommand.cs @@ -1694,7 +1694,7 @@ private static PSObject GetParameterType(Type parameterType) } /// - /// Provides argument completion for Noun parameter. + /// Provides argument completion for Noun parameter. /// public class NounArgumentCompleter : IArgumentCompleter { diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs index fa9e68f5c24..13d8f66e5e9 100644 --- a/src/System.Management.Automation/engine/LanguagePrimitives.cs +++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs @@ -2943,9 +2943,9 @@ private static object ConvertStringToInteger( } if (resultType == typeof(BigInteger)) - { + { NumberStyles style = NumberStyles.Integer | NumberStyles.AllowThousands; - + return BigInteger.Parse(strToConvert, style, NumberFormatInfo.InvariantInfo); } // Fallback conversion for regular numeric types. diff --git a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs index ca48c5c698c..39c3e9c905e 100644 --- a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs @@ -604,7 +604,7 @@ public IEnumerable CompleteArgument( string parameterName, string wordToComplete, CommandAst commandAst, - IDictionary fakeBoundParameters) + IDictionary fakeBoundParameters) => CompletionHelpers.GetMatchingResults(wordToComplete, possibleCompletionValues: Utils.AllowedEditionValues); } } diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index f07ddcc6335..0a1d0bfc04f 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -6168,7 +6168,7 @@ private void CheckForDisallowedDotSourcing( } } } - + private static void RemoveNestedModuleFunctions( ExecutionContext context, PSModuleInfo module, @@ -7276,7 +7276,7 @@ private static void ImportFunctions(FunctionInfo func, SessionStateInternal targ targetSessionState.ExecutionContext); // Note that the module 'func' and the function table 'functionInfo' instances are now linked - // together (see 'CopiedCommand' in CommandInfo class), so setting visibility on one also + // together (see 'CopiedCommand' in CommandInfo class), so setting visibility on one also // sets it on the other. SetCommandVisibility(isImportModulePrivate, functionInfo); functionInfo.Module = sourceModule; diff --git a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs index 0124b01332c..4115546a758 100644 --- a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs +++ b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs @@ -500,7 +500,7 @@ private static string GetEnumerableArgSeparator(ArrayLiteralAst arrayLiteralAst, afterPrev -= arrayExtent.StartOffset; beforeNext -= arrayExtent.StartOffset; - if (arrayText[afterPrev] == ',') + if (arrayText[afterPrev] == ',') { return ", "; } @@ -509,7 +509,7 @@ private static string GetEnumerableArgSeparator(ArrayLiteralAst arrayLiteralAst, { return " ,"; } - + return " , "; } diff --git a/src/System.Management.Automation/engine/debugger/debugger.cs b/src/System.Management.Automation/engine/debugger/debugger.cs index e093210f960..985d90ab3ec 100644 --- a/src/System.Management.Automation/engine/debugger/debugger.cs +++ b/src/System.Management.Automation/engine/debugger/debugger.cs @@ -2084,8 +2084,8 @@ private void SetPendingBreakpoints(FunctionContext functionContext) else { tuple.Item1.Add(breakpoint.SequencePointIndex, new List { breakpoint }); - } - + } + // We need to keep track of any breakpoints that are bound in each script because they may // need to be rebound if the script changes. var boundBreakpoints = _boundBreakpoints[currentScriptFile].Item2; @@ -2099,7 +2099,7 @@ private void SetPendingBreakpoints(FunctionContext functionContext) } // Here could check if all breakpoints for the current functionContext were bound, but because there is no atomic - // api for conditional removal we either need to lock, or do some trickery that has possibility of race conditions. + // api for conditional removal we either need to lock, or do some trickery that has possibility of race conditions. // Instead we keep the item in the dictionary with 0 breakpoint count. This should not be a big issue, // because it is single entry per file that had breakpoints, so there won't be thousands of files in a session. } diff --git a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs index 5dcc43ce2a7..822dc552204 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs @@ -1557,11 +1557,11 @@ public PSDataCollection ErrorRecords /// /// Serialization information. /// Streaming context. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected RunspaceOpenModuleLoadException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization } diff --git a/src/System.Management.Automation/engine/hostifaces/PSTask.cs b/src/System.Management.Automation/engine/hostifaces/PSTask.cs index c56225f3bb7..56bdabbff14 100644 --- a/src/System.Management.Automation/engine/hostifaces/PSTask.cs +++ b/src/System.Management.Automation/engine/hostifaces/PSTask.cs @@ -952,7 +952,7 @@ private Runspace GetRunspace(int taskId) iss.LanguageMode = PSLanguageMode.FullLanguage; break; } - + runspace = RunspaceFactory.CreateRunspace(iss); runspace.Name = runspaceName; _activeRunspaces.TryAdd(runspace.Id, runspace); diff --git a/src/System.Management.Automation/engine/hostifaces/Pipeline.cs b/src/System.Management.Automation/engine/hostifaces/Pipeline.cs index 66ebf7d0287..f7bca01fe7b 100644 --- a/src/System.Management.Automation/engine/hostifaces/Pipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/Pipeline.cs @@ -85,7 +85,7 @@ internal InvalidPipelineStateException(string message, PipelineState currentStat /// The that contains contextual information /// about the source or destination. /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] private InvalidPipelineStateException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs index 7073437d7e9..c86b86b4ffb 100644 --- a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs +++ b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs @@ -96,7 +96,7 @@ internal InvalidPowerShellStateException(PSInvocationState currentState) /// The that contains contextual information /// about the source or destination. /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected InvalidPowerShellStateException(SerializationInfo info, StreamingContext context) { @@ -3736,7 +3736,7 @@ public PSDataCollection EndInvoke(IAsyncResult asyncResult) /// /// /// When used with , that call will return a partial result. - /// When used with , that call will throw a . + /// When used with , that call will throw a . /// public void Stop() { @@ -3796,7 +3796,7 @@ public IAsyncResult BeginStop(AsyncCallback callback, object state) /// /// /// When used with , that call will return a partial result. - /// When used with , that call will throw a . + /// When used with , that call will throw a . /// public void EndStop(IAsyncResult asyncResult) { @@ -3850,7 +3850,7 @@ public void EndStop(IAsyncResult asyncResult) /// /// /// When used with , that call will return a partial result. - /// When used with , that call will throw a . + /// When used with , that call will throw a . /// public Task StopAsync(AsyncCallback callback, object state) => Task.Factory.FromAsync(BeginStop(callback, state), _endStopMethod); diff --git a/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs b/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs index 5b03ecffa58..7dc9e8d31de 100644 --- a/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs +++ b/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs @@ -90,7 +90,7 @@ RunspacePoolState expectedState /// The that contains /// contextual information about the source or destination. /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected InvalidRunspacePoolStateException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs b/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs index 6df0aa74695..1b20fc4c85f 100644 --- a/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs +++ b/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs @@ -812,7 +812,7 @@ public void ReleaseRunspace(Runspace runspace) EnqueueCheckAndStartRequestServicingThread(null, false); } } - + /// /// Release all resources. /// diff --git a/src/System.Management.Automation/engine/regex.cs b/src/System.Management.Automation/engine/regex.cs index cead035f057..d69f3bdb88f 100644 --- a/src/System.Management.Automation/engine/regex.cs +++ b/src/System.Management.Automation/engine/regex.cs @@ -335,7 +335,7 @@ internal static bool ContainsRangeWildcard(string pattern) foundStart = true; continue; } - + if (foundStart && pattern[index] is ']') { result = true; @@ -524,7 +524,7 @@ public WildcardPatternException(string message, /// /// Serialization information. /// Streaming context. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected WildcardPatternException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs b/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs index d0b7ef20680..defd87662e8 100644 --- a/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs +++ b/src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs @@ -327,8 +327,8 @@ internal static Dictionary GetUsingValuesForEachParallel( bool isTrustedInput, ExecutionContext context) { - // Using variables for Foreach-Object -Parallel use are restricted to be within the - // Foreach-Object -Parallel call scope. This will filter the using variable map to variables + // Using variables for Foreach-Object -Parallel use are restricted to be within the + // Foreach-Object -Parallel call scope. This will filter the using variable map to variables // only within the current (outer) Foreach-Object -Parallel call scope. var usingAsts = UsingExpressionAstSearcher.FindAllUsingExpressions(scriptBlock.Ast).ToList(); UsingExpressionAst usingAst = null; @@ -358,11 +358,11 @@ internal static Dictionary GetUsingValuesForEachParallel( if (rte.ErrorRecord.FullyQualifiedErrorId.Equals("VariableIsUndefined", StringComparison.Ordinal)) { throw InterpreterError.NewInterpreterException( - targetObject: null, + targetObject: null, exceptionType: typeof(RuntimeException), - errorPosition: usingAst.Extent, + errorPosition: usingAst.Extent, resourceIdAndErrorId: "UsingVariableIsUndefined", - resourceString: AutomationExceptions.UsingVariableIsUndefined, + resourceString: AutomationExceptions.UsingVariableIsUndefined, args: rte.ErrorRecord.TargetObject); } } @@ -435,7 +435,7 @@ private static bool IsInForeachParallelCallingScope( /* Example: $Test1 = "Hello" - 1 | ForEach-Object -Parallel { + 1 | ForEach-Object -Parallel { $using:Test1 $Test2 = "Goodbye" 1 | ForEach-Object -Parallel { @@ -450,7 +450,7 @@ private static bool IsInForeachParallelCallingScope( while (currentParent != scriptblockAst) { // Look for Foreach-Object outer commands - if (currentParent is CommandAst commandAst && + if (currentParent is CommandAst commandAst && FindForEachInCommand(commandAst)) { // Using Ast is outside the invoking foreach scope. diff --git a/src/System.Management.Automation/namespaces/RegistryProvider.cs b/src/System.Management.Automation/namespaces/RegistryProvider.cs index db901160910..4e3b84716cd 100644 --- a/src/System.Management.Automation/namespaces/RegistryProvider.cs +++ b/src/System.Management.Automation/namespaces/RegistryProvider.cs @@ -1835,7 +1835,7 @@ public void GetProperty( WriteError(new ErrorRecord( invalidCast, invalidCast.GetType().FullName, - ErrorCategory.ReadError, + ErrorCategory.ReadError, path)); } } diff --git a/src/System.Management.Automation/singleshell/config/MshSnapinLoadException.cs b/src/System.Management.Automation/singleshell/config/MshSnapinLoadException.cs index f0e61f01a9e..71c81611440 100644 --- a/src/System.Management.Automation/singleshell/config/MshSnapinLoadException.cs +++ b/src/System.Management.Automation/singleshell/config/MshSnapinLoadException.cs @@ -171,7 +171,7 @@ public override string Message /// /// Serialization information. /// Streaming context. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSSnapInException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/CommandDiscoveryExceptions.cs b/src/System.Management.Automation/utils/CommandDiscoveryExceptions.cs index 6c2380023ca..89580932359 100644 --- a/src/System.Management.Automation/utils/CommandDiscoveryExceptions.cs +++ b/src/System.Management.Automation/utils/CommandDiscoveryExceptions.cs @@ -78,7 +78,7 @@ public CommandNotFoundException(string message, Exception innerException) : base /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected CommandNotFoundException(SerializationInfo info, StreamingContext context) { @@ -336,13 +336,13 @@ public ScriptRequiresException(string message, Exception innerException) : base( /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ScriptRequiresException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); } - + #endregion Serialization #region Properties diff --git a/src/System.Management.Automation/utils/CommandProcessorExceptions.cs b/src/System.Management.Automation/utils/CommandProcessorExceptions.cs index f63ff69bd2c..668c95a25e6 100644 --- a/src/System.Management.Automation/utils/CommandProcessorExceptions.cs +++ b/src/System.Management.Automation/utils/CommandProcessorExceptions.cs @@ -24,7 +24,7 @@ public class ApplicationFailedException : RuntimeException /// The serialization information to use when initializing this object. /// The streaming context to use when initializing this object. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ApplicationFailedException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/ExecutionExceptions.cs b/src/System.Management.Automation/utils/ExecutionExceptions.cs index 69a58d326b2..ff41e045bbb 100644 --- a/src/System.Management.Automation/utils/ExecutionExceptions.cs +++ b/src/System.Management.Automation/utils/ExecutionExceptions.cs @@ -114,12 +114,12 @@ public CmdletInvocationException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected CmdletInvocationException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization #endregion ctor @@ -154,7 +154,7 @@ public override ErrorRecord ErrorRecord /// . /// This is generally reported from the standard provider navigation cmdlets /// such as get-childitem. - /// + /// public class CmdletProviderInvocationException : CmdletInvocationException { #region ctor @@ -193,7 +193,7 @@ public CmdletProviderInvocationException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected CmdletProviderInvocationException(SerializationInfo info, StreamingContext context) { @@ -281,7 +281,7 @@ private static Exception GetInnerException(Exception e) /// Catching this exception is optional; if the cmdlet or providers chooses not to /// handle PipelineStoppedException and instead allow it to propagate to the /// PowerShell Engine's call to ProcessRecord, the PowerShell Engine will handle it properly. - /// + /// public class PipelineStoppedException : RuntimeException { #region ctor @@ -304,7 +304,7 @@ public PipelineStoppedException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PipelineStoppedException(SerializationInfo info, StreamingContext context) { @@ -342,7 +342,7 @@ public PipelineStoppedException(string message, /// to an asynchronous pipeline source and the pipeline has already /// been stopped. /// - /// + /// public class PipelineClosedException : RuntimeException { #region ctor @@ -387,7 +387,7 @@ public PipelineClosedException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PipelineClosedException(SerializationInfo info, StreamingContext context) { @@ -405,7 +405,7 @@ protected PipelineClosedException(SerializationInfo info, /// /// For example, if $WarningPreference is "Stop", the command will fail with /// this error if a cmdlet calls WriteWarning. - /// + /// public class ActionPreferenceStopException : RuntimeException { #region ctor @@ -467,12 +467,12 @@ internal ActionPreferenceStopException(InvocationInfo invocationInfo, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ActionPreferenceStopException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization /// @@ -612,7 +612,7 @@ public ParentContainsErrorRecordException(string message, /// Streaming context. /// Doesn't return. /// Always. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ParentContainsErrorRecordException( SerializationInfo info, StreamingContext context) { @@ -648,7 +648,7 @@ public override string Message /// The redirected object is available as /// /// in the ErrorRecord which contains this exception. - /// + /// public class RedirectedException : RuntimeException { #region constructors @@ -697,7 +697,7 @@ public RedirectedException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected RedirectedException(SerializationInfo info, StreamingContext context) { @@ -719,7 +719,7 @@ protected RedirectedException(SerializationInfo info, /// call depth to prevent stack overflows. The maximum call depth is configurable /// but generally high enough that scripts which are not deeply recursive /// should not have a problem. - /// + /// public class ScriptCallDepthException : SystemException, IContainsErrorRecord { #region ctor @@ -765,7 +765,7 @@ public ScriptCallDepthException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ScriptCallDepthException(SerializationInfo info, StreamingContext context) { @@ -860,11 +860,11 @@ public PipelineDepthException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PipelineDepthException(SerializationInfo info, - StreamingContext context) + StreamingContext context) { - throw new NotSupportedException(); + throw new NotSupportedException(); } #endregion Serialization @@ -918,7 +918,7 @@ public int CallDepth /// /// Note that HaltCommandException does not define IContainsErrorRecord. /// This is because it is not reported to the user. - /// + /// public class HaltCommandException : SystemException { #region ctor @@ -963,7 +963,7 @@ public HaltCommandException(string message, /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected HaltCommandException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/HostInterfacesExceptions.cs b/src/System.Management.Automation/utils/HostInterfacesExceptions.cs index 362a1448207..df36d248d18 100644 --- a/src/System.Management.Automation/utils/HostInterfacesExceptions.cs +++ b/src/System.Management.Automation/utils/HostInterfacesExceptions.cs @@ -100,7 +100,7 @@ class HostException : RuntimeException /// /// The contextual information about the source or destination. /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected HostException(SerializationInfo info, StreamingContext context) { @@ -120,7 +120,7 @@ private void SetDefaultErrorRecord() /// /// Defines the exception thrown when an error occurs from prompting for a command parameter. - /// + /// public class PromptingException : HostException { @@ -209,7 +209,7 @@ class PromptingException : HostException /// /// The contextual information about the source or destination. /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PromptingException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/MshArgumentException.cs b/src/System.Management.Automation/utils/MshArgumentException.cs index baa3f8c3163..452527d1c18 100644 --- a/src/System.Management.Automation/utils/MshArgumentException.cs +++ b/src/System.Management.Automation/utils/MshArgumentException.cs @@ -68,7 +68,7 @@ public PSArgumentException(string message, string paramName) /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSArgumentException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/MshArgumentNullException.cs b/src/System.Management.Automation/utils/MshArgumentNullException.cs index a4f50256e44..16ef442e5ec 100644 --- a/src/System.Management.Automation/utils/MshArgumentNullException.cs +++ b/src/System.Management.Automation/utils/MshArgumentNullException.cs @@ -79,12 +79,12 @@ public PSArgumentNullException(string paramName, string message) /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSArgumentNullException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization #endregion ctor diff --git a/src/System.Management.Automation/utils/MshArgumentOutOfRangeException.cs b/src/System.Management.Automation/utils/MshArgumentOutOfRangeException.cs index 8d666778a4f..4e65ed0acb1 100644 --- a/src/System.Management.Automation/utils/MshArgumentOutOfRangeException.cs +++ b/src/System.Management.Automation/utils/MshArgumentOutOfRangeException.cs @@ -67,13 +67,13 @@ public PSArgumentOutOfRangeException(string paramName, object actualValue, strin /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSArgumentOutOfRangeException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); } - + #endregion Serialization /// diff --git a/src/System.Management.Automation/utils/MshInvalidOperationException.cs b/src/System.Management.Automation/utils/MshInvalidOperationException.cs index f398e4a2e99..8400e762360 100644 --- a/src/System.Management.Automation/utils/MshInvalidOperationException.cs +++ b/src/System.Management.Automation/utils/MshInvalidOperationException.cs @@ -38,7 +38,7 @@ public PSInvalidOperationException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSInvalidOperationException(SerializationInfo info, StreamingContext context) { diff --git a/src/System.Management.Automation/utils/MshNotImplementedException.cs b/src/System.Management.Automation/utils/MshNotImplementedException.cs index 7d1082bf747..1b925053410 100644 --- a/src/System.Management.Automation/utils/MshNotImplementedException.cs +++ b/src/System.Management.Automation/utils/MshNotImplementedException.cs @@ -38,12 +38,12 @@ public PSNotImplementedException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSNotImplementedException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization /// diff --git a/src/System.Management.Automation/utils/MshNotSupportedException.cs b/src/System.Management.Automation/utils/MshNotSupportedException.cs index 1268636742b..a1e519a960e 100644 --- a/src/System.Management.Automation/utils/MshNotSupportedException.cs +++ b/src/System.Management.Automation/utils/MshNotSupportedException.cs @@ -38,13 +38,13 @@ public PSNotSupportedException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected PSNotSupportedException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); } - + #endregion Serialization /// diff --git a/src/System.Management.Automation/utils/ParameterBinderExceptions.cs b/src/System.Management.Automation/utils/ParameterBinderExceptions.cs index 4052eec0b81..a28de586d8e 100644 --- a/src/System.Management.Automation/utils/ParameterBinderExceptions.cs +++ b/src/System.Management.Automation/utils/ParameterBinderExceptions.cs @@ -297,7 +297,7 @@ internal ParameterBindingException( /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ParameterBindingException( SerializationInfo info, StreamingContext context) @@ -486,7 +486,7 @@ private string BuildMessage() #endregion Private } - + internal class ParameterBindingValidationException : ParameterBindingException { #region Preferred constructors @@ -654,7 +654,7 @@ internal ParameterBindingValidationException( /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ParameterBindingValidationException( SerializationInfo info, StreamingContext context) @@ -844,7 +844,7 @@ internal ParameterBindingArgumentTransformationException( /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ParameterBindingArgumentTransformationException( SerializationInfo info, StreamingContext context) @@ -854,7 +854,7 @@ protected ParameterBindingArgumentTransformationException( #endregion serialization } - + internal class ParameterBindingParameterDefaultValueException : ParameterBindingException { #region Preferred constructors @@ -1018,7 +1018,7 @@ internal ParameterBindingParameterDefaultValueException( /// /// streaming context /// - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected ParameterBindingParameterDefaultValueException( SerializationInfo info, StreamingContext context) diff --git a/src/System.Management.Automation/utils/RuntimeException.cs b/src/System.Management.Automation/utils/RuntimeException.cs index 61a3a345eff..ab013359d5c 100644 --- a/src/System.Management.Automation/utils/RuntimeException.cs +++ b/src/System.Management.Automation/utils/RuntimeException.cs @@ -40,12 +40,12 @@ public RuntimeException() /// Serialization information. /// Streaming context. /// Constructed object. - [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] + [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")] protected RuntimeException(SerializationInfo info, StreamingContext context) { throw new NotSupportedException(); - } + } #endregion Serialization /// diff --git a/src/System.Management.Automation/utils/tracing/EtwActivityReverterMethodInvoker.cs b/src/System.Management.Automation/utils/tracing/EtwActivityReverterMethodInvoker.cs index d9d082879a6..8bd2ae3e620 100644 --- a/src/System.Management.Automation/utils/tracing/EtwActivityReverterMethodInvoker.cs +++ b/src/System.Management.Automation/utils/tracing/EtwActivityReverterMethodInvoker.cs @@ -21,7 +21,7 @@ internal class EtwActivityReverterMethodInvoker : public EtwActivityReverterMethodInvoker(IEtwEventCorrelator eventCorrelator) { - ArgumentNullException.ThrowIfNull(eventCorrelator); + ArgumentNullException.ThrowIfNull(eventCorrelator); _eventCorrelator = eventCorrelator; _invoker = DoInvoke; diff --git a/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs b/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs index f90bd92c6ed..625ba88a23b 100755 --- a/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs @@ -132,7 +132,7 @@ internal override void LogCommandLifecycleEvent(Func getLogContext, } else { - // When state is Start log the CommandLine which has arguments for completeness. + // When state is Start log the CommandLine which has arguments for completeness. payload.AppendLine(StringUtil.Format(EtwLoggingStrings.CommandStateChange, logContext.CommandLine, newState.ToString())); } } diff --git a/test/perf/benchmarks/Engine.Compiler.cs b/test/perf/benchmarks/Engine.Compiler.cs index 4f9dbab88a9..68385847f5b 100644 --- a/test/perf/benchmarks/Engine.Compiler.cs +++ b/test/perf/benchmarks/Engine.Compiler.cs @@ -61,7 +61,7 @@ public void GlobalSetup() // believe that there is no need to run many ops in each iteration. However, the subsequent runs // of this method is much faster than the first run, and this causes 'MinIterationTime' warnings // to our benchmarks and make the benchmark results not reliable. - // Calling this method once in 'GlobalSetup' is a workaround. + // Calling this method once in 'GlobalSetup' is a workaround. // See https://github.com/dotnet/BenchmarkDotNet/issues/837#issuecomment-828600157 CompileFunction(); } diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs index f478b6f7378..9bc477bc4fe 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/Extensions.cs @@ -13,7 +13,7 @@ public static class SummaryExtensions public static int ToExitCode(this IEnumerable summaries) { // an empty summary means that initial filtering and validation did not allow to run - if (!summaries.Any()) + if (!summaries.Any()) return 1; // if anything has failed, it's an error diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs index a2837d61988..d7089f6f5a8 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/PartitionFilter.cs @@ -10,13 +10,13 @@ public class PartitionFilter : IFilter private readonly int? _partitionsCount; private readonly int? _partitionIndex; // indexed from 0 private int _counter = 0; - + public PartitionFilter(int? partitionCount, int? partitionIndex) { _partitionsCount = partitionCount; _partitionIndex = partitionIndex; } - + public bool Predicate(BenchmarkCase benchmarkCase) { if (!_partitionsCount.HasValue || !_partitionIndex.HasValue) diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs index 47d5564309e..cd9c3a424ce 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/TooManyTestCasesValidator.cs @@ -14,9 +14,9 @@ namespace BenchmarkDotNet.Extensions public class TooManyTestCasesValidator : IValidator { private const int Limit = 16; - + public static readonly IValidator FailOnError = new TooManyTestCasesValidator(); - + public bool TreatsWarningsAsErrors => true; public IEnumerable Validate(ValidationParameters validationParameters) diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/UniqueArgumentsValidator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/UniqueArgumentsValidator.cs index 7bfab8445cb..0309e1e9065 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/UniqueArgumentsValidator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/UniqueArgumentsValidator.cs @@ -30,7 +30,7 @@ private class BenchmarkArgumentsComparer : IEqualityComparer { public bool Equals(BenchmarkCase x, BenchmarkCase y) => Enumerable.SequenceEqual( - x.Parameters.Items.Select(argument => argument.Value), + x.Parameters.Items.Select(argument => argument.Value), y.Parameters.Items.Select(argument => argument.Value)); public int GetHashCode(BenchmarkCase obj) diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs index 7e2b587abca..85f5d98af59 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/ValuesGenerator.cs @@ -33,7 +33,7 @@ public static T[] ArrayOfUniqueValues(int count) // of random-sized memory by BDN engine T[] result = new T[count]; - var random = new Random(Seed); + var random = new Random(Seed); var uniqueValues = new HashSet(); @@ -49,12 +49,12 @@ public static T[] ArrayOfUniqueValues(int count) return result; } - + public static T[] Array(int count) { var result = new T[count]; - var random = new Random(Seed); + var random = new Random(Seed); if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte)) { diff --git a/test/perf/dotnet-tools/Reporting/Reporter.cs b/test/perf/dotnet-tools/Reporting/Reporter.cs index 9291d6f36eb..d99ecfaf47c 100644 --- a/test/perf/dotnet-tools/Reporting/Reporter.cs +++ b/test/perf/dotnet-tools/Reporting/Reporter.cs @@ -44,7 +44,7 @@ public static Reporter CreateReporter(IEnvironment environment = null) { ret.Init(); } - + return ret; } @@ -66,7 +66,7 @@ private void Init() { var split = kvp.Split('='); run.Configurations.Add(split[0], split[1]); - } + } } os = new Os() @@ -91,7 +91,7 @@ private void Init() public string GetJson() { if (!InLab) - { + { return null; } var jsonobj = new @@ -122,7 +122,7 @@ public string WriteResultTable() ret.AppendLine($"{LeftJustify("Metric", counterWidth)}|{LeftJustify("Average",resultWidth)}|{LeftJustify("Min", resultWidth)}|{LeftJustify("Max",resultWidth)}"); ret.AppendLine($"{new String('-', counterWidth)}|{new String('-', resultWidth)}|{new String('-', resultWidth)}|{new String('-', resultWidth)}"); - + ret.AppendLine(Print(defaultCounter, counterWidth, resultWidth)); foreach(var counter in topCounters) { diff --git a/test/perf/dotnet-tools/ResultsComparer/Program.cs b/test/perf/dotnet-tools/ResultsComparer/Program.cs index 68615f61c78..a0c14e0057a 100644 --- a/test/perf/dotnet-tools/ResultsComparer/Program.cs +++ b/test/perf/dotnet-tools/ResultsComparer/Program.cs @@ -191,7 +191,7 @@ private static void ExportToCsv((string id, Benchmark baseResult, Benchmark diff private static void ExportToXml((string id, Benchmark baseResult, Benchmark diffResult, EquivalenceTestConclusion conclusion)[] notSame, FileInfo xmlPath) { if (xmlPath == null) - { + { Console.WriteLine("No file given"); return; } diff --git a/test/powershell/engine/ExperimentalFeature/assets/ExpTest/ExpTest.cs b/test/powershell/engine/ExperimentalFeature/assets/ExpTest/ExpTest.cs index 219c01058e9..73bb24ccd08 100644 --- a/test/powershell/engine/ExperimentalFeature/assets/ExpTest/ExpTest.cs +++ b/test/powershell/engine/ExperimentalFeature/assets/ExpTest/ExpTest.cs @@ -151,7 +151,7 @@ public class SaveMyFileCommand : PSCmdlet [Parameter] public string FileName { get; set; } - + [Experimental("ExpTest.FeatureOne", ExperimentAction.Show)] [Parameter] public string Destination { get; set; } diff --git a/test/xUnit/csharp/test_CryptoUtils.cs b/test/xUnit/csharp/test_CryptoUtils.cs index 0f737a94260..6531924d437 100644 --- a/test/xUnit/csharp/test_CryptoUtils.cs +++ b/test/xUnit/csharp/test_CryptoUtils.cs @@ -22,7 +22,7 @@ public static void TestSessionKeyExchange() string publicKey = cryptoClient.GetPublicKeyAsBase64EncodedString(); cryptoServer.ImportPublicKeyFromBase64EncodedString(publicKey); // sent to and imported by server - // generate, export, import session key + // generate, export, import session key cryptoServer.GenerateSessionKey(); // server provides the session key? string sessionKey = cryptoServer.SafeExportSessionKey(); cryptoClient.ImportSessionKeyFromBase64EncodedString(sessionKey); diff --git a/test/xUnit/csharp/test_FileSystemProvider.cs b/test/xUnit/csharp/test_FileSystemProvider.cs index 1bea0f84ce4..06cb43e6088 100644 --- a/test/xUnit/csharp/test_FileSystemProvider.cs +++ b/test/xUnit/csharp/test_FileSystemProvider.cs @@ -43,7 +43,7 @@ public void Dispose() { Dispose(true); GC.SuppressFinalize(this); - } + } protected virtual void Dispose(bool disposing) { diff --git a/test/xUnit/csharp/test_PSConfiguration.cs b/test/xUnit/csharp/test_PSConfiguration.cs index 54e69da68f0..de94107fc6b 100644 --- a/test/xUnit/csharp/test_PSConfiguration.cs +++ b/test/xUnit/csharp/test_PSConfiguration.cs @@ -99,7 +99,7 @@ public void Dispose() { Dispose(true); GC.SuppressFinalize(this); - } + } protected virtual void Dispose(bool disposing) { From 9461d96d559e525c201f649af28a4783519bc9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nagy-Egri=20M=C3=A1t=C3=A9=20Ferenc?= Date: Thu, 16 Oct 2025 10:29:49 +0200 Subject: [PATCH 119/378] Dynamically evaluate width of LastWriteTime for formatting output on Unix (#24624) --- .../DefaultFormatters/FileSystem_format_ps1xml.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs index 0400f99b899..4c8d23971af 100644 --- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs +++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Globalization; namespace System.Management.Automation.Runspaces { @@ -48,7 +49,10 @@ private static IEnumerable ViewsOf_FileSystemTypes(CustomC .AddHeader(Alignment.Left, label: "UnixMode", width: 10) .AddHeader(Alignment.Right, label: "User", width: 10) .AddHeader(Alignment.Left, label: "Group", width: 10) - .AddHeader(Alignment.Right, label: "LastWriteTime", width: 16) + .AddHeader( + Alignment.Right, + label: "LastWriteTime", + width: String.Format(CultureInfo.CurrentCulture, "{0:d} {0:HH}:{0:mm}", CultureInfo.CurrentCulture.Calendar.MaxSupportedDateTime).Length) .AddHeader(Alignment.Right, label: "Size", width: 12) .AddHeader(Alignment.Left, label: "Name") .StartRowDefinition(wrap: true) From b46e0709fbf7c1b4b9b572fc2bd6889faca12cd8 Mon Sep 17 00:00:00 2001 From: Elvin Aslanov Date: Thu, 16 Oct 2025 13:29:11 +0200 Subject: [PATCH 120/378] Capitalize Windows in PSNativeWindowsTildeExpansion experimental feature description (#25266) --- .../engine/ExperimentalFeature/ExperimentalFeature.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index dd26e609641..6ff7e1d6820 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -118,7 +118,7 @@ static ExperimentalFeature() description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), new ExperimentalFeature( name: PSNativeWindowsTildeExpansion, - description: "On windows, expand unquoted tilde (`~`) with the user's current home folder."), + description: "On Windows, expand unquoted tilde (`~`) with the user's current home folder."), new ExperimentalFeature( name: PSRedirectToVariable, description: "Add support for redirecting to the variable drive"), From 1d14c25d6bd3280a8639dd3e134ddb582010bae6 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 16 Oct 2025 13:44:30 -0700 Subject: [PATCH 121/378] Update changelog for v7.5.4 and v7.4.13 (#26202) --- CHANGELOG/7.4.md | 32 ++++++++++++++++++++++++++++++++ CHANGELOG/7.5.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md index a4966b09e99..89a3f64e37c 100644 --- a/CHANGELOG/7.4.md +++ b/CHANGELOG/7.4.md @@ -1,5 +1,37 @@ # 7.4 Changelog +## [7.4.13] + +### Build and Packaging Improvements + +
    + + + +

    Update .NET SDK to 8.0.415

    + +
    + +
      +
    • [release/v7.4] Update StableRelease to not be the latest (#26042)
    • +
    • [release/v7.4] Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26033)
    • +
    • [release/v7.4] Add 7.4.12 Changelog (#26018)
    • +
    • [release/v7.4] Fix variable reference for release environment in pipeline (#26014)
    • +
    • Backport Release Pipeline Changes (Internal 37169)
    • +
    • [release/v7.4] Update branch for release (#26194)
    • +
    • [release/v7.4] Mark the 3 consistently failing tests as pending to unblock PRs (#26197)
    • +
    • [release/v7.4] Remove UseDotnet task and use the dotnet-install script (#26170)
    • +
    • [release/v7.4] Automate Store Publishing (#26163)
    • +
    • [release/v7.4] add CodeQL suppresion for NativeCommandProcessor (#26174)
    • +
    • [release/v7.4] add CodeQL suppressions for UpdatableHelp and NativeCommandProcessor methods (#26172)
    • +
    • [release/v7.4] Suppress false positive PSScriptAnalyzer warnings in tests and build scripts (#26058)
    • +
    • [release/v7.4] Ensure that socket timeouts are set only during the token validation (#26080)
    • +
    + +
    + +[7.4.13]: https://github.com/PowerShell/PowerShell/compare/v7.4.12...v7.4.13 + ## [7.4.12] ### Tools diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index e231ce6b0e2..80b3ee0a8aa 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,38 @@ # 7.5 Changelog +## [7.5.4] + +### Build and Packaging Improvements + +
    + + + +

    Update to .NET SDK 9.0.306

    + +
    + +
      +
    • [release/v7.5] Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26032)
    • +
    • [release/v7.5] Fix variable reference for release environment in pipeline (#26013)
    • +
    • [release/v7.5] Add v7.5.3 Changelog (#26015)
    • +
    • [release/v7.5] Add LinuxHost Network configuration to PowerShell Packages pipeline (#26002)
    • +
    • Backport Release Pipeline Changes (Internal 37168)
    • +
    • [release/v7.5] Update branch for release (#26195)
    • +
    • [release/v7.5] Mark the 3 consistently failing tests as pending to unblock PRs (#26196)
    • +
    • [release/v7.5] add CodeQL suppresion for NativeCommandProcessor (#26173)
    • +
    • [release/v7.5] add CodeQL suppressions for UpdatableHelp and NativeCommandProcessor methods (#26171)
    • +
    • [release/v7.5] Remove UseDotnet task and use the dotnet-install script (#26169)
    • +
    • [release/v7.5] Automate Store Publishing (#26164)
    • +
    • [release/v7.5] Ensure that socket timeouts are set only during the token validation (#26079)
    • +
    • [release/v7.5] Suppress false positive PSScriptAnalyzer warnings in tests and build scripts (#26059)
    • +
    + +
    + +[7.5.4]: https://github.com/PowerShell/PowerShell/compare/v7.5.3...v7.5.4 + + ## [7.5.3] ### General Cmdlet Updates and Fixes From b4f42a07e065b7da486dce053d47b6149c2dc66c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 05:38:05 +0100 Subject: [PATCH 122/378] Replace stackallocs with collection expressions (#25803) --- .../host/msh/ConsoleHostUserInterface.cs | 2 +- .../host/msh/ConsoleTextWriter.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 40 ++++++++++--------- .../engine/Interop/Windows/QueryDosDevice.cs | 2 +- .../Interop/Windows/WNetGetConnection.cs | 2 +- .../namespaces/FileSystemProvider.cs | 11 ++--- src/powershell/Program.cs | 14 ++----- 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs index 51fe8203d80..f0da0d99547 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs @@ -578,7 +578,7 @@ private static bool shouldUnsetMode( [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void WriteToConsole(char c, bool transcribeResult) { - ReadOnlySpan value = stackalloc char[1] { c }; + ReadOnlySpan value = [c]; WriteToConsole(value, transcribeResult); } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs index 97a02cb7123..a82156ce1c8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleTextWriter.cs @@ -76,8 +76,8 @@ public override void Write(char c) { - ReadOnlySpan c1 = stackalloc char[1] { c }; - _ui.WriteToConsole(c1, transcribeResult: true); + ReadOnlySpan value = [c]; + _ui.WriteToConsole(value, transcribeResult: true); } public override diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index dc5db5f2c48..f4a7622b66f 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -637,25 +637,29 @@ public string GetModeString() return DirectoryOwnerFullGroupReadExecOtherReadExec; } - Span modeCharacters = stackalloc char[10]; - modeCharacters[0] = itemTypeTable[ItemType]; - bool isExecutable; - UnixFileMode modeInfo = (UnixFileMode)Mode; - modeCharacters[1] = modeInfo.HasFlag(UnixFileMode.UserRead) ? CanRead : NoPerm; - modeCharacters[2] = modeInfo.HasFlag(UnixFileMode.UserWrite) ? CanWrite : NoPerm; - isExecutable = modeInfo.HasFlag(UnixFileMode.UserExecute); - modeCharacters[3] = modeInfo.HasFlag(UnixFileMode.SetUser) ? (isExecutable ? SetAndExec : SetAndNotExec) : (isExecutable ? CanExecute : NoPerm); - - modeCharacters[4] = modeInfo.HasFlag(UnixFileMode.GroupRead) ? CanRead : NoPerm; - modeCharacters[5] = modeInfo.HasFlag(UnixFileMode.GroupWrite) ? CanWrite : NoPerm; - isExecutable = modeInfo.HasFlag(UnixFileMode.GroupExecute); - modeCharacters[6] = modeInfo.HasFlag(UnixFileMode.SetGroup) ? (isExecutable ? SetAndExec : SetAndNotExec) : (isExecutable ? CanExecute : NoPerm); - - modeCharacters[7] = modeInfo.HasFlag(UnixFileMode.OtherRead) ? CanRead : NoPerm; - modeCharacters[8] = modeInfo.HasFlag(UnixFileMode.OtherWrite) ? CanWrite : NoPerm; - isExecutable = modeInfo.HasFlag(UnixFileMode.OtherExecute); - modeCharacters[9] = modeInfo.HasFlag(UnixFileMode.StickyBit) ? (isExecutable ? StickyAndExec : StickyAndNotExec) : (isExecutable ? CanExecute : NoPerm); + + Span modeCharacters = [ + itemTypeTable[ItemType], + + modeInfo.HasFlag(UnixFileMode.UserRead) ? CanRead : NoPerm, + modeInfo.HasFlag(UnixFileMode.UserWrite) ? CanWrite : NoPerm, + modeInfo.HasFlag(UnixFileMode.SetUser) ? + (modeInfo.HasFlag(UnixFileMode.UserExecute) ? SetAndExec : SetAndNotExec) : + (modeInfo.HasFlag(UnixFileMode.UserExecute) ? CanExecute : NoPerm), + + modeInfo.HasFlag(UnixFileMode.GroupRead) ? CanRead : NoPerm, + modeInfo.HasFlag(UnixFileMode.GroupWrite) ? CanWrite : NoPerm, + modeInfo.HasFlag(UnixFileMode.SetGroup) ? + (modeInfo.HasFlag(UnixFileMode.GroupExecute) ? SetAndExec : SetAndNotExec) : + (modeInfo.HasFlag(UnixFileMode.GroupExecute) ? CanExecute : NoPerm), + + modeInfo.HasFlag(UnixFileMode.OtherRead) ? CanRead : NoPerm, + modeInfo.HasFlag(UnixFileMode.OtherWrite) ? CanWrite : NoPerm, + modeInfo.HasFlag(UnixFileMode.StickyBit) ? + (modeInfo.HasFlag(UnixFileMode.OtherExecute) ? StickyAndExec : StickyAndNotExec) : + (modeInfo.HasFlag(UnixFileMode.OtherExecute) ? CanExecute : NoPerm), + ]; return new string(modeCharacters); } diff --git a/src/System.Management.Automation/engine/Interop/Windows/QueryDosDevice.cs b/src/System.Management.Automation/engine/Interop/Windows/QueryDosDevice.cs index 27907bd0135..d23899e8ef7 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/QueryDosDevice.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/QueryDosDevice.cs @@ -28,7 +28,7 @@ internal static string GetDosDeviceForNetworkPath(char deviceName) #endif Span buffer = stackalloc char[StartLength + 1]; - Span fullDeviceName = stackalloc char[3] { deviceName, ':', '\0' }; + Span fullDeviceName = [deviceName, ':', '\0']; char[]? rentedArray = null; try diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs index 88ec4386a14..01667fb4274 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs @@ -25,7 +25,7 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) return ERROR_NOT_SUPPORTED; } - ReadOnlySpan driveName = stackalloc char[] { drive, ':', '\0' }; + ReadOnlySpan driveName = [drive, ':', '\0']; int bufferSize = MAX_PATH; Span uncBuffer = stackalloc char[MAX_PATH]; if (InternalTestHooks.WNetGetConnectionBufferSize > 0 && InternalTestHooks.WNetGetConnectionBufferSize <= MAX_PATH) diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 56c8a074334..71de4e8ac67 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -1903,15 +1903,16 @@ string ToModeString(FileSystemInfo fileSystemInfo) } } - bool isDirectory = fileAttributes.HasFlag(FileAttributes.Directory); - ReadOnlySpan mode = stackalloc char[] - { - isLink ? 'l' : isDirectory ? 'd' : '-', + ReadOnlySpan mode = + [ + isLink ? + 'l' : + fileAttributes.HasFlag(FileAttributes.Directory) ? 'd' : '-', fileAttributes.HasFlag(FileAttributes.Archive) ? 'a' : '-', fileAttributes.HasFlag(FileAttributes.ReadOnly) ? 'r' : '-', fileAttributes.HasFlag(FileAttributes.Hidden) ? 'h' : '-', fileAttributes.HasFlag(FileAttributes.System) ? 's' : '-', - }; + ]; return new string(mode); } diff --git a/src/powershell/Program.cs b/src/powershell/Program.cs index 70346a1d1ce..aa79bb8cf07 100644 --- a/src/powershell/Program.cs +++ b/src/powershell/Program.cs @@ -129,10 +129,7 @@ private static void AttemptExecPwshLogin(string[] args) // At this point, we are on macOS // Set up the mib array and the query for process maximum args size - Span mib = stackalloc int[3]; - int mibLength = 2; - mib[0] = MACOS_CTL_KERN; - mib[1] = MACOS_KERN_ARGMAX; + Span mib = [MACOS_CTL_KERN, MACOS_KERN_ARGMAX]; int size = IntPtr.Size / 2; int argmax = 0; @@ -141,7 +138,7 @@ private static void AttemptExecPwshLogin(string[] args) { fixed (int *mibptr = mib) { - ThrowOnFailure(nameof(argmax), SysCtl(mibptr, mibLength, &argmax, &size, IntPtr.Zero, 0)); + ThrowOnFailure(nameof(argmax), SysCtl(mibptr, mib.Length, &argmax, &size, IntPtr.Zero, 0)); } } @@ -155,16 +152,13 @@ private static void AttemptExecPwshLogin(string[] args) IntPtr executablePathPtr = IntPtr.Zero; try { - mib[0] = MACOS_CTL_KERN; - mib[1] = MACOS_KERN_PROCARGS2; - mib[2] = pid; - mibLength = 3; + mib = [MACOS_CTL_KERN, MACOS_KERN_PROCARGS2, pid]; unsafe { fixed (int *mibptr = mib) { - ThrowOnFailure(nameof(procargs), SysCtl(mibptr, mibLength, procargs.ToPointer(), &argmax, IntPtr.Zero, 0)); + ThrowOnFailure(nameof(procargs), SysCtl(mibptr, mib.Length, procargs.ToPointer(), &argmax, IntPtr.Zero, 0)); } // The memory block we're reading is a series of null-terminated strings From 907c3b1f62ede096b1b0e36b9f34b59f44000373 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:30:27 +0100 Subject: [PATCH 123/378] Fix `IDE0049` for `object` in `System.Management.Automation`. Part 1 (#25923) --- .../engine/Attributes.cs | 6 ++-- .../engine/ErrorPackage.cs | 4 +-- .../engine/ProgressRecord.cs | 2 +- .../hostifaces/MshHostRawUserInterface.cs | 30 +++++++++---------- .../namespaces/ContainerProviderBase.cs | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index 31c520498c0..dac3a2ac377 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -87,7 +87,7 @@ namespace System.Management.Automation /// validates the argument as a whole. If the argument value may /// be an enumerable, you can derive from /// which will take care of unrolling the enumerable and validate each element individually. - /// It is also recommended to override to return a readable string + /// It is also recommended to override to return a readable string /// similar to the attribute declaration, for example "[ValidateRangeAttribute(5,10)]". /// If this attribute is applied to a string parameter, the string command argument will be validated. /// If this attribute is applied to a string[] parameter, the string[] command argument will be validated. @@ -154,7 +154,7 @@ protected ValidateArgumentsAttribute() /// and override the /// /// abstract method, after which they can apply the attribute to their parameters. - /// It is also recommended to override to return a readable string + /// It is also recommended to override to return a readable string /// similar to the attribute declaration, for example "[ValidateRangeAttribute(5,10)]". /// If this attribute is applied to a string parameter, the string command argument will be validated. /// If this attribute is applied to a string[] parameter, each string command argument will be validated. @@ -2292,7 +2292,7 @@ public ValidateNotNullOrWhiteSpaceAttribute() /// and override the /// abstract method, after which they /// can apply the attribute to their parameters. - /// It is also recommended to override to return a readable + /// It is also recommended to override to return a readable /// string similar to the attribute declaration, for example "[ValidateRangeAttribute(5,10)]". /// If multiple transformations are defined on a parameter, they will be invoked in series, /// each getting the output of the previous transformation. diff --git a/src/System.Management.Automation/engine/ErrorPackage.cs b/src/System.Management.Automation/engine/ErrorPackage.cs index baa2dd215de..2a4e152c098 100644 --- a/src/System.Management.Automation/engine/ErrorPackage.cs +++ b/src/System.Management.Automation/engine/ErrorPackage.cs @@ -796,7 +796,7 @@ internal Exception TextLookupError #region ToString /// - /// As + /// As /// /// Developer-readable identifier. public override string ToString() @@ -1677,7 +1677,7 @@ private string GetInvocationTypeName() #region ToString /// - /// As + /// As /// /// Developer-readable identifier. public override string ToString() diff --git a/src/System.Management.Automation/engine/ProgressRecord.cs b/src/System.Management.Automation/engine/ProgressRecord.cs index 56d5518dcf8..b3139dc8e6e 100644 --- a/src/System.Management.Automation/engine/ProgressRecord.cs +++ b/src/System.Management.Automation/engine/ProgressRecord.cs @@ -293,7 +293,7 @@ internal ProgressRecord(ProgressRecord other) } /// - /// Overrides + /// Overrides /// /// /// "parent = a id = b act = c stat = d cur = e pct = f sec = g type = h" where diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostRawUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostRawUserInterface.cs index 201caf3c827..64b200b7d61 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostRawUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostRawUserInterface.cs @@ -62,7 +62,7 @@ public int Y } /// - /// Overrides + /// Overrides /// /// /// "a,b" where a and b are the values of the X and Y properties. @@ -75,7 +75,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// object to be compared for equality. @@ -99,7 +99,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// Hash code for this instance. @@ -248,7 +248,7 @@ public int Height } /// - /// Overloads + /// Overloads /// /// /// "a,b" where a and b are the values of the Width and Height properties. @@ -261,7 +261,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// object to be compared for equality. @@ -285,7 +285,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// Hash code for this instance. @@ -557,7 +557,7 @@ bool keyDown } /// - /// Overloads + /// Overloads /// /// /// "a,b,c,d" where a, b, c, and d are the values of the VirtualKeyCode, Character, ControlKeyState, and KeyDown properties. @@ -569,7 +569,7 @@ public override return string.Create(CultureInfo.InvariantCulture, $"{VirtualKeyCode},{Character},{ControlKeyState},{KeyDown}"); } /// - /// Overrides + /// Overrides /// /// /// object to be compared for equality. @@ -593,7 +593,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// Hash code for this instance. @@ -787,7 +787,7 @@ public int Bottom } /// - /// Overloads + /// Overloads /// /// /// "a,b ; c,d" where a, b, c, and d are values of the Left, Top, Right, and Bottom properties. @@ -800,7 +800,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// object to be compared for equality. @@ -824,7 +824,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// Hash code for this instance. @@ -1015,7 +1015,7 @@ public BufferCellType BufferCellType } /// - /// Overloads + /// Overloads /// /// /// "'a' b c d" where a, b, c, and d are the values of the Character, ForegroundColor, BackgroundColor, and Type properties. @@ -1028,7 +1028,7 @@ public override } /// - /// Overrides + /// Overrides /// /// /// object to be compared for equality. @@ -1052,7 +1052,7 @@ public override } /// - /// Overrides + /// Overrides /// /// diff --git a/src/System.Management.Automation/namespaces/ContainerProviderBase.cs b/src/System.Management.Automation/namespaces/ContainerProviderBase.cs index cc3e0ac83e2..2a600097108 100644 --- a/src/System.Management.Automation/namespaces/ContainerProviderBase.cs +++ b/src/System.Management.Automation/namespaces/ContainerProviderBase.cs @@ -840,7 +840,7 @@ protected virtual object RenameItemDynamicParameters(string path, string newName /// /// The parameter can be any type of object that the provider can use /// to create the item. It is recommended that the provider accept at a minimum strings, and an instance - /// of the type of object that would be returned from GetItem() for this path. + /// of the type of object that would be returned from GetItem() for this path. /// can be used to convert some types to the desired type. /// /// The default implementation of this method throws an . From 135bb540901834979dfbfb0e5bddcca81e61975c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:31:10 +0100 Subject: [PATCH 124/378] Fix `IDE0049` for `string` in `System.Management.Automation` (#25921) --- .../commands/management/ComputerUnix.cs | 2 +- .../cimSupport/cmdletization/QueryBuilder.cs | 4 ++-- .../engine/ErrorPackage.cs | 14 +++++++------- .../engine/hostifaces/FieldDescription.cs | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs index eb286f7c190..22092116330 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ComputerUnix.cs @@ -158,7 +158,7 @@ protected override void StopProcessing() /// /// Run shutdown command. /// - protected void RunShutdown(String args) + protected void RunShutdown(string args) { if (shutdownPath is null) { diff --git a/src/System.Management.Automation/cimSupport/cmdletization/QueryBuilder.cs b/src/System.Management.Automation/cimSupport/cmdletization/QueryBuilder.cs index 36f781d98a0..e71e4c7c04f 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/QueryBuilder.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/QueryBuilder.cs @@ -52,7 +52,7 @@ public abstract class QueryBuilder /// Property name to query on. /// Property values to accept in the query. /// - /// if should be treated as a containing a wildcard pattern; + /// if should be treated as a containing a wildcard pattern; /// otherwise. /// /// @@ -69,7 +69,7 @@ public virtual void FilterByProperty(string propertyName, IEnumerable allowedPro /// Property name to query on. /// Property values to reject in the query. /// - /// if should be treated as a containing a wildcard pattern; + /// if should be treated as a containing a wildcard pattern; /// otherwise. /// /// diff --git a/src/System.Management.Automation/engine/ErrorPackage.cs b/src/System.Management.Automation/engine/ErrorPackage.cs index 2a4e152c098..6dfaf34fbec 100644 --- a/src/System.Management.Automation/engine/ErrorPackage.cs +++ b/src/System.Management.Automation/engine/ErrorPackage.cs @@ -562,7 +562,7 @@ public ErrorDetails(string message) /// /// /// - /// + /// /// insertion parameters /// /// @@ -584,7 +584,7 @@ public ErrorDetails(string message) /// by overriding virtual method /// . /// This constructor then inserts the specified args using - /// . + /// . /// public ErrorDetails( Cmdlet cmdlet, @@ -610,7 +610,7 @@ public ErrorDetails( /// /// /// - /// + /// /// insertion parameters /// /// @@ -637,7 +637,7 @@ public ErrorDetails( /// will implement /// . /// The constructor then inserts the specified args using - /// . + /// . /// public ErrorDetails( IResourceSupplier resourceSupplier, @@ -663,7 +663,7 @@ public ErrorDetails( /// /// /// - /// + /// /// insertion parameters /// /// @@ -678,7 +678,7 @@ public ErrorDetails( /// This constructor first loads a template string from the assembly using /// . /// The constructor then inserts the specified args using - /// . + /// . /// public ErrorDetails( System.Reflection.Assembly assembly, @@ -1823,7 +1823,7 @@ public interface IResourceSupplier /// if you want more complex behavior. /// /// Insertions will be inserted into the string with - /// + /// /// to generate the final error message in /// . /// diff --git a/src/System.Management.Automation/engine/hostifaces/FieldDescription.cs b/src/System.Management.Automation/engine/hostifaces/FieldDescription.cs index 541b1607df0..3f47fedb55e 100644 --- a/src/System.Management.Automation/engine/hostifaces/FieldDescription.cs +++ b/src/System.Management.Automation/engine/hostifaces/FieldDescription.cs @@ -89,7 +89,7 @@ public string Name /// /// /// If not already set by a call to , - /// will be used as the type. + /// will be used as the type. /// /// @@ -115,7 +115,7 @@ public string Name ///
    /// /// If not already set by a call to , - /// will be used as the type. + /// will be used as the type. /// /// @@ -144,7 +144,7 @@ public string Name /// to load the containing assembly to access the type information. AssemblyName is used for this purpose. /// /// If not already set by a call to , - /// will be used as the type. + /// will be used as the type. /// public string From 23a6cd329ae809ab1f663a5ea30b85ef7526baef Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 18:30:58 +0100 Subject: [PATCH 125/378] Remove nightly build status section from README.md (#26227) --- README.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/README.md b/README.md index dade0207250..7874646c063 100644 --- a/README.md +++ b/README.md @@ -61,21 +61,6 @@ There are dozens of topic-specific channels on our community-driven PowerShell V * [IRC](https://web.libera.chat/#powershell) on Libera.Chat * [Slack](https://aka.ms/psslack) -### Build status of nightly builds - -| Azure CI (Windows) | Azure CI (Linux) | Azure CI (macOS) | CodeFactor Grade | -|:-----------------------------------------|:-----------------------------------------------|:-----------------------------------------------|:-------------------------| -| [![windows-nightly-image][]][windows-nightly-site] | [![linux-nightly-image][]][linux-nightly-site] | [![macOS-nightly-image][]][macos-nightly-site] | [![cf-image][]][cf-site] | - -[windows-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=32 -[linux-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=23 -[macos-nightly-site]: https://powershell.visualstudio.com/PowerShell/_build?definitionId=24 -[windows-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-Windows-daily -[linux-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-linux-daily?branchName=master -[macOS-nightly-image]: https://powershell.visualstudio.com/PowerShell/_apis/build/status/PowerShell-CI-macos-daily?branchName=master -[cf-site]: https://www.codefactor.io/repository/github/powershell/powershell -[cf-image]: https://www.codefactor.io/repository/github/powershell/powershell/badge - ## Developing and Contributing Want to contribute to PowerShell? Please start with the [Contribution Guide][] to learn how to develop and contribute. From 8472a37f26353779c1a3afd8cefbc6f581686d94 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 18:31:37 +0100 Subject: [PATCH 126/378] Remove Gitter from README (#26200) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7874646c063..a7b31c475f8 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,6 @@ Want to chat with other members of the PowerShell community? There are dozens of topic-specific channels on our community-driven PowerShell Virtual User Group, which you can join on: -* [Gitter](https://gitter.im/PowerShell/PowerShell) * [Discord](https://discord.gg/PowerShell) * [IRC](https://web.libera.chat/#powershell) on Libera.Chat * [Slack](https://aka.ms/psslack) From 2786fceb3ab35b553b82f1067cddcc540d3e15ca Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 17 Oct 2025 19:06:45 +0100 Subject: [PATCH 127/378] Fix IDE0083: UseNotPattern (#26213) --- .../engine/remoting/client/ClientMethodExecutor.cs | 2 +- .../engine/remoting/client/Job.cs | 10 +++++----- .../engine/remoting/client/JobSourceAdapter.cs | 4 ++-- .../remoting/client/RemoteRunspacePoolInternal.cs | 2 +- .../engine/remoting/client/remoterunspaceinfo.cs | 2 +- .../engine/remoting/commands/CustomShellCommands.cs | 2 +- .../engine/remoting/commands/InvokeCommandCommand.cs | 2 +- .../engine/remoting/commands/ReceivePSSession.cs | 2 +- .../engine/remoting/common/RunspaceConnectionInfo.cs | 2 +- .../remoting/common/WireDataFormat/EncodeAndDecode.cs | 4 ++-- .../remoting/fanin/InitialSessionStateProvider.cs | 2 +- .../engine/remoting/server/ServerRemoteHost.cs | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/client/ClientMethodExecutor.cs b/src/System.Management.Automation/engine/remoting/client/ClientMethodExecutor.cs index 73c432158f3..9d52bcb4dc9 100644 --- a/src/System.Management.Automation/engine/remoting/client/ClientMethodExecutor.cs +++ b/src/System.Management.Automation/engine/remoting/client/ClientMethodExecutor.cs @@ -133,7 +133,7 @@ internal static void Dispatch( ///
    private static bool IsRunspacePushed(PSHost host) { - if (!(host is IHostSupportsInteractiveSession host2)) + if (host is not IHostSupportsInteractiveSession host2) { return false; } diff --git a/src/System.Management.Automation/engine/remoting/client/Job.cs b/src/System.Management.Automation/engine/remoting/client/Job.cs index b3a0135afc7..adf47d04cab 100644 --- a/src/System.Management.Automation/engine/remoting/client/Job.cs +++ b/src/System.Management.Automation/engine/remoting/client/Job.cs @@ -752,10 +752,10 @@ private void WriteError(Cmdlet cmdlet, ErrorRecord errorRecord) private static Exception GetExceptionFromErrorRecord(ErrorRecord errorRecord) { - if (!(errorRecord.Exception is RuntimeException runtimeException)) + if (errorRecord.Exception is not RuntimeException runtimeException) return null; - if (!(runtimeException is RemoteException remoteException)) + if (runtimeException is not RemoteException remoteException) return null; PSPropertyInfo wasThrownFromThrow = @@ -1911,7 +1911,7 @@ internal List GetJobsForComputer(string computerName) foreach (Job j in ChildJobs) { - if (!(j is PSRemotingChildJob child)) continue; + if (j is not PSRemotingChildJob child) continue; if (string.Equals(child.Runspace.ConnectionInfo.ComputerName, computerName, StringComparison.OrdinalIgnoreCase)) { @@ -1934,7 +1934,7 @@ internal List GetJobsForRunspace(PSSession runspace) foreach (Job j in ChildJobs) { - if (!(j is PSRemotingChildJob child)) continue; + if (j is not PSRemotingChildJob child) continue; if (child.Runspace.InstanceId.Equals(runspace.InstanceId)) { returnJobList.Add(child); @@ -1957,7 +1957,7 @@ internal List GetJobsForOperation(IThrottleOperation operation) foreach (Job j in ChildJobs) { - if (!(j is PSRemotingChildJob child)) continue; + if (j is not PSRemotingChildJob child) continue; if (child.Helper.Equals(helper)) { returnJobList.Add(child); diff --git a/src/System.Management.Automation/engine/remoting/client/JobSourceAdapter.cs b/src/System.Management.Automation/engine/remoting/client/JobSourceAdapter.cs index 9f6297fbfab..85cd6c7ba1f 100644 --- a/src/System.Management.Automation/engine/remoting/client/JobSourceAdapter.cs +++ b/src/System.Management.Automation/engine/remoting/client/JobSourceAdapter.cs @@ -413,7 +413,7 @@ public void StoreJobIdForReuse(Job2 job, bool recurse) duplicateDetector.Add(job.InstanceId, job.InstanceId); foreach (Job child in job.ChildJobs) { - if (!(child is Job2 childJob)) continue; + if (child is not Job2 childJob) continue; StoreJobIdForReuseHelper(duplicateDetector, childJob, true); } } @@ -429,7 +429,7 @@ private void StoreJobIdForReuseHelper(Hashtable duplicateDetector, Job2 job, boo if (!recurse || job.ChildJobs == null) return; foreach (Job child in job.ChildJobs) { - if (!(child is Job2 childJob)) continue; + if (child is not Job2 childJob) continue; StoreJobIdForReuseHelper(duplicateDetector, childJob, recurse); } } diff --git a/src/System.Management.Automation/engine/remoting/client/RemoteRunspacePoolInternal.cs b/src/System.Management.Automation/engine/remoting/client/RemoteRunspacePoolInternal.cs index c414b5095e6..983180bd5ca 100644 --- a/src/System.Management.Automation/engine/remoting/client/RemoteRunspacePoolInternal.cs +++ b/src/System.Management.Automation/engine/remoting/client/RemoteRunspacePoolInternal.cs @@ -1237,7 +1237,7 @@ public override RunspacePoolCapability GetCapabilities() internal static RunspacePool[] GetRemoteRunspacePools(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable) { - if (!(connectionInfo is WSManConnectionInfo wsmanConnectionInfoParam)) + if (connectionInfo is not WSManConnectionInfo wsmanConnectionInfoParam) { // Disconnect-Connect currently only supported by WSMan. throw new NotSupportedException(); diff --git a/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs b/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs index 55c2b23db75..c1b34691104 100644 --- a/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs +++ b/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs @@ -374,7 +374,7 @@ public static PSSession Create( string transportName, PSCmdlet psCmdlet) { - if (!(runspace is RemoteRunspace remoteRunspace)) + if (runspace is not RemoteRunspace remoteRunspace) { throw new PSArgumentException(RemotingErrorIdStrings.InvalidPSSessionArgument); } diff --git a/src/System.Management.Automation/engine/remoting/commands/CustomShellCommands.cs b/src/System.Management.Automation/engine/remoting/commands/CustomShellCommands.cs index e600661eab9..1d88210e7b6 100644 --- a/src/System.Management.Automation/engine/remoting/commands/CustomShellCommands.cs +++ b/src/System.Management.Automation/engine/remoting/commands/CustomShellCommands.cs @@ -1753,7 +1753,7 @@ internal static string CreateConditionalACEFromConfig( } StringBuilder conditionalACE = new StringBuilder(); - if (!(configTable[ConfigFileConstants.RequiredGroups] is Hashtable requiredGroupsHash)) + if (configTable[ConfigFileConstants.RequiredGroups] is not Hashtable requiredGroupsHash) { throw new PSInvalidOperationException(RemotingErrorIdStrings.RequiredGroupsNotHashTable); } diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs index 2145a1dbe2a..0dd769537c6 100644 --- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs @@ -1050,7 +1050,7 @@ protected override void BeginProcessing() // create collection of input writers here foreach (IThrottleOperation operation in Operations) { - if (!(operation is ExecutionCmdletHelperRunspace ecHelper)) + if (operation is not ExecutionCmdletHelperRunspace ecHelper) { // either all the operations will be of type ExecutionCmdletHelperRunspace // or not...there is no mix. diff --git a/src/System.Management.Automation/engine/remoting/commands/ReceivePSSession.cs b/src/System.Management.Automation/engine/remoting/commands/ReceivePSSession.cs index b9cf33e4b1c..67477e5b36f 100644 --- a/src/System.Management.Automation/engine/remoting/commands/ReceivePSSession.cs +++ b/src/System.Management.Automation/engine/remoting/commands/ReceivePSSession.cs @@ -1166,7 +1166,7 @@ private static PSSession ConnectSession(PSSession session, out Exception ex) /// PSSession disconnected runspace object. private PSSession TryGetSessionFromServer(PSSession session) { - if (!(session.Runspace is RemoteRunspace remoteRunspace)) + if (session.Runspace is not RemoteRunspace remoteRunspace) { return null; } diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index d9a6d0b317b..5f25851337e 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1174,7 +1174,7 @@ private static string ResolveShellUri(string shell) internal static T ExtractPropertyAsWsManConnectionInfo(RunspaceConnectionInfo rsCI, string property, T defaultValue) { - if (!(rsCI is WSManConnectionInfo wsCI)) + if (rsCI is not WSManConnectionInfo wsCI) { return defaultValue; } diff --git a/src/System.Management.Automation/engine/remoting/common/WireDataFormat/EncodeAndDecode.cs b/src/System.Management.Automation/engine/remoting/common/WireDataFormat/EncodeAndDecode.cs index c7b06d4c74d..e26f3421cda 100644 --- a/src/System.Management.Automation/engine/remoting/common/WireDataFormat/EncodeAndDecode.cs +++ b/src/System.Management.Automation/engine/remoting/common/WireDataFormat/EncodeAndDecode.cs @@ -1869,7 +1869,7 @@ internal static object GetPowerShellOutput(object data) /// PSInvocationInfo. internal static PSInvocationStateInfo GetPowerShellStateInfo(object data) { - if (!(data is PSObject dataAsPSObject)) + if (data is not PSObject dataAsPSObject) { throw new PSRemotingDataStructureException( RemotingErrorIdStrings.DecodingErrorForPowerShellStateInfo); @@ -2137,7 +2137,7 @@ internal static RemoteStreamOptions GetRemoteStreamOptions(object data) /// RemoteSessionCapability object. internal static RemoteSessionCapability GetSessionCapability(object data) { - if (!(data is PSObject dataAsPSObject)) + if (data is not PSObject dataAsPSObject) { throw new PSRemotingDataStructureException( RemotingErrorIdStrings.CantCastRemotingDataToPSObject, data.GetType().FullName); diff --git a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs index 94ffe3a68e6..07e17e8b63a 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs @@ -2836,7 +2836,7 @@ internal static Hashtable[] TryGetHashtableArray(object hashObj) for (int i = 0; i < hashArray.Length; i++) { - if (!(objArray[i] is Hashtable hash)) + if (objArray[i] is not Hashtable hash) { return null; } diff --git a/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs b/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs index 7e7aa767d5c..71dda0d0b7a 100644 --- a/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs +++ b/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs @@ -327,7 +327,7 @@ public override void PushRunspace(Runspace runspace) throw new PSInvalidOperationException(RemotingErrorIdStrings.ServerDriverRemoteHostAlreadyPushed); } - if (!(runspace is RemoteRunspace remoteRunspace)) + if (runspace is not RemoteRunspace remoteRunspace) { throw new PSInvalidOperationException(RemotingErrorIdStrings.ServerDriverRemoteHostNotRemoteRunspace); } From 0d5d7deeff2f53d05732a2f751d7b5618cabc4d5 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:15:13 -0700 Subject: [PATCH 128/378] Integrate Windows packaging into windows-ci workflow using reusable workflow (#26224) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk --- .../infrastructure/path-filters/action.yml | 18 ++++ .github/workflows/windows-ci.yml | 10 +++ .../workflows/windows-packaging-reusable.yml | 88 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 .github/workflows/windows-packaging-reusable.yml diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index e150b1a9d09..09ed7c22d17 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -26,6 +26,9 @@ outputs: buildModuleChanged: description: 'Build module changes' value: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: + description: 'Packaging related changes' + value: ${{ steps.filter.outputs.packagingChanged }} runs: using: composite steps: @@ -85,6 +88,19 @@ runs: const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); + const packagingChanged = files.some(file => + file.filename === '.github/workflows/windows-ci.yml' || + file.filename.startsWith('assets/wix/') || + file.filename === 'PowerShell.Common.props' || + file.filename.match(/^src\/.*\.csproj$/) || + file.filename.startsWith('test/packaging/windows/') || + file.filename.startsWith('tools/packaging/') || + file.filename.startsWith('tools/wix/') + ) || + buildModuleChanged || + globalConfigChanged || + toolsCiPsm1Changed; + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; core.setOutput('toolsChanged', toolsChanged); @@ -94,6 +110,7 @@ runs: core.setOutput('mainSourceChanged', mainSourceChanged); core.setOutput('buildModuleChanged', buildModuleChanged); core.setOutput('globalConfigChanged', globalConfigChanged); + core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); @@ -106,4 +123,5 @@ runs: Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" + Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" shell: pwsh diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 63e6c5ab7a3..64d37eb1ae5 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -41,6 +41,8 @@ env: POWERSHELL_TELEMETRY_OPTOUT: 1 __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts jobs: changes: name: Change Detection @@ -54,6 +56,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -158,6 +161,12 @@ jobs: fetch-depth: 1000 - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" + windows_packaging: + name: Windows Packaging + needs: + - changes + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} + uses: ./.github/workflows/windows-packaging-reusable.yml ready_to_merge: name: windows ready to merge needs: @@ -166,6 +175,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml new file mode 100644 index 00000000000..5a763544c62 --- /dev/null +++ b/.github/workflows/windows-packaging-reusable.yml @@ -0,0 +1,88 @@ +name: Windows Packaging (Reusable) + +on: + workflow_call: + +env: + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts + +jobs: + package: + name: ${{ matrix.architecture }} - ${{ matrix.channel }} + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - architecture: x64 + channel: preview + runtimePrefix: win7 + - architecture: x86 + channel: stable + runtimePrefix: win7 + - architecture: x86 + channel: preview + runtimePrefix: win7 + - architecture: arm64 + channel: preview + runtimePrefix: win + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1000 + + - name: Capture Environment + if: success() || failure() + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + shell: pwsh + + - name: Capture PowerShell Version Table + if: success() || failure() + run: | + $PSVersionTable + shell: pwsh + + - name: Switch to Public Feeds + if: success() + run: | + Import-Module .\tools\ci.psm1 + Switch-PSNugetConfig -Source Public + shell: pwsh + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + if: success() + run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + shell: pwsh + + - name: Build and Package + run: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + Invoke-CIFinish -Runtime ${{ matrix.runtimePrefix }}-${{ matrix.architecture }} -channel ${{ matrix.channel }} + shell: pwsh + + - name: Upload Build Artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} + path: | + ${{ github.workspace }}/artifacts/**/* + !${{ github.workspace }}/artifacts/**/*.pdb From 1bd038c4df941dde7876b430362f6dcf813d9d5d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:16:22 -0700 Subject: [PATCH 129/378] Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26225) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../actions/test/linux-packaging/action.yml | 112 +++++++++--------- .github/workflows/linux-ci.yml | 32 +++-- build.psm1 | 2 +- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b4a9c3b55c0..736bddfa7a7 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -1,12 +1,5 @@ name: linux_packaging -description: 'Test very basic Linux packaging' - -# This isn't working yet -# It fails with - -# ERROR: While executing gem ... (Gem::FilePermissionError) -# You don't have write permissions for the /var/lib/gems/2.7.0 directory. -# WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. +description: 'Linux packaging for PowerShell' runs: using: composite @@ -15,58 +8,64 @@ runs: if: success() || failure() run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' shell: pwsh + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + - name: Download Build Artifacts uses: actions/download-artifact@v4 with: - path: "${{ github.workspace }}" + name: build + path: "${{ runner.workspace }}/build" + - name: Capture Artifacts Directory continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + run: Get-ChildItem "${{ runner.workspace }}/build/*" -Recurse shell: pwsh - name: Bootstrap run: |- Import-Module ./build.psm1 Start-PSBootstrap -Scenario Package + Write-Verbose -Verbose "Start Sync-PSTags" + Sync-PSTags -AddRemoteIfMissing + Write-Verbose -Verbose "End Sync-PSTags" shell: pwsh - - name: Capture Artifacts Directory - continue-on-error: true - run: Import-Module ./build.psm1 + + - name: Extract Build ZIP + run: |- + $destinationFolder = "${{ runner.workspace }}/bins" + $archiveFile = "${{ runner.workspace }}/build/build.zip" + + Write-Verbose "Extracting $archiveFile to $destinationFolder" -Verbose + New-Item -ItemType Directory -Path $destinationFolder -Force | Out-Null + Expand-Archive -Path $archiveFile -DestinationPath $destinationFolder -Force shell: pwsh - - name: Extract Files - uses: actions/github-script@v7.0.0 - env: - DESTINATION_FOLDER: "${{ github.workspace }}/bins" - ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" - with: - script: |- - const fs = require('fs').promises - const path = require('path') - const target = path.resolve(process.env.DESTINATION_FOLDER) - const patterns = process.env.ARCHIVE_FILE_PATTERNS - const globber = await glob.create(patterns) - await io.mkdirP(path.dirname(target)) - for await (const file of globber.globGenerator()) { - if ((await fs.lstat(file)).isDirectory()) continue - await exec.exec(`7z x ${file} -o${target} -aoa`) - } + - name: Fix permissions continue-on-error: true run: |- - find "${{ github.workspace }}/bins" -type d -exec chmod +rwx {} \; - find "${{ github.workspace }}/bins" -type f -exec chmod +rw {} \; + find "${{ runner.workspace }}/bins" -type d -exec chmod +rwx {} \; + find "${{ runner.workspace }}/bins" -type f -exec chmod +rw {} \; shell: bash + - name: Capture Extracted Build ZIP continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + run: Get-ChildItem "${{ runner.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue shell: pwsh - - name: Packaging Tests - if: success() + + - name: Create Packages + env: + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ runner.workspace }}/packages run: |- + # Create the artifacts staging directory + New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + Import-Module ./tools/ci.psm1 - Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) - $rootPath = '${{ github.workspace }}/bins' + $rootPath = '${{ runner.workspace }}/bins' $originalRootPath = Split-Path -path $options.Output $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) $pwshPath = Join-Path -path $path -ChildPath 'pwsh' @@ -75,21 +74,24 @@ runs: Set-PSOptions $options Invoke-CIFinish shell: pwsh - - name: Upload packages - run: |- - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.deb" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=deb;artifactname=deb]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.rpm" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.tar.gz" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - shell: pwsh + + - name: Upload deb packages + uses: actions/upload-artifact@v4 + with: + name: packages-deb + path: ${{ runner.workspace }}/packages/*.deb + if-no-files-found: ignore + + - name: Upload rpm packages + uses: actions/upload-artifact@v4 + with: + name: packages-rpm + path: ${{ runner.workspace }}/packages/*.rpm + if-no-files-found: ignore + + - name: Upload tar.gz packages + uses: actions/upload-artifact@v4 + with: + name: packages-tar + path: ${{ runner.workspace }}/packages/*.tar.gz + if-no-files-found: ignore diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index b58b75c64a4..2e4c54d4068 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -229,24 +229,22 @@ jobs: - linux_test_unelevated_ci - linux_test_unelevated_others - analyze + - linux_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} - # TODO: Enable this when we have a Linux packaging workflow - - # ERROR: While executing gem ... (Gem::FilePermissionError) - # You don't have write permissions for the /var/lib/gems/2.7.0 directory. - # WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. - - # linux_packaging: - # name: Attempt Linux Packaging - # needs: ci_build - # runs-on: ubuntu-20.04 - # steps: - # - name: checkout - # uses: actions/checkout@v5 - # with: - # fetch-depth: 1000 - # - name: Verify xUnit test results - # uses: "./.github/actions/test/linux-packaging" + linux_packaging: + name: Linux Packaging + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Linux Packaging + uses: "./.github/actions/test/linux-packaging" diff --git a/build.psm1 b/build.psm1 index a610c684e2c..98d080ecc99 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2252,7 +2252,7 @@ function Install-GlobalGem { # We cannot guess if the user wants to run gem install as root on linux and windows, # but macOs usually requires sudo $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD) { + if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { $gemsudo = $sudo } From fcb0e5cde36d50c998095264a3d398ec10ba7b54 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 20 Oct 2025 06:18:37 +0100 Subject: [PATCH 130/378] Remove redundant `CharSet` from `StructLayout` attributes. Part 1 (#26216) --- .../namespaces/Win32Native.cs | 4 ++-- .../security/SecureStringHelper.cs | 2 +- .../security/nativeMethods.cs | 16 ++++++++-------- .../utils/PlatformInvokes.cs | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/namespaces/Win32Native.cs b/src/System.Management.Automation/namespaces/Win32Native.cs index 5c668fd471f..4f2c65c49f5 100644 --- a/src/System.Management.Automation/namespaces/Win32Native.cs +++ b/src/System.Management.Automation/namespaces/Win32Native.cs @@ -76,14 +76,14 @@ internal enum SID_NAME_USE #region Struct - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct SID_AND_ATTRIBUTES { internal IntPtr Sid; internal uint Attributes; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct TOKEN_USER { internal SID_AND_ATTRIBUTES User; diff --git a/src/System.Management.Automation/security/SecureStringHelper.cs b/src/System.Management.Automation/security/SecureStringHelper.cs index d06e33f9567..5ff5881bab4 100644 --- a/src/System.Management.Automation/security/SecureStringHelper.cs +++ b/src/System.Management.Automation/security/SecureStringHelper.cs @@ -594,7 +594,7 @@ internal static class CAPI internal const int E_FILENOTFOUND = unchecked((int)0x80070002); // File not found internal const int ERROR_FILE_NOT_FOUND = 2; // File not found - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct CRYPTOAPI_BLOB { internal uint cbData; diff --git a/src/System.Management.Automation/security/nativeMethods.cs b/src/System.Management.Automation/security/nativeMethods.cs index ae880e05518..6dd8f59d613 100644 --- a/src/System.Management.Automation/security/nativeMethods.cs +++ b/src/System.Management.Automation/security/nativeMethods.cs @@ -1287,28 +1287,28 @@ internal enum SecurityInformation : uint UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct LUID { internal uint LowPart; internal uint HighPart; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct LUID_AND_ATTRIBUTES { internal LUID Luid; internal uint Attributes; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct TOKEN_PRIVILEGE { internal uint PrivilegeCount; internal LUID_AND_ATTRIBUTES Privilege; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct ACL { internal byte AclRevision; @@ -1318,7 +1318,7 @@ internal struct ACL internal ushort Sbz2; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct ACE_HEADER { internal byte AceType; @@ -1326,7 +1326,7 @@ internal struct ACE_HEADER internal ushort AceSize; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct SYSTEM_AUDIT_ACE { internal ACE_HEADER Header; @@ -1334,7 +1334,7 @@ internal struct SYSTEM_AUDIT_ACE internal uint SidStart; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct LSA_UNICODE_STRING { internal ushort Length; @@ -1342,7 +1342,7 @@ internal struct LSA_UNICODE_STRING internal IntPtr Buffer; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct CENTRAL_ACCESS_POLICY { internal IntPtr CAPID; diff --git a/src/System.Management.Automation/utils/PlatformInvokes.cs b/src/System.Management.Automation/utils/PlatformInvokes.cs index fbd4117e844..f9e78f5d1d3 100644 --- a/src/System.Management.Automation/utils/PlatformInvokes.cs +++ b/src/System.Management.Automation/utils/PlatformInvokes.cs @@ -444,28 +444,28 @@ internal static extern bool AdjustTokenPrivileges(IntPtr tokenHandler, bool disa out TOKEN_PRIVILEGE previousPrivilegeState, ref int returnLength); - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct TOKEN_PRIVILEGE { internal uint PrivilegeCount; internal LUID_AND_ATTRIBUTES Privilege; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct LUID { internal uint LowPart; internal uint HighPart; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct LUID_AND_ATTRIBUTES { internal LUID Luid; internal uint Attributes; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential)] internal struct PRIVILEGE_SET { internal uint PrivilegeCount; From e25ade306baaf9e7db7b4e1df8bce9cf476ff33c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 20 Oct 2025 07:12:49 +0100 Subject: [PATCH 131/378] Enable IDE0080: RemoveConfusingSuppressionForIsExpression (#26206) --- .globalconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index 68fb0a66b2d..ed1d6c1a335 100644 --- a/.globalconfig +++ b/.globalconfig @@ -1454,7 +1454,7 @@ dotnet_diagnostic.IDE0079.severity = silent # IDE0080: RemoveConfusingSuppressionForIsExpression # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0080 -dotnet_diagnostic.IDE0080.severity = silent +dotnet_diagnostic.IDE0080.severity = warning # IDE0081: RemoveUnnecessaryByVal # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0081 From 4a7bf2574e723ffc86816c5c8d6cdcd1fa1031b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:11:45 -0700 Subject: [PATCH 132/378] Bump github/codeql-action from 4.30.8 to 4.30.9 (#26249) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 2e4c54d4068..b12ebbcf317 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -192,7 +192,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 + uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -218,7 +218,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 + uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 2a12425a829..f612ed0e22a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3.29.5 + uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 with: sarif_file: results.sarif From b53a551284606e234fa8fbbbff4a06eca9df08dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 11:12:17 -0700 Subject: [PATCH 133/378] Bump actions/setup-dotnet from 4 to 5 (#26248) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/windows-packaging-reusable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 5a763544c62..a48e071e7a1 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -60,7 +60,7 @@ jobs: shell: pwsh - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: global-json-file: ./global.json From 9470212e6a1190551a79cacf54c531637f8f1ff0 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 20 Oct 2025 19:16:44 +0100 Subject: [PATCH 134/378] Fix CA1837: Use 'Environment.ProcessId' (#26242) --- .../security/CertificateProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs index 2a05a9bf30d..08ee5a70f51 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs @@ -3459,8 +3459,7 @@ private static bool IsUIAllowed(PSHost host) return false; uint SessionId; - uint ProcessId = (uint)System.Diagnostics.Process.GetCurrentProcess().Id; - if (!SMASecurity.NativeMethods.ProcessIdToSessionId(ProcessId, out SessionId)) + if (!SMASecurity.NativeMethods.ProcessIdToSessionId((uint)Environment.ProcessId, out SessionId)) return false; if (SessionId == 0) From 5661a5152f0aba7ab460132566d4f36950993096 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:18:23 -0700 Subject: [PATCH 135/378] Replace fpm with native rpmbuild for RPM package generation (#26233) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../actions/test/linux-packaging/action.yml | 13 + .github/workflows/linux-ci.yml | 3 +- build.psm1 | 21 +- .../linux/package-validation.tests.ps1 | 91 +++++ tools/ci.psm1 | 26 +- tools/packaging/packaging.psm1 | 326 ++++++++++++++++-- 6 files changed, 440 insertions(+), 40 deletions(-) create mode 100644 test/packaging/linux/package-validation.tests.ps1 diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 736bddfa7a7..b7bbdf37185 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -62,6 +62,9 @@ runs: # Create the artifacts staging directory New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + # Import packaging module to ensure RPM packaging changes are loaded + Import-Module ./build.psm1 -Force + Import-Module ./tools/packaging/packaging.psm1 -Force Import-Module ./tools/ci.psm1 Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) @@ -75,6 +78,16 @@ runs: Invoke-CIFinish shell: pwsh + - name: Validate Package Names + run: |- + # Run Pester tests to validate package names + Import-Module Pester -Force + $testResults = Invoke-Pester -Path ./test/packaging/linux/package-validation.tests.ps1 -PassThru + if ($testResults.FailedCount -gt 0) { + throw "Package validation tests failed" + } + shell: pwsh + - name: Upload deb packages uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index b12ebbcf317..0f0cd110303 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -239,7 +240,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout diff --git a/build.psm1 b/build.psm1 index 98d080ecc99..88878bdd635 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2401,11 +2401,24 @@ function Start-PSBootstrap { } # Install [fpm](https://github.com/jordansissel/fpm) + # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) + if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { + Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" + Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" + Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" + Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + } + + # For RPM-based systems, ensure rpmbuild is available + if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for rpmbuild..." + if (!(Get-Command rpmbuild -ErrorAction SilentlyContinue)) { + Write-Warning "rpmbuild not found. Installing rpm-build package..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode + } + } } } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 new file mode 100644 index 00000000000..241863de45d --- /dev/null +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -0,0 +1,91 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Linux Package Name Validation" { + BeforeAll { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "$env:GITHUB_WORKSPACE/../packages" + } else { + $env:SYSTEM_ARTIFACTSDIRECTORY + } + + if (-not $artifactsDir) { + throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set." + } + + Write-Verbose "Artifacts directory: $artifactsDir" -Verbose + } + + Context "RPM Package Names" { + It "Should have valid RPM package names" { + $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue + + if ($rpmPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" + return + } + + $invalidPackages = @() + # Regex pattern for valid RPM package names. + # Breakdown: + # ^powershell\- : Starts with 'powershell-' + # (preview-|lts-)? : Optionally 'preview-' or 'lts-' + # \d+\.\d+\.\d+ : Version number (e.g., 7.6.0) + # (_[a-z]*\.\d+)? : Optional underscore, letters, dot, and digits (e.g., _alpha.1) + # -1\. : Literal '-1.' + # (preview\.\d+\.)? : Optional 'preview.' and digits, followed by a dot + # (rh|cm)\. : Either 'rh.' or 'cm.' + # (x86_64|aarch64)\.rpm$ : Architecture and file extension + $rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(preview\.\d+\.)?(rh|cm)\.(x86_64|aarch64)\.rpm' + + foreach ($package in $rpmPackages) { + if ($package.Name -notmatch $rpmPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid RPM package name" + Write-Warning "$($package.Name) is not a valid RPM package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $rpmPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Tar.Gz Package Names" { + It "Should have valid tar.gz package names" { + $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue + + if ($tarPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" + return + } + + $invalidPackages = @() + foreach ($package in $tarPackages) { + # Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz + # Also matches various runtime configurations + if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') { + $invalidPackages += "$($package.Name) is not a valid tar.gz package name" + Write-Warning "$($package.Name) is not a valid tar.gz package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $tarPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Package Existence" { + It "Should find at least one package in artifacts directory" { + $allPackages = Get-ChildItem -Path $artifactsDir -Recurse -Include *.rpm, *.tar.gz, *.deb -ErrorAction SilentlyContinue + + $allPackages.Count | Should -BeGreaterThan 0 -Because "At least one package should exist in the artifacts directory" + } + } +} diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 7b13ded1811..9e95e68c843 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -874,16 +874,36 @@ function New-LinuxPackage $packageObj = $package } - Write-Log -message "Artifacts directory: ${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" - Copy-Item $packageObj.FullName -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + + # Ensure artifacts directory exists + if (-not (Test-Path $artifactsDir)) { + New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null + } + + Write-Log -message "Artifacts directory: $artifactsDir" + Copy-Item $packageObj.FullName -Destination $artifactsDir -Force } if ($IsLinux) { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + # Create and package Raspbian .tgz + # Build must be clean for Raspbian Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release' $armPackage = Start-PSPackage @packageParams -Type tar-arm -SkipReleaseChecks - Copy-Item $armPackage -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + Copy-Item $armPackage -Destination $artifactsDir -Force } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8e7fb3c4e08..894323a4b98 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1245,40 +1245,124 @@ function New-UnixPackage { # Setup package dependencies $Dependencies = @(Get-PackageDependencies @packageDependenciesParams) - $Arguments = @() - - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - # Build package try { - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } + if ($Type -eq 'rpm') { + # Use rpmbuild directly for RPM packages + if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { + Write-Log "Creating RPM package with rpmbuild..." + + # Create rpmbuild directory structure + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + $specsDir = Join-Path $rpmBuildRoot "SPECS" + $rpmsDir = Join-Path $rpmBuildRoot "RPMS" + + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null + New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null + + # Generate RPM spec file + $specContent = New-RpmSpec ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture + + $specFile = Join-Path $specsDir "$Name.spec" + $specContent | Out-File -FilePath $specFile -Encoding ascii + Write-Verbose "Generated spec file: $specFile" -Verbose + + # Log the spec file content + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Host "::group::RPM Spec File Content" + Write-Host $specContent + Write-Host "::endgroup::" + } else { + Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose + } + + # Build RPM package + try { + # Use bash to properly handle rpmbuild arguments + # Add --target for cross-architecture builds + $targetArch = "" + if ($HostArchitecture -ne "x86_64" -and $HostArchitecture -ne "noarch") { + $targetArch = "--target $HostArchitecture" + } + $buildCmd = "rpmbuild -bb --quiet $targetArch --define '_topdir $rpmBuildRoot' --buildroot '$rpmBuildRoot/BUILDROOT' '$specFile'" + Write-Verbose "Running: $buildCmd" -Verbose + $Output = bash -c $buildCmd 2>&1 + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + throw "rpmbuild failed with exit code $exitCode" + } + + # Find the generated RPM + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | + Select-Object -First 1 + + if ($rpmFile) { + # Copy RPM to current location + Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force + $Output = @("Created package {:path=>""$($rpmFile.Name)""}") + } else { + throw "RPM file not found after build" + } + } + catch { + Write-Verbose -Message "!!!Handling error in rpmbuild!!!" -Verbose -ErrorAction SilentlyContinue + if ($Output) { + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + } + Get-Error -InputObject $_ + throw + } } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw + } else { + # Use fpm for DEB and macOS packages + $Arguments = @() + + $Arguments += Get-FpmArguments ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Type $Type ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -AppsFolder $AppsFolder ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture ` + -ErrorAction Stop + + if ($PSCmdlet.ShouldProcess("Create $type package")) { + Write-Log "Creating package with fpm $Arguments..." + try { + $Output = Start-NativeExecution { fpm $Arguments } + } + catch { + Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } } } } finally { @@ -1295,6 +1379,16 @@ function New-UnixPackage { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError } } + + # Clean up rpmbuild directory if it was created + if ($Type -eq 'rpm') { + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + if (Test-Path $rpmBuildRoot) { + Write-Verbose "Cleaning up rpmbuild directory: $rpmBuildRoot" -Verbose + Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1439,6 +1533,165 @@ Class LinkInfo [string] $Destination } +function New-RpmSpec +{ + param( + [Parameter(Mandatory,HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory,HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory,HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory,HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory,HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory,HelpMessage='Packages required to install this package')] + [String[]]$Dependencies, + + [Parameter(Mandatory,HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(Mandatory,HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [String]$Distribution = 'rhel.7', + [string]$HostArchitecture + ) + + # RPM doesn't allow hyphens in version, so convert them to underscores + # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 + $rpmVersion = $Version -replace '-', '_' + + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") + # Don't use RPM macros - build the full release string in PowerShell + $rpmRelease = "$Iteration.$Distribution" + + $specContent = @" +# RPM spec file for PowerShell +# Generated by PowerShell build system + +Name: $Name +Version: $rpmVersion +Release: $rpmRelease +Summary: PowerShell - Cross-platform automation and configuration tool/framework +License: MIT +URL: https://microsoft.com/powershell +AutoReq: no + +"@ + + # Only add BuildArch if not doing cross-architecture build + # For cross-arch builds, we'll rely on --target option + if ($HostArchitecture -eq "x86_64" -or $HostArchitecture -eq "noarch") { + $specContent += "BuildArch: $HostArchitecture`n`n" + } else { + # For cross-architecture builds, don't specify BuildArch in spec + # The --target option will handle the architecture + + # Disable automatic binary stripping for cross-arch builds + # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: + # "Unable to recognise the format of the input file" + # See: https://rpm-software-management.github.io/rpm/manual/macros.html + # __strip: This macro controls the command used for stripping binaries during the build process. + # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. + $specContent += "%define __strip /bin/true`n" + + # Disable debug package generation to prevent strip-related errors + # Debug packages require binary stripping which fails for cross-arch builds + # See: https://rpm-packaging-guide.github.io/#debugging + # See: https://docs.fedoraproject.org/en-US/packaging-guidelines/Debuginfo/#_useless_or_incomplete_debuginfo_packages_due_to_other_reasons + $specContent += "%global debug_package %{nil}`n`n" + } + + # Add dependencies + foreach ($dep in $Dependencies) { + $specContent += "Requires: $dep`n" + } + + $specContent += @" + +%description +$Description + +%prep +# No prep needed - files are already staged + +%build +# No build needed - binaries are pre-built + +%install +rm -rf `$RPM_BUILD_ROOT +mkdir -p `$RPM_BUILD_ROOT$Destination +mkdir -p `$RPM_BUILD_ROOT$(Split-Path -Parent $ManDestination) + +# Copy all files from staging to destination +cp -r $Staging/* `$RPM_BUILD_ROOT$Destination/ + +# Copy man page +cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination + +"@ + + # Add symlinks - we need to get the target of the temp symlink + foreach ($link in $LinkInfo) { + $linkDir = Split-Path -Parent $link.Destination + $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" + # For RPM, we copy the symlink itself (which fpm does by including it in the source) + # The symlink at $link.Source points to the actual target, so we'll copy it + # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. + $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" + } + + # Post-install script + $postInstallContent = Get-Content -Path $AfterInstallScript -Raw + $specContent += "`n%post`n" + $specContent += $postInstallContent + $specContent += "`n" + + # Post-uninstall script + $postUninstallContent = Get-Content -Path $AfterRemoveScript -Raw + $specContent += "%postun`n" + $specContent += $postUninstallContent + $specContent += "`n" + + # Files section + $specContent += "%files`n" + $specContent += "%defattr(-,root,root,-)`n" + $specContent += "$Destination/*`n" + $specContent += "$ManDestination`n" + + # Add symlinks to files + foreach ($link in $LinkInfo) { + $specContent += "$($link.Destination)`n" + } + + # Changelog with correct date format for RPM + $changelogDate = Get-Date -Format "ddd MMM dd yyyy" + $specContent += "`n%changelog`n" + $specContent += "* $changelogDate PowerShell Team - $rpmVersion-$rpmRelease`n" + $specContent += "- Automated build`n" + + return $specContent +} + function Get-FpmArguments { param( @@ -1651,7 +1904,16 @@ function Get-PackageDependencies function Test-Dependencies { - foreach ($Dependency in "fpm") { + # Note: RPM packages no longer require fpm; they use rpmbuild directly + # DEB packages still use fpm + $Dependencies = @() + + # Only check for fpm on Debian-based systems + if ($Environment.IsDebianFamily) { + $Dependencies += "fpm" + } + + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { # These tools are not added to the path automatically on OpenSUSE 13.2 # try adding them to the path and re-tesing first From 810c1eafdf6692b7bf4a4423ef0a41cec5e283da Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:23:27 -0700 Subject: [PATCH 136/378] Update dependabot.yml to monitor release/* branches (#26251) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/dependabot.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fdb18f82c9d..45d2e8fe928 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,9 +8,25 @@ updates: labels: - "CL-BuildPackaging" - - package-ecosystem: docker + - package-ecosystem: "github-actions" + directory: "/" + target-branch: "release/*" + schedule: + interval: "daily" + labels: + - "CL-BuildPackaging" + + - package-ecosystem: "docker" directory: / schedule: interval: daily labels: - "CL-BuildPackaging" + + - package-ecosystem: "docker" + directory: "/" + target-branch: "release/*" + schedule: + interval: daily + labels: + - "CL-BuildPackaging" From 90e9159cb5199f4f4e24e759fa255236bd7a3290 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:59:29 -0700 Subject: [PATCH 137/378] Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26243) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/actions/build/ci/action.yml | 14 --- .github/actions/test/verify_xunit/action.yml | 21 ---- .../instructions/build-configuration-guide.md | 95 +++++++++++++++++++ .../git-requirements-for-builds.md | 71 ++++++++++++++ .github/instructions/start-psbuild-basics.md | 92 ++++++++++++++++++ .../instructions/troubleshooting-builds.md | 92 ++++++++++++++++++ .../instructions/workflow-prerequisites.md | 91 ++++++++++++++++++ .github/workflows/linux-ci.yml | 19 ++-- .github/workflows/macos-ci.yml | 19 ++-- .github/workflows/windows-ci.yml | 19 ++-- .github/workflows/xunit-tests.yml | 53 +++++++++++ 11 files changed, 515 insertions(+), 71 deletions(-) delete mode 100644 .github/actions/test/verify_xunit/action.yml create mode 100644 .github/instructions/build-configuration-guide.md create mode 100644 .github/instructions/git-requirements-for-builds.md create mode 100644 .github/instructions/start-psbuild-basics.md create mode 100644 .github/instructions/troubleshooting-builds.md create mode 100644 .github/instructions/workflow-prerequisites.md create mode 100644 .github/workflows/xunit-tests.yml diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 93adaf6b17a..997be8b264c 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -31,22 +31,8 @@ runs: Import-Module .\tools\ci.psm1 Invoke-CIBuild shell: pwsh - - name: xUnit Tests - if: success() - continue-on-error: true - run: |- - Write-Verbose -Verbose "Running xUnit tests..." - Import-Module .\tools\ci.psm1 - Restore-PSOptions - Invoke-CIxUnit -SkipFailing - shell: pwsh - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: build path: ${{ runner.workspace }}/build - - name: Upload xunit artifact - uses: actions/upload-artifact@v4 - with: - name: testResults-xunit - path: ${{ runner.workspace }}/xunit diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml deleted file mode 100644 index fccca27182f..00000000000 --- a/.github/actions/test/verify_xunit/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: verify_xunit -description: 'Verify xUnit Results' - -runs: - using: composite - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - path: "${{ github.workspace }}" - - name: Capture artifacts directory - continue-on-error: true - run: dir "${{ github.workspace }}\testResults-xunit\*" -Recurse - shell: pwsh - - name: Test - if: success() - run: |- - Import-Module .\tools\ci.psm1 - $xUnitTestResultsFile = "${{ github.workspace }}\testResults-xunit\xUnitTestResults.xml" - Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile - shell: pwsh diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md new file mode 100644 index 00000000000..d082bcbe774 --- /dev/null +++ b/.github/instructions/build-configuration-guide.md @@ -0,0 +1,95 @@ +# Build Configuration Guide + +## Choosing the Right Configuration + +### For Testing + +**Use: Default (Debug)** + +```yaml +- name: Build for Testing + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +**Why Debug:** +- Includes debugging symbols +- Better error messages +- Faster build times +- Suitable for xUnit and Pester tests + +**Do NOT use:** +- `-Configuration 'Release'` (unnecessary for tests) +- `-ReleaseTag` (not needed for tests) +- `-CI` (unless you specifically need Pester module) + +### For Release/Packaging + +**Use: Release with version tag** + +```yaml +- name: Build for Release + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +**Why Release:** +- Optimized binaries +- No debug symbols (smaller size) +- Production-ready + +### For Code Coverage + +**Use: CodeCoverage configuration** + +```yaml +- name: Build with Coverage + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild -Configuration 'CodeCoverage' +``` + +## Platform Considerations + +### All Platforms + +Same commands work across Linux, Windows, and macOS: + +```yaml +strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] +runs-on: ${{ matrix.os }} +steps: + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +### Output Locations + +**Linux/macOS:** +``` +src/powershell-unix/bin/Debug///publish/ +``` + +**Windows:** +``` +src/powershell-win-core/bin/Debug///publish/ +``` + +## Best Practices + +1. Use default configuration for testing +2. Avoid redundant parameters +3. Match configuration to purpose +4. Use `-CI` only when needed +5. Always specify `-ReleaseTag` for release or packaging builds diff --git a/.github/instructions/git-requirements-for-builds.md b/.github/instructions/git-requirements-for-builds.md new file mode 100644 index 00000000000..3c8cd91e7c7 --- /dev/null +++ b/.github/instructions/git-requirements-for-builds.md @@ -0,0 +1,71 @@ +# Git Requirements for Building PowerShell + +## Fetch Depth + +**Required:** `fetch-depth: 1000` + +The PowerShell build process uses `git describe --abbrev=60 --long` to generate version information. This requires access to git history and tags. + +### Problem + +Without sufficient fetch depth, builds fail with: +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +### Solution + +Always use `fetch-depth: 1000` in the checkout step: + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Tag Synchronization + +**Required:** `Sync-PSTags -AddRemoteIfMissing` + +The build process needs git tags to properly version the build. + +### Problem + +Without tag synchronization: +- Version information is incorrect +- Build versioning fails + +### Solution + +Include tag synchronization in the bootstrap step: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Example + +```yaml +steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` diff --git a/.github/instructions/start-psbuild-basics.md b/.github/instructions/start-psbuild-basics.md new file mode 100644 index 00000000000..ae216a1584d --- /dev/null +++ b/.github/instructions/start-psbuild-basics.md @@ -0,0 +1,92 @@ +# Start-PSBuild Basics + +## Purpose + +`Start-PSBuild` builds PowerShell from source. It's defined in `build.psm1` and used in CI/CD workflows. + +## Default Usage + +For most scenarios, use with no parameters: + +```powershell +Import-Module ./tools/ci.psm1 +Start-PSBuild +``` + +**Default behavior:** +- Configuration: `Debug` +- PSModuleRestore: Enabled +- Runtime: Auto-detected for platform + +## Common Configurations + +### Debug Build (Default) + +```powershell +Start-PSBuild +``` + +Use for: +- Testing (xUnit, Pester) +- Development +- Debugging + +### Release Build + +```powershell +Start-PSBuild -Configuration 'Release' +``` + +Use for: +- Production packages +- Distribution +- Performance testing + +### Code Coverage Build + +```powershell +Start-PSBuild -Configuration 'CodeCoverage' +``` + +Use for: +- Code coverage analysis +- Test coverage reports + +## Common Parameters + +### -Configuration + +Values: `Debug`, `Release`, `CodeCoverage`, `StaticAnalysis` + +Default: `Debug` + +### -CI + +Restores Pester module for CI environments. + +```powershell +Start-PSBuild -CI +``` + +### -PSModuleRestore + +Now enabled by default. Use `-NoPSModuleRestore` to skip. + +### -ReleaseTag + +Specifies version tag for release builds: + +```powershell +$releaseTag = Get-ReleaseTag +Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +## Workflow Example + +```yaml +- name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` diff --git a/.github/instructions/troubleshooting-builds.md b/.github/instructions/troubleshooting-builds.md new file mode 100644 index 00000000000..37f5df00912 --- /dev/null +++ b/.github/instructions/troubleshooting-builds.md @@ -0,0 +1,92 @@ +# Troubleshooting Build Issues + +## Git Describe Error + +**Error:** +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +**Cause:** Insufficient git history (shallow clone) + +**Solution:** Add `fetch-depth: 1000` to checkout step + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Version Information Incorrect + +**Symptom:** Build produces wrong version numbers + +**Cause:** Git tags not synchronized + +**Solution:** Run `Sync-PSTags -AddRemoteIfMissing`: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## PowerShell Binary Not Built + +**Error:** +``` +Exception: CoreCLR pwsh.exe was not built +``` + +**Causes:** +1. Build failed (check logs) +2. Wrong configuration used +3. Build output location incorrect + +**Solutions:** +1. Check build logs for errors +2. Verify correct configuration for use case +3. Use default parameters: `Start-PSBuild` + +## Module Restore Issues + +**Symptom:** Slow build or module restore failures + +**Causes:** +- Network issues +- Module cache problems +- Package source unavailable + +**Solutions:** +1. Retry the build +2. Check network connectivity +3. Use `-NoPSModuleRestore` if modules not needed +4. Clear package cache if persistent + +## .NET SDK Not Found + +**Symptom:** Build can't find .NET SDK + +**Solution:** Ensure .NET setup step runs first: + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +## Bootstrap Failures + +**Symptom:** Invoke-CIInstall fails + +**Causes:** +- Missing dependencies +- Network issues +- Platform-specific requirements not met + +**Solution:** Check prerequisites for your platform in build system docs diff --git a/.github/instructions/workflow-prerequisites.md b/.github/instructions/workflow-prerequisites.md new file mode 100644 index 00000000000..fe88abb384f --- /dev/null +++ b/.github/instructions/workflow-prerequisites.md @@ -0,0 +1,91 @@ +# Workflow Prerequisites for Building PowerShell + +## Required Steps Before Start-PSBuild + +These steps must run before calling `Start-PSBuild`: + +### 1. Checkout + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 # Required for version generation +``` + +### 2. Setup .NET + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +### 3. Bootstrap + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Prerequisites Example + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +## Why Each Step Matters + +**Checkout with fetch-depth:** +- Build needs git history for versioning +- Without it: `git describe` fails + +**Setup .NET:** +- Provides SDK for building +- Uses version from global.json + +**Bootstrap:** +- Installs dependencies +- Syncs git tags +- Prepares build environment + +## Optional Steps + +### Environment Capture (Debugging) + +```yaml +- name: Capture Environment + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + shell: pwsh +``` diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 0f0cd110303..450b5f4f147 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -147,20 +147,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: ubuntu-latest + test_results_artifact_name: testResults-xunit analyze: permissions: @@ -224,7 +219,7 @@ jobs: ready_to_merge: name: Linux ready to merge needs: - - verify_xunit + - xunit_tests - linux_test_elevated_ci - linux_test_elevated_others - linux_test_unelevated_ci diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 0007d550f06..7ec1fc6da06 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -143,20 +143,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: macos-15-large + test_results_artifact_name: testResults-xunit PackageMac-macos_packaging: name: macOS packaging (bootstrap only) needs: @@ -176,7 +171,7 @@ jobs: ready_to_merge: name: macos ready to merge needs: - - verify_xunit + - xunit_tests - PackageMac-macos_packaging - macos_test_elevated_ci - macos_test_elevated_others diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 64d37eb1ae5..37470475079 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -147,20 +147,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: windows-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: windows-latest + test_results_artifact_name: testResults-xunit windows_packaging: name: Windows Packaging needs: @@ -170,7 +165,7 @@ jobs: ready_to_merge: name: windows ready to merge needs: - - verify_xunit + - xunit_tests - windows_test_elevated_ci - windows_test_elevated_others - windows_test_unelevated_ci diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml new file mode 100644 index 00000000000..8bf5fd699d0 --- /dev/null +++ b/.github/workflows/xunit-tests.yml @@ -0,0 +1,53 @@ +name: xUnit Tests (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for xUnit tests' + type: string + required: false + default: ubuntu-latest + test_results_artifact_name: + description: 'Artifact name for xUnit test results directory' + type: string + required: false + default: testResults-xunit + +jobs: + xunit: + name: Run xUnit Tests + runs-on: ${{ inputs.runner_os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell and run xUnit tests + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild + Write-Host "Running full xUnit test suite (no skipping)..." + Invoke-CIxUnit + Write-Host "Completed xUnit test run." + + - name: Upload xUnit results + uses: actions/upload-artifact@v4 + if: always() + with: + name: ${{ inputs.test_results_artifact_name }} + path: ${{ github.workspace }}/xUnitTestResults.xml From ae12e4cb8c7694c8f3264c9098a0ffb809f6d202 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:26:48 -0700 Subject: [PATCH 138/378] Update outdated package references (#26148) --- test/xUnit/xUnit.tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 33f0a2dde00..90ae1a9b453 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -29,8 +29,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + From 38054547f52717e3ead13fc2970bc165f8d58be9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:09:31 -0700 Subject: [PATCH 139/378] Remove unused Azure Devops windows CI workflows (#26245) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .vsts-ci/templates/windows-test.yml | 92 ----------------- .vsts-ci/windows-daily.yml | 148 ---------------------------- 2 files changed, 240 deletions(-) delete mode 100644 .vsts-ci/templates/windows-test.yml delete mode 100644 .vsts-ci/windows-daily.yml diff --git a/.vsts-ci/templates/windows-test.yml b/.vsts-ci/templates/windows-test.yml deleted file mode 100644 index 22758e3953c..00000000000 --- a/.vsts-ci/templates/windows-test.yml +++ /dev/null @@ -1,92 +0,0 @@ -parameters: - pool: 'windows-2019' - imageName: 'PSWindows11-ARM64' - parentJobs: [] - purpose: '' - tagSet: 'CI' - -jobs: -- job: win_test_${{ parameters.purpose }}_${{ parameters.tagSet }} - dependsOn: - ${{ parameters.parentJobs }} - pool: - ${{ if startsWith( parameters.pool, 'windows-') }}: - vmImage: ${{ parameters.pool }} - ${{ else }}: - name: ${{ parameters.pool }} - demands: - - ImageOverride -equals ${{ parameters.imageName }} - - displayName: Windows Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} - - steps: - - powershell: | - [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 - $pwsh = Get-Command pwsh -ErrorAction SilentlyContinue -CommandType Application - - if ($null -eq $pwsh) { - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.ps1 -outfile ./install-powershell.ps1 - ./install-powershell.ps1 -Destination $powerShellPath - $vstsCommandString = "vso[task.setvariable variable=PATH]$powerShellPath;$env:PATH" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - } - - displayName: Install PowerShell if missing - condition: ne('${{ parameters.pool }}', 'windows-2019') - - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture Environment - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)" - - # must be run frow Windows PowerShell - - powershell: | - # Remove "Program Files\dotnet" from the env variable PATH, so old SDKs won't affect us. - Write-Host "Old Path:" - Write-Host $env:Path - - $dotnetPath = Join-Path $env:SystemDrive 'Program Files\dotnet' - $paths = $env:Path -split ";" | Where-Object { -not $_.StartsWith($dotnetPath) } - $env:Path = $paths -join ";" - - Write-Host "New Path:" - Write-Host $env:Path - - # Bootstrap - Import-Module .\tools\ci.psm1 - Invoke-CIInstall - displayName: Bootstrap - - - pwsh: | - Import-Module .\build.psm1 -force - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $options = (Get-PSOptions) - $path = split-path -path $options.Output - $rootPath = split-Path -path $path - Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force - Invoke-CITest -Purpose '${{ parameters.purpose }}' -TagSet '${{ parameters.tagSet }}' - displayName: Test - condition: succeeded() diff --git a/.vsts-ci/windows-daily.yml b/.vsts-ci/windows-daily.yml deleted file mode 100644 index 1e9306e9dd1..00000000000 --- a/.vsts-ci/windows-daily.yml +++ /dev/null @@ -1,148 +0,0 @@ -name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr) -trigger: - # Batch merge builds together while a merge build is running - batch: true - branches: - include: - - master - - release* - - feature* - paths: - include: - - '*' - exclude: - - /.vsts-ci/misc-analysis.yml - - /.github/ISSUE_TEMPLATE/* - - /.dependabot/config.yml -pr: - branches: - include: - - master - - release* - - feature* - paths: - include: - - '*' - exclude: - - /.vsts-ci/misc-analysis.yml - - /.github/ISSUE_TEMPLATE/* - - /.dependabot/config.yml - -variables: - GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - POWERSHELL_TELEMETRY_OPTOUT: 1 - DOTNET_NOLOGO: 1 - __SuppressAnsiEscapeSequences: 1 - -resources: -- repo: self - clean: true - -stages: -- stage: BuildWin - displayName: Build for Windows - jobs: - - template: templates/ci-build.yml - -- stage: TestWin - displayName: Test for Windows - jobs: - - job: win_test - pool: - vmImage: windows-2019 - displayName: Windows Test - timeoutInMinutes: 90 - - steps: - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: 'Capture Environment' - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - xunit/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - # must be run frow Windows PowerShell - - powershell: | - # Remove "Program Files\dotnet" from the env variable PATH, so old SDKs won't affect us. - Write-Host "Old Path:" - Write-Host $env:Path - - $dotnetPath = Join-Path $env:SystemDrive 'Program Files\dotnet' - $paths = $env:Path -split ";" | Where-Object { -not $_.StartsWith($dotnetPath) } - $env:Path = $paths -join ";" - - Write-Host "New Path:" - Write-Host $env:Path - - Import-Module .\tools\ci.psm1 - Invoke-CIInstall - displayName: Bootstrap - condition: succeededOrFailed() - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - useGlobalJson: true - packageType: 'sdk' - workingDirectory: $(Build.SourcesDirectory)" - - - pwsh: | - Import-Module .\build.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $path = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions)) - $rootPath = Split-Path -Path $path - Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force - displayName: 'Unzip Build' - condition: succeeded() - - - pwsh: | - Import-Module .\build.psm1 - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - Invoke-CITest -Purpose UnelevatedPesterTests -TagSet CI - displayName: Test - UnelevatedPesterTests - CI - condition: succeeded() - - - pwsh: | - Import-Module .\build.psm1 - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - Invoke-CITest -Purpose ElevatedPesterTests -TagSet CI - displayName: Test - ElevatedPesterTests - CI - condition: succeededOrFailed() - - - pwsh: | - Import-Module .\build.psm1 - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - Invoke-CITest -Purpose UnelevatedPesterTests -TagSet Others - displayName: Test - UnelevatedPesterTests - Others - condition: succeededOrFailed() - - - pwsh: | - Import-Module .\build.psm1 - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - Invoke-CITest -Purpose ElevatedPesterTests -TagSet Others - displayName: Test - ElevatedPesterTests - Others - condition: succeededOrFailed() - - - pwsh: | - Import-Module .\build.psm1 - $xUnitTestResultsFile = '$(System.ArtifactsDirectory)\xunit\xUnitTestResults.xml' - Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile - displayName: Verify xUnit Test Results - condition: succeededOrFailed() From 20cb6d2e8208c1482e8d82503613e9393e014887 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 20 Oct 2025 17:18:06 -0700 Subject: [PATCH 140/378] Update release tags to version 7.5.4 and 7.4.13 (#26258) --- tools/metadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index f9339e276f2..bbe64d0cefe 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,9 +1,9 @@ { - "StableReleaseTag": "v7.5.3", + "StableReleaseTag": "v7.5.4", "PreviewReleaseTag": "v7.6.0-preview.5", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.5.3", - "LTSReleaseTag" : ["v7.4.12"], + "ReleaseTag": "v7.5.4", + "LTSReleaseTag" : ["v7.4.13"], "NextReleaseTag": "v7.6.0-preview.6", "LTSRelease": { "Latest": false, "Package": false }, "StableRelease": { "Latest": false, "Package": false } From 92aa0eb90a1d18bf022578bcbb77dbb3d6296535 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:25:59 -0700 Subject: [PATCH 141/378] Add documentation for publishing Pester test results in GitHub Actions (#26254) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../publishing-pester-result.instructions.md | 272 ++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 .github/instructions/publishing-pester-result.instructions.md diff --git a/.github/instructions/publishing-pester-result.instructions.md b/.github/instructions/publishing-pester-result.instructions.md new file mode 100644 index 00000000000..49010e65a99 --- /dev/null +++ b/.github/instructions/publishing-pester-result.instructions.md @@ -0,0 +1,272 @@ +--- +applyTo: ".github/**/*.{yml,yaml}" +--- + +# Publishing Pester Test Results Instructions + +This document describes how the PowerShell repository uses GitHub Actions to publish Pester test results. + +## Overview + +The PowerShell repository uses a custom composite GitHub Action located at `.github/actions/test/process-pester-results` to process and publish Pester test results in CI/CD workflows. +This action aggregates test results from NUnitXml formatted files, creates a summary in the GitHub Actions job summary, and uploads the results as artifacts. + +## How It Works + +### Action Location and Structure + +**Path**: `.github/actions/test/process-pester-results/` + +The action consists of two main files: + +1. **action.yml** - The composite action definition +1. **process-pester-results.ps1** - PowerShell script that processes test results + +### Action Inputs + +The action accepts the following inputs: + +- **name** (required): A descriptive name for the test run (e.g., "UnelevatedPesterTests-CI") + - Used for naming the uploaded artifact and in the summary + - Format: `junit-pester-{name}` + +- **testResultsFolder** (optional): Path to the folder containing test result XML files + - Default: `${{ runner.workspace }}/testResults` + - The script searches for all `*.xml` files in this folder recursively + +### Action Workflow + +The action performs the following steps: + +1. **Process Test Results** + - Runs `process-pester-results.ps1` with the provided name and test results folder + - Parses all NUnitXml formatted test result files (`*.xml`) + - Aggregates test statistics across all files: + - Total test cases + - Errors + - Failures + - Not run tests + - Inconclusive tests + - Ignored tests + - Skipped tests + - Invalid tests + +1. **Generate Summary** + - Creates a markdown summary using the `$GITHUB_STEP_SUMMARY` environment variable + - Uses `Write-Log` and `Write-LogGroupStart`/`Write-LogGroupEnd` functions from `build.psm1` + - Outputs a formatted summary with all test statistics + - Example format: + + ```markdown + # Summary of {Name} + + - Total Tests: X + - Total Errors: X + - Total Failures: X + - Total Not Run: X + - Total Inconclusive: X + - Total Ignored: X + - Total Skipped: X + - Total Invalid: X + ``` + +1. **Upload Artifacts** + - Uses `actions/upload-artifact@v4` to upload test results + - Artifact name: `junit-pester-{name}` + - Always runs (even if previous steps fail) via `if: always()` + - Uploads the entire test results folder + +1. **Exit Status** + - Fails the job (exit 1) if: + - Any test errors occurred (`$testErrorCount -gt 0`) + - Any test failures occurred (`$testFailureCount -gt 0`) + - No test cases were run (`$testCaseCount -eq 0`) + +## Usage in Test Actions + +The `process-pester-results` action is called by two platform-specific composite test actions: + +### Linux/macOS Tests: `.github/actions/test/nix` + +Used in: + +- `.github/workflows/linux-ci.yml` +- `.github/workflows/macos-ci.yml` + +Example usage (lines 99-104 in `nix/action.yml`): + +```yaml +- name: Convert, Publish, and Upload Pester Test Results + uses: "./.github/actions/test/process-pester-results" + with: + name: "${{ inputs.purpose }}-${{ inputs.tagSet }}" + testResultsFolder: "${{ runner.workspace }}/testResults" +``` + +### Windows Tests: `.github/actions/test/windows` + +Used in: + +- `.github/workflows/windows-ci.yml` + +Example usage (line 78-83 in `windows/action.yml`): + +```yaml +- name: Convert, Publish, and Upload Pester Test Results + uses: "./.github/actions/test/process-pester-results" + with: + name: "${{ inputs.purpose }}-${{ inputs.tagSet }}" + testResultsFolder: ${{ runner.workspace }}\testResults +``` + +## Workflow Integration + +The process-pester-results action is integrated into the CI workflows through a multi-level hierarchy: + +### Level 1: Main CI Workflows + +- `linux-ci.yml` +- `macos-ci.yml` +- `windows-ci.yml` + +### Level 2: Test Jobs + +Each workflow contains multiple test jobs with different purposes and tag sets: + +- `UnelevatedPesterTests` with tagSet `CI` +- `ElevatedPesterTests` with tagSet `CI` +- `UnelevatedPesterTests` with tagSet `Others` +- `ElevatedPesterTests` with tagSet `Others` + +### Level 3: Platform Test Actions + +Test jobs use platform-specific actions: + +- `nix` for Linux and macOS +- `windows` for Windows + +### Level 4: Process Results Action + +Platform actions call `process-pester-results` to publish results + +## Test Execution Flow + +1. **Build Phase**: Source code is built (e.g., in `ci_build` job) +1. **Test Preparation**: + - Build artifacts are downloaded + - PowerShell is bootstrapped + - Test binaries are extracted +1. **Test Execution**: + - `Invoke-CITest` is called with: + - `-Purpose`: Test purpose (e.g., "UnelevatedPesterTests") + - `-TagSet`: Test category (e.g., "CI", "Others") + - `-OutputFormat NUnitXml`: Results format + - Results are written to `${{ runner.workspace }}/testResults` +1. **Results Processing**: + - `process-pester-results` action runs + - Results are aggregated and summarized + - Artifacts are uploaded + - Job fails if any tests failed or errored + +## Key Dependencies + +### PowerShell Modules + +- **build.psm1**: Provides utility functions + - `Write-Log`: Logging function with GitHub Actions support + - `Write-LogGroupStart`: Creates collapsible log groups + - `Write-LogGroupEnd`: Closes collapsible log groups + +### GitHub Actions Features + +- **GITHUB_STEP_SUMMARY**: Environment variable for job summary +- **actions/upload-artifact@v4**: For uploading test results +- **Composite Actions**: For reusable workflow steps + +### Test Result Format + +- **NUnitXml**: XML format for test results +- Expected XML structure with `test-results` root element containing: + - `total`: Total number of tests + - `errors`: Number of errors + - `failures`: Number of failures + - `not-run`: Number of tests not run + - `inconclusive`: Number of inconclusive tests + - `ignored`: Number of ignored tests + - `skipped`: Number of skipped tests + - `invalid`: Number of invalid tests + +## Best Practices + +1. **Naming Convention**: Use descriptive names that include both purpose and tagSet: + - Format: `{purpose}-{tagSet}` + - Example: `UnelevatedPesterTests-CI` + +1. **Test Results Location**: + - Default location: `${{ runner.workspace }}/testResults` + - Use platform-appropriate path separators (Windows: `\`, Unix: `/`) + +1. **Always Upload**: The artifact upload step uses `if: always()` to ensure results are uploaded even when tests fail + +1. **Error Handling**: The action will fail the job if: + - Tests have errors or failures (intentional fail-fast behavior) + - No tests were executed (potential configuration issue) + - `GITHUB_STEP_SUMMARY` is not set (environment issue) + +## Customizing for Your Repository + +To use this pattern in another repository: + +1. **Copy the Action Files**: + - Copy `.github/actions/test/process-pester-results/` directory + - Ensure the PowerShell script has proper permissions + +1. **Adjust Dependencies**: + - Modify or remove the `Import-Module "$PSScriptRoot/../../../../build.psm1"` line + - Implement equivalent `Write-Log` and `Write-LogGroup*` functions if needed + +1. **Customize Summary Format**: + - Modify the here-string in `process-pester-results.ps1` to change summary format + - Add additional metrics or formatting as needed + +1. **Call from Your Workflows**: + + ```yaml + - name: Process Test Results + uses: "./.github/actions/test/process-pester-results" + with: + name: "my-test-run" + testResultsFolder: "path/to/results" + ``` + +## Related Documentation + +- [GitHub Actions: Creating composite actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action) +- [GitHub Actions: Job summaries](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary) +- [GitHub Actions: Uploading artifacts](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts) +- [Pester: PowerShell testing framework](https://pester.dev/) +- [NUnit XML Format](https://docs.nunit.org/articles/nunit/technical-notes/usage/Test-Result-XML-Format.html) + +## Troubleshooting + +### No Test Results Found + +- Verify `testResultsFolder` path is correct +- Ensure tests are generating NUnitXml formatted output +- Check that `*.xml` files exist in the specified folder + +### Action Fails with "GITHUB_STEP_SUMMARY is not set" + +- Ensure the action runs within a GitHub Actions environment +- Cannot be run locally without mocking this environment variable + +### All Tests Pass but Job Fails + +- Check if any tests are marked as errors (different from failures) +- Verify that at least some tests executed (`$testCaseCount -eq 0`) + +### Artifact Upload Fails + +- Check artifact name for invalid characters +- Ensure the test results folder exists +- Verify actions/upload-artifact version compatibility From af26292a7a287af9e7c9c32c8a5997c0e6ff10a6 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Tue, 21 Oct 2025 15:13:30 +1000 Subject: [PATCH 142/378] Add PSApplicationOutputEncoding variable (#21219) Adds the $PSApplicationOutputEncoding variable that can be used to control the encoding PowerShell uses when reading the raw bytes to a string of an external application. --- .../engine/InitialSessionState.cs | 8 +++ .../engine/NativeCommandProcessor.cs | 19 +++++- .../engine/SpecialVariables.cs | 5 ++ .../resources/RunspaceInit.resx | 3 + .../Basic/NativeCommandEncoding.Tests.ps1 | 62 +++++++++++++++++++ .../engine/Basic/assets/WriteConsoleOut.ps1 | 23 +++++++ 6 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 test/powershell/engine/Basic/NativeCommandEncoding.Tests.ps1 create mode 100644 test/powershell/engine/Basic/assets/WriteConsoleOut.ps1 diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 84f513d8450..ba508560ee7 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -4527,6 +4527,14 @@ static InitialSessionState() ScopedItemOptions.None, new ArgumentTypeConverterAttribute(typeof(System.Text.Encoding))), + // Variable which controls the encoding for decoding data from a NativeCommand + new SessionStateVariableEntry( + SpecialVariables.PSApplicationOutputEncoding, + null, + RunspaceInit.PSApplicationOutputEncodingDescription, + ScopedItemOptions.None, + new ArgumentTypeConverterAttribute(typeof(Encoding))), + // Preferences // // NTRAID#Windows Out Of Band Releases-931461-2006/03/13 diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 6b27c4542ab..75e3b468814 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -1645,16 +1645,17 @@ private ProcessStartInfo GetProcessStartInfo( startInfo.UseShellExecute = false; startInfo.RedirectStandardInput = redirectInput; + Encoding outputEncoding = GetOutputEncoding(); if (redirectOutput) { startInfo.RedirectStandardOutput = true; - startInfo.StandardOutputEncoding = Console.OutputEncoding; + startInfo.StandardOutputEncoding = outputEncoding; } if (redirectError) { startInfo.RedirectStandardError = true; - startInfo.StandardErrorEncoding = Console.OutputEncoding; + startInfo.StandardErrorEncoding = outputEncoding; } } @@ -1712,6 +1713,20 @@ private ProcessStartInfo GetProcessStartInfo( return startInfo; } +#nullable enable + /// + /// Gets the encoding to use for a process' output/error pipes. + /// + /// The encoding to use for the process output. + private Encoding GetOutputEncoding() + { + Encoding? applicationOutputEncoding = Context.GetVariableValue( + SpecialVariables.PSApplicationOutputEncodingVarPath) as Encoding; + + return applicationOutputEncoding ?? Console.OutputEncoding; + } +#nullable disable + /// /// Determine if we have a special file which will change the way native argument passing /// is done on Windows. We use legacy behavior for cmd.exe, .bat, .cmd files. diff --git a/src/System.Management.Automation/engine/SpecialVariables.cs b/src/System.Management.Automation/engine/SpecialVariables.cs index 7563f89a919..51419a0d5c2 100644 --- a/src/System.Management.Automation/engine/SpecialVariables.cs +++ b/src/System.Management.Automation/engine/SpecialVariables.cs @@ -41,6 +41,10 @@ internal static class SpecialVariables internal static readonly VariablePath OutputEncodingVarPath = new VariablePath(OutputEncoding); + internal const string PSApplicationOutputEncoding = nameof(PSApplicationOutputEncoding); + + internal static readonly VariablePath PSApplicationOutputEncodingVarPath = new VariablePath(PSApplicationOutputEncoding); + internal const string VerboseHelpErrors = "VerboseHelpErrors"; internal static readonly VariablePath VerboseHelpErrorsVarPath = new VariablePath(VerboseHelpErrors); @@ -388,6 +392,7 @@ internal static class SpecialVariables SpecialVariables.NestedPromptLevel, SpecialVariables.pwd, SpecialVariables.Matches, + SpecialVariables.PSApplicationOutputEncoding, }, StringComparer.OrdinalIgnoreCase ); diff --git a/src/System.Management.Automation/resources/RunspaceInit.resx b/src/System.Management.Automation/resources/RunspaceInit.resx index f12ba3f71c5..985056b69ee 100644 --- a/src/System.Management.Automation/resources/RunspaceInit.resx +++ b/src/System.Management.Automation/resources/RunspaceInit.resx @@ -153,6 +153,9 @@ The text encoding used when piping text to a native executable file + + The text encoding used when reading output text from a native executable file + Configuration controlling how text is rendered. diff --git a/test/powershell/engine/Basic/NativeCommandEncoding.Tests.ps1 b/test/powershell/engine/Basic/NativeCommandEncoding.Tests.ps1 new file mode 100644 index 00000000000..5f044d059e0 --- /dev/null +++ b/test/powershell/engine/Basic/NativeCommandEncoding.Tests.ps1 @@ -0,0 +1,62 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'Native command output encoding tests' -Tags 'CI' { + BeforeAll { + $WriteConsoleOutPath = Join-Path $PSScriptRoot assets WriteConsoleOut.ps1 + $defaultEncoding = [Console]::OutputEncoding.WebName + } + + BeforeEach { + Clear-Variable -Name PSApplicationOutputEncoding + } + + AfterEach { + Clear-Variable -Name PSApplicationOutputEncoding + } + + It 'Defaults to [Console]::OutputEncoding if not set' { + $actual = pwsh -File $WriteConsoleOutPath -Value café -Encoding $defaultEncoding + $actual | Should -Be café + } + + It 'Defaults to [Console]::OutputEncoding if set to $null' { + $PSApplicationOutputEncoding = $null + $actual = pwsh -File $WriteConsoleOutPath -Value café -Encoding $defaultEncoding + $actual | Should -Be café + } + + It 'Uses scoped $PSApplicationOutputEncoding value' { + $PSApplicationOutputEncoding = [System.Text.Encoding]::Unicode + $actual = & { + $PSApplicationOutputEncoding = [System.Text.UTF8Encoding]::new() + pwsh -File $WriteConsoleOutPath -Value café -Encoding utf-8 + } + + $actual | Should -Be café + + # Will use UTF-16-LE hence the different values + $actual = pwsh -File $WriteConsoleOutPath -Value café -Encoding Unicode + $actual | Should -Be café + } + + It 'Uses variable in class method' { + class NativeEncodingTestClass { + static [string] RunTest([string]$Script) { + $PSApplicationOutputEncoding = [System.Text.Encoding]::Unicode + return pwsh -File $Script -Value café -Encoding unicode + } + } + + $actual = [NativeEncodingTestClass]::RunTest($WriteConsoleOutPath) + $actual | Should -Be café + } + + It 'Fails to set variable with invalid encoding object' { + $ps = [PowerShell]::Create() + $ps.AddScript('$PSApplicationOutputEncoding = "utf-8"').Invoke() + + $ps.Streams.Error.Count | Should -Be 1 + [string]$ps.Streams.Error[0] | Should -Be 'Cannot convert the "utf-8" value of type "System.String" to type "System.Text.Encoding".' + } +} diff --git a/test/powershell/engine/Basic/assets/WriteConsoleOut.ps1 b/test/powershell/engine/Basic/assets/WriteConsoleOut.ps1 new file mode 100644 index 00000000000..ef82907a17f --- /dev/null +++ b/test/powershell/engine/Basic/assets/WriteConsoleOut.ps1 @@ -0,0 +1,23 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +[CmdletBinding()] +param ( + [Parameter(Mandatory)] + [string] + $Value, + + [Parameter(Mandatory)] + [string] + $Encoding +) + +$enc = [System.Text.Encoding]::GetEncoding($Encoding) +$data = $enc.GetBytes($Value) + +$outStream = [System.Console]::OpenStandardOutput() +try { + $outStream.Write($data, 0, $data.Length) +} finally { + $outStream.Dispose() +} From 770f8676d2440e7f6366c86936fc343f5c5c5968 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:41:35 -0700 Subject: [PATCH 143/378] Update concurrency groups to prevent merge runs and pull request runs from canceling each other (#26257) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 2 +- .github/workflows/macos-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 450b5f4f147..18defb738e2 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -27,7 +27,7 @@ on: # Path filters for PRs need to go into the changes job concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ contains(github.ref, 'merge')}} env: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 7ec1fc6da06..b0242a6d212 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -25,7 +25,7 @@ on: # Path filters for PRs need to go into the changes job concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ contains(github.ref, 'merge')}} env: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 37470475079..e3fbe7f7185 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -25,7 +25,7 @@ on: # Path filters for PRs need to go into the changes job concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ contains(github.ref, 'merge')}} permissions: From dbc09a1aabf1cdd5120c97de1d04069838f6c7d7 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:43:01 -0500 Subject: [PATCH 144/378] Separate Store Automation Service Endpoints, Resolve AppID (#26210) --- .pipelines/templates/package-create-msix.yml | 22 +++++++- .pipelines/templates/release-MSIX-Publish.yml | 52 ++++++++----------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index e464b612234..f45f3718b04 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -218,13 +218,31 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" name: UpdateConfigs displayName: Update PDPs and SBConfig.json - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package' + displayName: 'Create StoreBroker Package (Preview)' + condition: eq('$(PREVIEW)', 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Private' + serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 4d3e0cb41c8..1735cd9f710 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -50,7 +50,7 @@ jobs: $middleURL = $matches[1] } - $endURL = $tagString -replace '^v|\.', '' + $endURL = $tagString -replace '^v','' -replace '\.','' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -73,7 +73,6 @@ jobs: Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(STABLE), Preview: $(PREVIEW)" - # Determine the current channel for logging purposes $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -81,17 +80,30 @@ jobs: Write-Error "No valid channel detected" exit 1 } - + + # Assign AppID for Store-Publish Task + $appID = $null + if ($IsLTS) { + $appID = '$(AppID-LTS)' + } + elseif ($IsStable) { + $appID = '$(AppID-Stable)' + } + else { + $appID = '$(AppID-Preview)' + } + + Write-Host "##vso[task.setvariable variable=AppID]$appID" Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "Conditional tasks will handle the publishing based on channel variables" displayName: 'Validate Channel Selection' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish LTS StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) + displayName: 'Publish StoreBroker Package (Stable/LTS)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-LTS)' + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' @@ -100,32 +112,14 @@ jobs: targetPublishMode: 'Immediate' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Stable StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) + displayName: 'Publish StoreBroker Package (Preview)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Stable)' + serviceEndpoint: 'StoreAppPublish-Preview' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' - - - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Preview StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Preview)' - inputMethod: JsonAndZip - jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' - zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' - numberOfPackagesToKeep: 2 - jsonZipUpdateMetadata: true - targetPublishMode: 'Immediate' - - - pwsh: | - Get-Content -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue - displayName: Upload Store Failure Log - condition: failed() From eeefcd7bd6950e2812131d495adc10b0d977746f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:45:23 -0400 Subject: [PATCH 145/378] Add GitHub Copilot instruction files for PowerShell CI build system (#26253) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk --- ...ild-checkout-prerequisites.instructions.md | 148 ++++++++++++ ...build-configuration-guide.instructions.md} | 8 + .../git-requirements-for-builds.md | 71 ------ .../instruction-file-format.instructions.md | 220 ++++++++++++++++++ ...d => start-psbuild-basics.instructions.md} | 8 + ...=> troubleshooting-builds.instructions.md} | 8 + .../instructions/workflow-prerequisites.md | 91 -------- 7 files changed, 392 insertions(+), 162 deletions(-) create mode 100644 .github/instructions/build-checkout-prerequisites.instructions.md rename .github/instructions/{build-configuration-guide.md => build-configuration-guide.instructions.md} (94%) delete mode 100644 .github/instructions/git-requirements-for-builds.md create mode 100644 .github/instructions/instruction-file-format.instructions.md rename .github/instructions/{start-psbuild-basics.md => start-psbuild-basics.instructions.md} (93%) rename .github/instructions/{troubleshooting-builds.md => troubleshooting-builds.instructions.md} (94%) delete mode 100644 .github/instructions/workflow-prerequisites.md diff --git a/.github/instructions/build-checkout-prerequisites.instructions.md b/.github/instructions/build-checkout-prerequisites.instructions.md new file mode 100644 index 00000000000..717aa6faa36 --- /dev/null +++ b/.github/instructions/build-checkout-prerequisites.instructions.md @@ -0,0 +1,148 @@ +--- +applyTo: + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Build and Checkout Prerequisites for PowerShell CI + +This document describes the checkout and build prerequisites used in PowerShell's CI workflows. It is intended for GitHub Copilot sessions working with the build system. + +## Overview + +The PowerShell repository uses a standardized build process across Linux, Windows, and macOS CI workflows. Understanding the checkout configuration and the `Sync-PSTags` operation is crucial for working with the build system. + +## Checkout Configuration + +### Fetch Depth + +All CI workflows that build or test PowerShell use `fetch-depth: 1000` in the checkout step: + +```yaml +- name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1000 +``` + +**Why 1000 commits?** +- The build system needs access to Git history to determine version information +- `Sync-PSTags` requires sufficient history to fetch and work with tags +- 1000 commits provides a reasonable balance between clone speed and having enough history for version calculation +- Shallow clones (fetch-depth: 1) would break versioning logic + +**Exceptions:** +- The `changes` job uses default fetch depth (no explicit `fetch-depth`) since it only needs to detect file changes +- The `analyze` job (CodeQL) uses `fetch-depth: '0'` (full history) for comprehensive security analysis +- Linux packaging uses `fetch-depth: 0` to ensure all tags are available for package version metadata + +### Workflows Using fetch-depth: 1000 + +- **Linux CI** (`.github/workflows/linux-ci.yml`): All build and test jobs +- **Windows CI** (`.github/workflows/windows-ci.yml`): All build and test jobs +- **macOS CI** (`.github/workflows/macos-ci.yml`): All build and test jobs + +## Sync-PSTags Operation + +### What is Sync-PSTags? + +`Sync-PSTags` is a PowerShell function defined in `build.psm1` that ensures Git tags from the upstream PowerShell repository are synchronized to the local clone. + +### Location + +- **Function Definition**: `build.psm1` (line 36-76) +- **Called From**: + - `.github/actions/build/ci/action.yml` (Bootstrap step, line 24) + - `tools/ci.psm1` (Invoke-CIInstall function, line 146) + +### How It Works + +```powershell +Sync-PSTags -AddRemoteIfMissing +``` + +The function: +1. Searches for a Git remote pointing to the official PowerShell repository: + - `https://github.com/PowerShell/PowerShell` + - `git@github.com:PowerShell/PowerShell` + +2. If no upstream remote exists and `-AddRemoteIfMissing` is specified: + - Adds a remote named `upstream` pointing to `https://github.com/PowerShell/PowerShell.git` + +3. Fetches all tags from the upstream remote: + ```bash + git fetch --tags --quiet upstream + ``` + +4. Sets `$script:tagsUpToDate = $true` to indicate tags are synchronized + +### Why Sync-PSTags is Required + +Tags are critical for: +- **Version Calculation**: `Get-PSVersion` uses `git describe --abbrev=0` to find the latest tag +- **Build Numbering**: CI builds use tag-based versioning for artifacts +- **Changelog Generation**: Release notes are generated based on tags +- **Package Metadata**: Package versions are derived from Git tags + +Without synchronized tags: +- Version detection would fail or return incorrect versions +- Builds might have inconsistent version numbers +- The build process would error when trying to determine the version + +### Bootstrap Step in CI Action + +The `.github/actions/build/ci/action.yml` includes this in the Bootstrap step: + +```yaml +- name: Bootstrap + if: success() + run: |- + Write-Verbose -Verbose "Running Bootstrap..." + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + Write-Verbose -Verbose "Start Sync-PSTags" + Sync-PSTags -AddRemoteIfMissing + Write-Verbose -Verbose "End Sync-PSTags" + shell: pwsh +``` + +**Note**: `Sync-PSTags` is called twice: +1. Once by `Invoke-CIInstall` (in `tools/ci.psm1`) +2. Explicitly again in the Bootstrap step + +This redundancy ensures tags are available even if the first call encounters issues. + +## Best Practices for Copilot Sessions + +When working with the PowerShell CI system: + +1. **Always use `fetch-depth: 1000` or greater** when checking out code for build or test operations +2. **Understand that `Sync-PSTags` requires network access** to fetch tags from the upstream repository +3. **Don't modify the fetch-depth without understanding the impact** on version calculation +4. **If adding new CI workflows**, follow the existing pattern: + - Use `fetch-depth: 1000` for build/test jobs + - Call `Sync-PSTags -AddRemoteIfMissing` during bootstrap + - Ensure the upstream remote is properly configured + +5. **For local development**, developers should: + - Have the upstream remote configured + - Run `Sync-PSTags -AddRemoteIfMissing` before building + - Or use `Start-PSBuild` which handles this automatically + +## Related Files + +- `.github/actions/build/ci/action.yml` - Main CI build action +- `.github/workflows/linux-ci.yml` - Linux CI workflow +- `.github/workflows/windows-ci.yml` - Windows CI workflow +- `.github/workflows/macos-ci.yml` - macOS CI workflow +- `build.psm1` - Contains Sync-PSTags function definition +- `tools/ci.psm1` - CI-specific build functions that call Sync-PSTags + +## Summary + +The PowerShell CI system depends on: +1. **Adequate Git history** (fetch-depth: 1000) for version calculation +2. **Synchronized Git tags** via `Sync-PSTags` for accurate versioning +3. **Upstream remote access** to fetch official repository tags + +These prerequisites ensure consistent, accurate build versioning across all CI platforms. diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.instructions.md similarity index 94% rename from .github/instructions/build-configuration-guide.md rename to .github/instructions/build-configuration-guide.instructions.md index d082bcbe774..848aacef496 100644 --- a/.github/instructions/build-configuration-guide.md +++ b/.github/instructions/build-configuration-guide.instructions.md @@ -1,3 +1,11 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + # Build Configuration Guide ## Choosing the Right Configuration diff --git a/.github/instructions/git-requirements-for-builds.md b/.github/instructions/git-requirements-for-builds.md deleted file mode 100644 index 3c8cd91e7c7..00000000000 --- a/.github/instructions/git-requirements-for-builds.md +++ /dev/null @@ -1,71 +0,0 @@ -# Git Requirements for Building PowerShell - -## Fetch Depth - -**Required:** `fetch-depth: 1000` - -The PowerShell build process uses `git describe --abbrev=60 --long` to generate version information. This requires access to git history and tags. - -### Problem - -Without sufficient fetch depth, builds fail with: -``` -error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. -``` - -### Solution - -Always use `fetch-depth: 1000` in the checkout step: - -```yaml -- name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1000 -``` - -## Tag Synchronization - -**Required:** `Sync-PSTags -AddRemoteIfMissing` - -The build process needs git tags to properly version the build. - -### Problem - -Without tag synchronization: -- Version information is incorrect -- Build versioning fails - -### Solution - -Include tag synchronization in the bootstrap step: - -```yaml -- name: Bootstrap - shell: pwsh - run: | - Import-Module ./tools/ci.psm1 - Sync-PSTags -AddRemoteIfMissing -``` - -## Complete Example - -```yaml -steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1000 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - global-json-file: ./global.json - - - name: Bootstrap - shell: pwsh - run: | - Import-Module ./tools/ci.psm1 - Invoke-CIInstall -SkipUser - Sync-PSTags -AddRemoteIfMissing -``` diff --git a/.github/instructions/instruction-file-format.instructions.md b/.github/instructions/instruction-file-format.instructions.md new file mode 100644 index 00000000000..7c4e0bdd13d --- /dev/null +++ b/.github/instructions/instruction-file-format.instructions.md @@ -0,0 +1,220 @@ +--- +applyTo: + - ".github/instructions/**/*.instructions.md" +--- + +# Instruction File Format Guide + +This document describes the format and guidelines for creating custom instruction files for GitHub Copilot in the PowerShell repository. + +## File Naming Convention + +All instruction files must use the `.instructions.md` suffix: +- ✅ Correct: `build-checkout-prerequisites.instructions.md` +- ✅ Correct: `start-psbuild-basics.instructions.md` +- ❌ Incorrect: `build-guide.md` +- ❌ Incorrect: `instructions.md` + +## Required Frontmatter + +Every instruction file must start with YAML frontmatter containing an `applyTo` section: + +```yaml +--- +applyTo: + - "path/to/files/**/*.ext" + - "specific-file.ext" +--- +``` + +### applyTo Patterns + +Specify which files or directories these instructions apply to: + +**For workflow files:** +```yaml +applyTo: + - ".github/**/*.yml" + - ".github/**/*.yaml" +``` + +**For build scripts:** +```yaml +applyTo: + - "build.psm1" + - "tools/ci.psm1" +``` + +**For multiple contexts:** +```yaml +applyTo: + - "build.psm1" + - "tools/**/*.psm1" + - ".github/**/*.yml" +``` + +## Content Structure + +### 1. Clear Title + +Use a descriptive H1 heading after the frontmatter: + +```markdown +# Build Configuration Guide +``` + +### 2. Purpose or Overview + +Start with a brief explanation of what the instructions cover: + +```markdown +## Purpose + +This guide explains how to configure PowerShell builds for different scenarios. +``` + +### 3. Actionable Content + +Provide clear, actionable guidance: + +**✅ Good - Specific and actionable:** +```markdown +## Default Usage + +Use `Start-PSBuild` with no parameters for testing: + +```powershell +Import-Module ./tools/ci.psm1 +Start-PSBuild +``` +``` + +**❌ Bad - Vague and unclear:** +```markdown +## Usage + +You can use Start-PSBuild to build stuff. +``` + +### 4. Code Examples + +Include working code examples with proper syntax highlighting: + +```markdown +```yaml +- name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` +``` + +### 5. Context and Rationale + +Explain why things are done a certain way: + +```markdown +**Why fetch-depth: 1000?** +- The build system needs Git history for version calculation +- Shallow clones would break versioning logic +``` + +## Best Practices + +### Be Concise + +- Focus on essential information +- Remove redundant explanations +- Use bullet points for lists + +### Be Specific + +- Provide exact commands and parameters +- Include file paths and line numbers when relevant +- Show concrete examples, not abstract concepts + +### Avoid Duplication + +- Don't repeat information from other instruction files +- Reference other files when appropriate +- Keep each file focused on one topic + +### Use Proper Formatting + +**Headers:** +- Use H1 (`#`) for the main title +- Use H2 (`##`) for major sections +- Use H3 (`###`) for subsections + +**Code blocks:** +- Always specify the language: ` ```yaml `, ` ```powershell `, ` ```bash ` +- Keep examples short and focused +- Test examples before including them + +**Lists:** +- Use `-` for unordered lists +- Use `1.` for ordered lists +- Keep list items concise + +## Example Structure + +```markdown +--- +applyTo: + - "relevant/files/**/*.ext" +--- + +# Title of Instructions + +Brief description of what these instructions cover. + +## Section 1 + +Content with examples. + +```language +code example +``` + +## Section 2 + +More specific guidance. + +### Subsection + +Detailed information when needed. + +## Best Practices + +- Actionable tip 1 +- Actionable tip 2 +``` + +## Maintaining Instructions + +### When to Create a New File + +Create a new instruction file when: +- Covering a distinct topic not addressed elsewhere +- The content is substantial enough to warrant its own file +- The `applyTo` scope is different from existing files + +### When to Update an Existing File + +Update an existing file when: +- Information is outdated +- New best practices emerge +- Examples need correction + +### When to Merge or Delete + +Merge or delete files when: +- Content is duplicated across multiple files +- A file is too small to be useful standalone +- Information is no longer relevant + +## Reference + +For more details, see: +- [GitHub Copilot Custom Instructions Documentation](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions) diff --git a/.github/instructions/start-psbuild-basics.md b/.github/instructions/start-psbuild-basics.instructions.md similarity index 93% rename from .github/instructions/start-psbuild-basics.md rename to .github/instructions/start-psbuild-basics.instructions.md index ae216a1584d..18a0026eb2d 100644 --- a/.github/instructions/start-psbuild-basics.md +++ b/.github/instructions/start-psbuild-basics.instructions.md @@ -1,3 +1,11 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + # Start-PSBuild Basics ## Purpose diff --git a/.github/instructions/troubleshooting-builds.md b/.github/instructions/troubleshooting-builds.instructions.md similarity index 94% rename from .github/instructions/troubleshooting-builds.md rename to .github/instructions/troubleshooting-builds.instructions.md index 37f5df00912..e9b60cb8c80 100644 --- a/.github/instructions/troubleshooting-builds.md +++ b/.github/instructions/troubleshooting-builds.instructions.md @@ -1,3 +1,11 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + # Troubleshooting Build Issues ## Git Describe Error diff --git a/.github/instructions/workflow-prerequisites.md b/.github/instructions/workflow-prerequisites.md deleted file mode 100644 index fe88abb384f..00000000000 --- a/.github/instructions/workflow-prerequisites.md +++ /dev/null @@ -1,91 +0,0 @@ -# Workflow Prerequisites for Building PowerShell - -## Required Steps Before Start-PSBuild - -These steps must run before calling `Start-PSBuild`: - -### 1. Checkout - -```yaml -- name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1000 # Required for version generation -``` - -### 2. Setup .NET - -```yaml -- name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - global-json-file: ./global.json -``` - -### 3. Bootstrap - -```yaml -- name: Bootstrap - shell: pwsh - run: | - Import-Module ./tools/ci.psm1 - Invoke-CIInstall -SkipUser - Sync-PSTags -AddRemoteIfMissing -``` - -## Complete Prerequisites Example - -```yaml -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1000 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - global-json-file: ./global.json - - - name: Bootstrap - shell: pwsh - run: | - Import-Module ./tools/ci.psm1 - Invoke-CIInstall -SkipUser - Sync-PSTags -AddRemoteIfMissing - - - name: Build PowerShell - shell: pwsh - run: | - Import-Module ./tools/ci.psm1 - Start-PSBuild -``` - -## Why Each Step Matters - -**Checkout with fetch-depth:** -- Build needs git history for versioning -- Without it: `git describe` fails - -**Setup .NET:** -- Provides SDK for building -- Uses version from global.json - -**Bootstrap:** -- Installs dependencies -- Syncs git tags -- Prepares build environment - -## Optional Steps - -### Environment Capture (Debugging) - -```yaml -- name: Capture Environment - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose - shell: pwsh -``` From 67a34a888f4a3e1a3b8da4bb137130ba13793e01 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:51:01 +0000 Subject: [PATCH 146/378] Update linux.md documentation to reflect current CI build configuration (#26255) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .spelling | 1 + docs/building/linux.md | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.spelling b/.spelling index dbc54bbc393..cc711f0aa5a 100644 --- a/.spelling +++ b/.spelling @@ -622,6 +622,7 @@ NativeCommandProcessor.cs NativeCultureResolver nativeexecution net5.0 +net10.0 netcoreapp5.0 netip.ps1. netstandard.dll diff --git a/docs/building/linux.md b/docs/building/linux.md index d1ec01bd206..bd7f9aadf69 100644 --- a/docs/building/linux.md +++ b/docs/building/linux.md @@ -5,7 +5,7 @@ We'll start by showing how to set up your environment from scratch. ## Environment -These instructions are written assuming the Ubuntu 16.04 LTS, since that's the distro the team uses. +These instructions are written assuming Ubuntu 24.04 LTS (the CI uses ubuntu-latest). The build module works on a best-effort basis for other distributions. ### Git Setup @@ -41,15 +41,13 @@ In PowerShell: ```powershell Import-Module ./build.psm1 -Start-PSBootstrap +Start-PSBootstrap -Scenario Both ``` The `Start-PSBootstrap` function does the following: -- Adds the LLVM package feed -- Installs our dependencies combined with the dependencies of the .NET CLI toolchain via `apt-get` -- Uninstalls any prior versions of .NET CLI -- Downloads and installs the .NET Core SDK 2.0.0 to `~/.dotnet` +- Installs build dependencies and packaging tools via `apt-get` (or equivalent package manager) +- Downloads and installs the .NET SDK (currently version 10.0.100-rc.1) to `~/.dotnet` If you want to use `dotnet` outside of `Start-PSBuild`, add `~/.dotnet` to your `PATH` environment variable. @@ -69,7 +67,7 @@ Start-PSBuild -UseNuGetOrg Congratulations! If everything went right, PowerShell is now built. The `Start-PSBuild` script will output the location of the executable: -`./src/powershell-unix/bin/Debug/net6.0/linux-x64/publish/pwsh`. +`./src/powershell-unix/bin/Debug/net10.0/linux-x64/publish/pwsh`. You should now be running the PowerShell Core that you just built, if you run the above executable. You can run our cross-platform Pester tests with `Start-PSPester -UseNuGetOrg`, and our xUnit tests with `Start-PSxUnit`. From 0e3b4c071c84ed358d710ee1635913065ed5d58b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:01:07 -0700 Subject: [PATCH 147/378] Bump actions/setup-dotnet from 4 to 5 (#26264) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/xunit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 8bf5fd699d0..15533a2c397 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -25,7 +25,7 @@ jobs: fetch-depth: 1000 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: global-json-file: ./global.json From bedefa2733d2d527a2bb3ccbe72dece7a363b72a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:02:31 -0700 Subject: [PATCH 148/378] Bump actions/checkout from 4 to 5 (#26263) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/xunit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 15533a2c397..c80ee40d039 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -20,7 +20,7 @@ jobs: runs-on: ${{ inputs.runner_os }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1000 From c6cbd41a6abdeac40157276e756098fd064c484f Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 21 Oct 2025 13:39:12 -0700 Subject: [PATCH 149/378] Add network isolation policy parameter to vPack pipeline (#26223) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/PowerShell-vPack-Official.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 3b151127cb1..7ba92f4eda9 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -24,6 +24,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: 'Enable debug output' type: boolean default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) @@ -54,6 +62,8 @@ variables: value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual + - name: netiso + value: ${{ parameters.netiso }} # We shouldn't be using PATs anymore # - group: mscodehub-feed-read-general @@ -70,6 +80,11 @@ extends: platform: name: 'windows_undocked' # windows undocked + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + cloudvault: enabled: false From 7bcdda77e1e328658453be4df4bf12f0fe62f804 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 21 Oct 2025 13:47:59 -0700 Subject: [PATCH 150/378] Add markdown link verification for PRs (#26219) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: xtqqczze <45661989+xtqqczze@users.noreply.github.com> --- .../markdownlinks/Parse-MarkdownLink.ps1 | 182 ++++++++++ .../infrastructure/markdownlinks/README.md | 177 ++++++++++ .../markdownlinks/Verify-MarkdownLinks.ps1 | 317 ++++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 139 ++++++++ ...owershell-parameter-naming.instructions.md | 69 ++++ .github/workflows/verify-markdown-links.yml | 32 ++ 6 files changed, 916 insertions(+) create mode 100644 .github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/README.md create mode 100644 .github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/action.yml create mode 100644 .github/instructions/powershell-parameter-naming.instructions.md create mode 100644 .github/workflows/verify-markdown-links.yml diff --git a/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 new file mode 100644 index 00000000000..a56d696eb6e --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 @@ -0,0 +1,182 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#requires -version 7 +# Markdig is always available in PowerShell 7 +<# +.SYNOPSIS + Parse CHANGELOG files using Markdig to extract links. + +.DESCRIPTION + This script uses Markdig.Markdown.Parse to parse all markdown files in the CHANGELOG directory + and extract different types of links (inline links, reference links, etc.). + +.PARAMETER ChangelogPath + Path to the CHANGELOG directory. Defaults to ./CHANGELOG + +.PARAMETER LinkType + Filter by link type: All, Inline, Reference, AutoLink. Defaults to All. + +.EXAMPLE + .\Parse-MarkdownLink.ps1 + +.EXAMPLE + .\Parse-MarkdownLink.ps1 -LinkType Reference +#> + +param( + [string]$ChangelogPath = "./CHANGELOG", + [ValidateSet("All", "Inline", "Reference", "AutoLink")] + [string]$LinkType = "All" +) + +Write-Verbose "Using built-in Markdig functionality to parse markdown files" + +function Get-LinksFromMarkdownAst { + param( + [Parameter(Mandatory)] + [object]$Node, + [Parameter(Mandatory)] + [string]$FileName, + [System.Collections.ArrayList]$Links + ) + + if ($null -eq $Links) { + return + } + + # Check if current node is a link + if ($Node -is [Markdig.Syntax.Inlines.LinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 # Convert to 1-based line numbering + Column = $Node.Column + 1 # Convert to 1-based column numbering + Url = $Node.Url ?? "" + Text = $Node.FirstChild?.ToString() ?? "" + Type = "Inline" + IsImage = $Node.IsImage + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.Inlines.AutolinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Url ?? "" + Type = "AutoLink" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinitionGroup]) { + foreach ($refDef in $Node) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $refDef.Line + 1 + Column = $refDef.Column + 1 + Url = $refDef.Url ?? "" + Text = $refDef.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinition]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + + # For MarkdownDocument (root), iterate through all blocks + if ($Node -is [Markdig.Syntax.MarkdownDocument]) { + foreach ($block in $Node) { + Get-LinksFromMarkdownAst -Node $block -FileName $FileName -Links $Links + } + } + # For block containers, iterate through children + elseif ($Node -is [Markdig.Syntax.ContainerBlock]) { + foreach ($child in $Node) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + } + } + # For leaf blocks with inlines, process the inline content + elseif ($Node -is [Markdig.Syntax.LeafBlock] -and $Node.Inline) { + Get-LinksFromMarkdownAst -Node $Node.Inline -FileName $FileName -Links $Links + } + # For inline containers, process all child inlines + elseif ($Node -is [Markdig.Syntax.Inlines.ContainerInline]) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } + # For other inline elements that might have children + elseif ($Node.PSObject.Properties.Name -contains "FirstChild" -and $Node.FirstChild) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } +} + +function Parse-ChangelogFiles { + param( + [string]$Path + ) + + if (-not (Test-Path $Path)) { + Write-Error "CHANGELOG directory not found: $Path" + return + } + + $markdownFiles = Get-ChildItem -Path $Path -Filter "*.md" -File + + if ($markdownFiles.Count -eq 0) { + Write-Warning "No markdown files found in $Path" + return + } + + $allLinks = [System.Collections.ArrayList]::new() + + foreach ($file in $markdownFiles) { + Write-Verbose "Processing file: $($file.Name)" + + try { + $content = Get-Content -Path $file.FullName -Raw -Encoding UTF8 + + # Parse the markdown content using Markdig + $document = [Markdig.Markdown]::Parse($content, [Markdig.MarkdownPipelineBuilder]::new()) + + # Extract links from the AST + Get-LinksFromMarkdownAst -Node $document -FileName $file.FullName -Links $allLinks + + } catch { + Write-Warning "Error processing file $($file.Name): $($_.Exception.Message)" + } + } + + # Filter by link type if specified + if ($LinkType -ne "All") { + $allLinks = $allLinks | Where-Object { $_.Type -eq $LinkType } + } + + return $allLinks +} + +# Main execution +$links = Parse-ChangelogFiles -Path $ChangelogPath + +# Output PowerShell objects +$links diff --git a/.github/actions/infrastructure/markdownlinks/README.md b/.github/actions/infrastructure/markdownlinks/README.md new file mode 100644 index 00000000000..e566ec2bcc3 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/README.md @@ -0,0 +1,177 @@ +# Verify Markdown Links Action + +A GitHub composite action that verifies all links in markdown files using PowerShell and Markdig. + +## Features + +- ✅ Parses markdown files using Markdig (built into PowerShell 7) +- ✅ Extracts all link types: inline links, reference links, and autolinks +- ✅ Verifies HTTP/HTTPS links with configurable timeouts and retries +- ✅ Validates local file references +- ✅ Supports excluding specific URL patterns +- ✅ Provides detailed error reporting with file locations +- ✅ Outputs metrics for CI/CD integration + +## Usage + +### Basic Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' +``` + +### Advanced Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'true' + timeout: 30 + max-retries: 2 + exclude-patterns: '*.example.com/*,*://localhost/*' +``` + +### With Outputs + +```yaml +- name: Verify Markdown Links + id: verify-links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'false' + +- name: Display Results + run: | + echo "Total links: ${{ steps.verify-links.outputs.total-links }}" + echo "Passed: ${{ steps.verify-links.outputs.passed-links }}" + echo "Failed: ${{ steps.verify-links.outputs.failed-links }}" + echo "Skipped: ${{ steps.verify-links.outputs.skipped-links }}" +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `path` | Path to the directory containing markdown files to verify | No | `./CHANGELOG` | +| `exclude-patterns` | Comma-separated list of URL patterns to exclude from verification | No | `''` | +| `fail-on-error` | Whether to fail the action if any links are broken | No | `true` | +| `timeout` | Timeout in seconds for HTTP requests | No | `30` | +| `max-retries` | Maximum number of retries for failed requests | No | `2` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `total-links` | Total number of unique links checked | +| `passed-links` | Number of links that passed verification | +| `failed-links` | Number of links that failed verification | +| `skipped-links` | Number of links that were skipped | + +## Excluded Link Types + +The action automatically skips the following link types: + +- **Anchor links** (`#section-name`) - Would require full markdown parsing +- **Email links** (`mailto:user@example.com`) - Cannot be verified without sending email + +## GitHub Workflow Test + +This section provides a workflow example and instructions for testing the link verification action. + +### Testing the Workflow + +To test that the workflow properly detects broken links: + +1. Make change to this file (e.g., this README.md file already contains one in the [Broken Link Test](#broken-link-test) section) +1. The workflow will run and should fail, reporting the broken link(s) +1. Revert your change to this file +1. Push again to verify the workflow passes + +### Example Workflow Configuration + +```yaml +name: Verify Links + +on: + push: + branches: [ main ] + paths: + - '**/*.md' + pull_request: + branches: [ main ] + paths: + - '**/*.md' + schedule: + # Run weekly to catch external link rot + - cron: '0 0 * * 0' + +jobs: + verify-links: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Verify CHANGELOG Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'true' + + - name: Verify Documentation Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'false' + exclude-patterns: '*.internal.example.com/*' +``` + +## How It Works + +1. **Parse Markdown**: Uses `Parse-MarkdownLink.ps1` to extract all links from markdown files using Markdig +2. **Deduplicate**: Groups links by URL to avoid checking the same link multiple times +3. **Verify Links**: + - HTTP/HTTPS links: Makes HEAD/GET requests with configurable timeout and retries + - Local file references: Checks if the file exists relative to the markdown file + - Excluded patterns: Skips links matching the exclude patterns +4. **Report Results**: Displays detailed results with file locations for failed links +5. **Set Outputs**: Provides metrics for downstream steps + +## Error Output Example + +``` +✗ FAILED: https://example.com/broken-link - HTTP 404 + Found in: /path/to/file.md:42:15 + Found in: /path/to/other.md:100:20 + +Link Verification Summary +============================================================ +Total URLs checked: 150 +Passed: 145 +Failed: 2 +Skipped: 3 + +Failed Links: + • https://example.com/broken-link + Error: HTTP 404 + Occurrences: 2 +``` + +## Requirements + +- PowerShell 7+ (includes Markdig) +- Runs on: `ubuntu-latest`, `windows-latest`, `macos-latest` + +## Broken Link Test + +- [Broken Link](https://github.com/PowerShell/PowerShell/wiki/NonExistentPage404) + +## License + +Same as the PowerShell repository. diff --git a/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 new file mode 100644 index 00000000000..f50ab1590b9 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 @@ -0,0 +1,317 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#Requires -Version 7.0 + +<# +.SYNOPSIS + Verify all links in markdown files. + +.DESCRIPTION + This script parses markdown files to extract links and verifies their accessibility. + It supports HTTP/HTTPS links and local file references. + +.PARAMETER Path + Path to the directory containing markdown files. Defaults to current directory. + +.PARAMETER File + Array of specific markdown files to verify. If provided, Path parameter is ignored. + +.PARAMETER TimeoutSec + Timeout in seconds for HTTP requests. Defaults to 30. + +.PARAMETER MaximumRetryCount + Maximum number of retries for failed requests. Defaults to 2. + +.PARAMETER RetryIntervalSec + Interval in seconds between retry attempts. Defaults to 2. + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./CHANGELOG + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./docs -FailOnError + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -File @('CHANGELOG/7.5.md', 'README.md') +#> + +param( + [Parameter(ParameterSetName = 'ByPath', Mandatory)] + [string]$Path = "Q:\src\git\powershell\docs\git", + [Parameter(ParameterSetName = 'ByFile', Mandatory)] + [string[]]$File = @(), + [int]$TimeoutSec = 30, + [int]$MaximumRetryCount = 2, + [int]$RetryIntervalSec = 2 +) + +$ErrorActionPreference = 'Stop' + +# Get the script directory +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +# Determine what to process: specific files or directory +if ($File.Count -gt 0) { + Write-Host "Extracting links from $($File.Count) specified markdown file(s)" -ForegroundColor Cyan + + # Process each file individually + $allLinks = @() + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + + foreach ($filePath in $File) { + if (Test-Path $filePath) { + Write-Verbose "Processing: $filePath" + $fileLinks = & $parseScriptPath -ChangelogPath $filePath + $allLinks += $fileLinks + } + else { + Write-Warning "File not found: $filePath" + } + } +} +else { + Write-Host "Extracting links from markdown files in: $Path" -ForegroundColor Cyan + + # Get all links from markdown files using the Parse-ChangelogLinks script + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + $allLinks = & $parseScriptPath -ChangelogPath $Path +} + +if ($allLinks.Count -eq 0) { + Write-Host "No links found in markdown files." -ForegroundColor Yellow + exit 0 +} + +Write-Host "Found $($allLinks.Count) links to verify" -ForegroundColor Green + +# Group links by URL to avoid duplicate checks +$uniqueLinks = $allLinks | Group-Object -Property Url + +Write-Host "Unique URLs to verify: $($uniqueLinks.Count)" -ForegroundColor Cyan + +$results = @{ + Total = $uniqueLinks.Count + Passed = 0 + Failed = 0 + Skipped = 0 + Errors = [System.Collections.ArrayList]::new() +} + +function Test-HttpLink { + param( + [string]$Url + ) + + try { + # Try HEAD request first (faster, doesn't download content) + $response = Invoke-WebRequest -Uri $Url ` + -Method Head ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com/PowerShell/PowerShell)" ` + -SkipHttpErrorCheck + + # If HEAD fails with 404 or 405, retry with GET (some servers don't support HEAD) + if ($response.StatusCode -eq 404 -or $response.StatusCode -eq 405) { + Write-Verbose "HEAD request failed with $($response.StatusCode), retrying with GET for: $Url" + $response = Invoke-WebRequest -Uri $Url ` + -Method Get ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com)" ` + -SkipHttpErrorCheck + } + + if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 400) { + return @{ Success = $true; StatusCode = $response.StatusCode } + } + else { + return @{ Success = $false; StatusCode = $response.StatusCode; Error = "HTTP $($response.StatusCode)" } + } + } + catch { + return @{ Success = $false; StatusCode = 0; Error = $_.Exception.Message } + } +} + +function Test-LocalLink { + param( + [string]$Url, + [string]$BasePath + ) + + # Strip query parameters (e.g., ?sanitize=true) and anchors (e.g., #section) + $cleanUrl = $Url -replace '\?.*$', '' -replace '#.*$', '' + + # Handle relative paths + $targetPath = Join-Path $BasePath $cleanUrl + + if (Test-Path $targetPath) { + return @{ Success = $true } + } + else { + return @{ Success = $false; Error = "File not found: $targetPath" } + } +} + +# Verify each unique link +$progressCount = 0 +foreach ($linkGroup in $uniqueLinks) { + $progressCount++ + $url = $linkGroup.Name + $occurrences = $linkGroup.Group + Write-Verbose -Verbose "[$progressCount/$($uniqueLinks.Count)] Checking: $url" + + # Determine link type and verify + $verifyResult = $null + if ($url -match '^https?://') { + $verifyResult = Test-HttpLink -Url $url + } + elseif ($url -match '^#') { + Write-Verbose -Verbose "Skipping anchor link: $url" + $results.Skipped++ + continue + } + elseif ($url -match '^mailto:') { + Write-Verbose -Verbose "Skipping mailto link: $url" + $results.Skipped++ + continue + } + else { + $basePath = Split-Path -Parent $occurrences[0].Path + $verifyResult = Test-LocalLink -Url $url -BasePath $basePath + } + if ($verifyResult.Success) { + Write-Host "✓ OK: $url" -ForegroundColor Green + $results.Passed++ + } + else { + $errorMsg = if ($verifyResult.StatusCode) { + "HTTP $($verifyResult.StatusCode)" + } + else { + $verifyResult.Error + } + + # Determine if this status code should be ignored or treated as failure + # Ignore: 401 (Unauthorized), 403 (Forbidden), 429 (Too Many Requests - already retried) + # Fail: 404 (Not Found), 410 (Gone), 406 (Not Acceptable) - these indicate broken links + $shouldIgnore = $false + $ignoreReason = "" + + switch ($verifyResult.StatusCode) { + 401 { + $shouldIgnore = $true + $ignoreReason = "authentication required" + } + 403 { + $shouldIgnore = $true + $ignoreReason = "access forbidden" + } + 429 { + $shouldIgnore = $true + $ignoreReason = "rate limited (already retried)" + } + } + + if ($shouldIgnore) { + Write-Host "⊘ IGNORED: $url - $errorMsg ($ignoreReason)" -ForegroundColor Yellow + Write-Verbose -Verbose "Ignored error details for $url - Status: $($verifyResult.StatusCode) - $ignoreReason" + foreach ($occurrence in $occurrences) { + Write-Verbose -Verbose " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" + } + $results.Skipped++ + } + else { + Write-Host "✗ FAILED: $url - $errorMsg" -ForegroundColor Red + foreach ($occurrence in $occurrences) { + Write-Host " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" -ForegroundColor DarkGray + } + $results.Failed++ + [void]$results.Errors.Add(@{ + Url = $url + Error = $errorMsg + Occurrences = $occurrences + }) + } + } + } + +# Print summary +Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan +Write-Host "Link Verification Summary" -ForegroundColor Cyan +Write-Host ("=" * 60) -ForegroundColor Cyan +Write-Host "Total URLs checked: $($results.Total)" -ForegroundColor White +Write-Host "Passed: $($results.Passed)" -ForegroundColor Green +Write-Host "Failed: $($results.Failed)" -ForegroundColor $(if ($results.Failed -gt 0) { "Red" } else { "Green" }) +Write-Host "Skipped: $($results.Skipped)" -ForegroundColor Gray + +if ($results.Failed -gt 0) { + Write-Host "`nFailed Links:" -ForegroundColor Red + foreach ($failedLink in $results.Errors) { + Write-Host " • $($failedLink.Url)" -ForegroundColor Red + Write-Host " Error: $($failedLink.Error)" -ForegroundColor DarkGray + Write-Host " Occurrences: $($failedLink.Occurrences.Count)" -ForegroundColor DarkGray + } + + Write-Host "`n❌ Link verification failed!" -ForegroundColor Red + exit 1 +} +else { + Write-Host "`n✅ All links verified successfully!" -ForegroundColor Green +} + +# Write to GitHub Actions step summary if running in a workflow +if ($env:GITHUB_STEP_SUMMARY) { + $summaryContent = @" + +# Markdown Link Verification Results + +## Summary +- **Total URLs checked:** $($results.Total) +- **Passed:** ✅ $($results.Passed) +- **Failed:** $(if ($results.Failed -gt 0) { "❌" } else { "✅" }) $($results.Failed) +- **Skipped:** $($results.Skipped) + +"@ + + if ($results.Failed -gt 0) { + $summaryContent += @" + +## Failed Links + +| URL | Error | Occurrences | +|-----|-------|-------------| + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "| $($failedLink.Url) | $($failedLink.Error) | $($failedLink.Occurrences.Count) |`n" + } + + $summaryContent += @" + +
    +Click to see all failed link locations + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "`n### $($failedLink.Url)`n" + $summaryContent += "**Error:** $($failedLink.Error)`n`n" + foreach ($occurrence in $failedLink.Occurrences) { + $summaryContent += "- `$($occurrence.Path):$($occurrence.Line):$($occurrence.Column)`n" + } + } + $summaryContent += "`n
    `n" + } + else { + $summaryContent += "`n## ✅ All links verified successfully!`n" + } + + Write-Verbose -Verbose "Writing `n $summaryContent `n to ${env:GITHUB_STEP_SUMMARY}" + $summaryContent | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append + Write-Verbose -Verbose "Summary written to GitHub Actions step summary" +} + diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml new file mode 100644 index 00000000000..1d6d0864784 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -0,0 +1,139 @@ +name: 'Verify Markdown Links' +description: 'Verify all links in markdown files using PowerShell and Markdig' +author: 'PowerShell Team' + +inputs: + timeout-sec: + description: 'Timeout in seconds for HTTP requests' + required: false + default: '30' + maximum-retry-count: + description: 'Maximum number of retries for failed requests' + required: false + default: '2' + +outputs: + total-links: + description: 'Total number of unique links checked' + value: ${{ steps.verify.outputs.total }} + passed-links: + description: 'Number of links that passed verification' + value: ${{ steps.verify.outputs.passed }} + failed-links: + description: 'Number of links that failed verification' + value: ${{ steps.verify.outputs.failed }} + skipped-links: + description: 'Number of links that were skipped' + value: ${{ steps.verify.outputs.skipped }} + +runs: + using: 'composite' + steps: + - name: Get changed markdown files + id: changed-files + uses: actions/github-script@v7 + with: + script: | + let changedMarkdownFiles = []; + + if (context.eventName === 'pull_request') { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + + changedMarkdownFiles = files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else if (context.eventName === 'push') { + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedMarkdownFiles = comparison.files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); + return; + } + + console.log('Changed markdown files:', changedMarkdownFiles); + core.setOutput('files', JSON.stringify(changedMarkdownFiles)); + core.setOutput('count', changedMarkdownFiles.length); + return changedMarkdownFiles; + + - name: Verify markdown links + id: verify + shell: pwsh + run: | + Write-Host "Starting markdown link verification..." -ForegroundColor Cyan + + # Get changed markdown files from previous step + $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + $changedFiles = $changedFilesJson | ConvertFrom-Json + + if ($changedFiles.Count -eq 0) { + Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow + "total=0" >> $env:GITHUB_OUTPUT + "passed=0" >> $env:GITHUB_OUTPUT + "failed=0" >> $env:GITHUB_OUTPUT + "skipped=0" >> $env:GITHUB_OUTPUT + exit 0 + } + + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan + $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } + + # Build parameters for each file + $params = @{ + File = $changedFiles + TimeoutSec = [int]'${{ inputs.timeout-sec }}' + MaximumRetryCount = [int]'${{ inputs.maximum-retry-count }}' + } + + # Run the verification script + $scriptPath = Join-Path '${{ github.action_path }}' 'Verify-MarkdownLinks.ps1' + + # Capture output and parse results + $output = & $scriptPath @params 2>&1 | Tee-Object -Variable capturedOutput + + # Try to extract metrics from output + $totalLinks = 0 + $passedLinks = 0 + $failedLinks = 0 + $skippedLinks = 0 + + foreach ($line in $capturedOutput) { + if ($line -match 'Total URLs checked: (\d+)') { + $totalLinks = $Matches[1] + } + elseif ($line -match 'Passed: (\d+)') { + $passedLinks = $Matches[1] + } + elseif ($line -match 'Failed: (\d+)') { + $failedLinks = $Matches[1] + } + elseif ($line -match 'Skipped: (\d+)') { + $skippedLinks = $Matches[1] + } + } + + # Set outputs + "total=$totalLinks" >> $env:GITHUB_OUTPUT + "passed=$passedLinks" >> $env:GITHUB_OUTPUT + "failed=$failedLinks" >> $env:GITHUB_OUTPUT + "skipped=$skippedLinks" >> $env:GITHUB_OUTPUT + + Write-Host "Action completed" -ForegroundColor Cyan + + # Exit with the same code as the verification script + exit $LASTEXITCODE + +branding: + icon: 'link' + color: 'blue' diff --git a/.github/instructions/powershell-parameter-naming.instructions.md b/.github/instructions/powershell-parameter-naming.instructions.md new file mode 100644 index 00000000000..155fd1a85c3 --- /dev/null +++ b/.github/instructions/powershell-parameter-naming.instructions.md @@ -0,0 +1,69 @@ +--- +applyTo: '**/*.ps1, **/*.psm1' +description: Naming conventions for PowerShell parameters +--- + +# PowerShell Parameter Naming Conventions + +## Purpose + +This instruction defines the naming conventions for parameters in PowerShell scripts and modules. Consistent parameter naming improves code readability, maintainability, and usability for users of PowerShell cmdlets and functions. + +## Parameter Naming Rules + +### General Conventions +- **Singular Nouns**: Use singular nouns for parameter names even if the parameter is expected to handle multiple values (e.g., `File` instead of `Files`). +- **Use PascalCase**: Parameter names must use PascalCase (e.g., `ParameterName`). +- **Descriptive Names**: Parameter names should be descriptive and convey their purpose clearly (e.g., `FilePath`, `UserName`). +- **Avoid Abbreviations**: Avoid using abbreviations unless they are widely recognized (e.g., `ID` for Identifier). +- **Avoid Reserved Words**: Do not use PowerShell reserved words as parameter names (e.g., `if`, `else`, `function`). + +### Units and Precision +- **Include Units in Parameter Names**: When a parameter represents a value with units, include the unit in the parameter name for clarity: + - `TimeoutSec` instead of `Timeout` + - `RetryIntervalSec` instead of `RetryInterval` + - `MaxSizeBytes` instead of `MaxSize` +- **Use Full Words for Clarity**: Spell out common terms to match PowerShell conventions: + - `MaximumRetryCount` instead of `MaxRetries` + - `MinimumLength` instead of `MinLength` + +### Alignment with Built-in Cmdlets +- **Follow Existing PowerShell Conventions**: When your parameter serves a similar purpose to a built-in cmdlet parameter, use the same or similar naming: + - Match `Invoke-WebRequest` parameters when making HTTP requests: `TimeoutSec`, `MaximumRetryCount`, `RetryIntervalSec` + - Follow common parameter patterns like `Path`, `Force`, `Recurse`, `WhatIf`, `Confirm` +- **Consistency Within Scripts**: If multiple parameters relate to the same concept, use consistent naming patterns (e.g., `TimeoutSec`, `RetryIntervalSec` both use `Sec` suffix). + +## Examples + +### Good Parameter Names +```powershell +param( + [string[]]$File, # Singular, even though it accepts arrays + [int]$TimeoutSec = 30, # Unit included + [int]$MaximumRetryCount = 2, # Full word "Maximum" + [int]$RetryIntervalSec = 2, # Consistent with TimeoutSec + [string]$Path, # Standard PowerShell convention + [switch]$Force # Common PowerShell parameter +) +``` + +### Names to Avoid +```powershell +param( + [string[]]$Files, # Should be singular: File + [int]$Timeout = 30, # Missing unit: TimeoutSec + [int]$MaxRetries = 2, # Should be: MaximumRetryCount + [int]$RetryInterval = 2, # Missing unit: RetryIntervalSec + [string]$FileLoc, # Avoid abbreviations: FilePath + [int]$Max # Ambiguous: MaximumWhat? +) +``` + +## Exceptions +- **Common Terms**: Some common terms may be used in plural form if they are widely accepted in the context (e.g., `Credentials`, `Permissions`). +- **Legacy Code**: Existing code that does not follow these conventions may be exempted to avoid breaking changes, but new code should adhere to these guidelines. +- **Well Established Naming Patterns**: If a naming pattern is well established in the PowerShell community, it may be used even if it does not strictly adhere to these guidelines. + +## References +- [PowerShell Cmdlet Design Guidelines](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) +- [About Parameters - PowerShell Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_parameters) diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml new file mode 100644 index 00000000000..db9fb7e416a --- /dev/null +++ b/.github/workflows/verify-markdown-links.yml @@ -0,0 +1,32 @@ +name: Verify Markdown Links + +on: + push: + branches: [ main, master ] + paths: + - '**/*.md' + - '.github/workflows/verify-markdown-links.yml' + - '.github/actions/infrastructure/markdownlinks/**' + pull_request: + branches: [ main, master ] + paths: + - '**/*.md' + schedule: + # Run weekly on Sundays at midnight UTC to catch external link rot + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + verify-markdown-links: + name: Verify Markdown Links + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Verify markdown links + id: verify + uses: ./.github/actions/infrastructure/markdownlinks + with: + timeout-sec: 30 + maximum-retry-count: 2 From c7ee0d2941884ce4437c7913ef64c56b37654454 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Wed, 22 Oct 2025 11:55:23 -0400 Subject: [PATCH 151/378] Fix checks for local user config file paths (#26269) --- .../host/msh/ConsoleHost.cs | 13 +- .../host/msh/UpdatesNotification.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 46 +- .../engine/CommandDiscovery.cs | 10 +- .../engine/Modules/AnalysisCache.cs | 7 +- .../engine/PSConfiguration.cs | 10 +- .../engine/hostifaces/HostUtilities.cs | 9 +- .../engine/hostifaces/MshHostUserInterface.cs | 5 + .../utils/Telemetry.cs | 927 +++++++++--------- 9 files changed, 552 insertions(+), 479 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index b866815a25c..7228cb31ee2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -148,13 +148,16 @@ internal static int Start( try { string profileDir = Platform.CacheDirectory; -#if !UNIX - if (!Directory.Exists(profileDir)) + if (!string.IsNullOrEmpty(profileDir)) { - Directory.CreateDirectory(profileDir); - } +#if !UNIX + if (!Directory.Exists(profileDir)) + { + Directory.CreateDirectory(profileDir); + } #endif - ProfileOptimization.SetProfileRoot(profileDir); + ProfileOptimization.SetProfileRoot(profileDir); + } } catch { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index 28cd31473dd..b7c001db710 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -57,12 +57,12 @@ internal static class UpdatesNotification static UpdatesNotification() { s_notificationType = GetNotificationType(); - CanNotifyUpdates = s_notificationType != NotificationType.Off; + CanNotifyUpdates = s_notificationType != NotificationType.Off + && Platform.TryDeriveFromCache(PSVersionInfo.GitCommitId, out s_cacheDirectory); if (CanNotifyUpdates) { s_enumOptions = new EnumerationOptions(); - s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId); // Build the template/pattern strings for the configured notification type. string typeNum = ((int)s_notificationType).ToString(); diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index f4a7622b66f..8be65502543 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -167,8 +167,13 @@ public static bool IsStaSupported internal static readonly string ConfigDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CONFIG); #else // Gets the location for cache and config folders. - internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; - internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; + internal static readonly string CacheDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.LocalApplicationData, + @"Microsoft\PowerShell"); + + internal static readonly string ConfigDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.Personal, + @"PowerShell"); private static readonly Lazy _isStaSupported = new Lazy(() => { @@ -189,6 +194,30 @@ public static bool IsStaSupported private static bool? _isWindowsDesktop = null; #endif + internal static bool TryDeriveFromCache(string path1, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1); + return true; + } + + internal static bool TryDeriveFromCache(string path1, string path2, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1, path2); + return true; + } + // format files internal static readonly string[] FormatFileNames = new string[] { @@ -218,6 +247,17 @@ internal static class CommonEnvVariableNames #endif } + private static string SafeDeriveFromSpecialFolder(Environment.SpecialFolder specialFolder, string subPath) + { + string basePath = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.DoNotVerify); + if (string.IsNullOrWhiteSpace(basePath)) + { + return string.Empty; + } + + return Path.Join(basePath, subPath); + } + #if UNIX private static string s_tempHome = null; @@ -360,7 +400,7 @@ internal static string GetFolderPath(Environment.SpecialFolder folder) _ => throw new NotSupportedException() }; #else - return Environment.GetFolderPath(folder); + return Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify); #endif } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index cf4f561c983..9ca87f4c834 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1231,11 +1231,17 @@ internal LookupPathCollection GetLookupDirectoryPaths() string tempDir = directory.TrimStart(); if (tempDir.EqualsOrdinalIgnoreCase("~")) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify); } else if (tempDir.StartsWith("~" + Path.DirectorySeparatorChar)) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar + tempDir.Substring(2); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify) + + Path.DirectorySeparatorChar + + tempDir.Substring(2); } _cachedPath.Add(tempDir); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 79085041abd..8a5f29e2b16 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -664,6 +664,11 @@ private static byte[] GetHeader() public void QueueSerialization() { + if (string.IsNullOrEmpty(s_cacheStoreLocation)) + { + return; + } + // We expect many modules to rapidly call for serialization. // Instead of doing it right away, we'll queue a task that starts writing // after it seems like we've stopped adding stuff to write out. This is @@ -1121,7 +1126,7 @@ static AnalysisCacheData() cacheFileName = string.Create(CultureInfo.InvariantCulture, $"{cacheFileName}-{hashString}"); } - s_cacheStoreLocation = Path.Combine(Platform.CacheDirectory, cacheFileName); + Platform.TryDeriveFromCache(cacheFileName, out s_cacheStoreLocation); } } diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs index e321423f768..419a4cae95f 100644 --- a/src/System.Management.Automation/engine/PSConfiguration.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -89,7 +89,10 @@ private PowerShellConfig() // Note: This directory may or may not exist depending upon the execution scenario. // Writes will attempt to create the directory if it does not already exist. perUserConfigDirectory = Platform.ConfigDirectory; - perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + if (!string.IsNullOrEmpty(perUserConfigDirectory)) + { + perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + } emptyConfig = new JObject(); configRoots = new JObject[2]; @@ -387,6 +390,11 @@ internal PSKeyword GetLogKeywords() private T ReadValueFromFile(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); + if (string.IsNullOrEmpty(fileName)) + { + return defaultValue; + } + JObject configData = configRoots[(int)scope]; if (configData == null) diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index ba71fef0443..7c8ccd0d307 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -208,10 +208,11 @@ internal static string GetFullProfileFileName(string shellId, bool forCurrentUse else { basePath = GetAllUsersFolderPath(shellId); - if (string.IsNullOrEmpty(basePath)) - { - return string.Empty; - } + } + + if (string.IsNullOrEmpty(basePath)) + { + return string.Empty; } string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1"; diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 29fc5fa1f7f..5f51ba15751 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -1156,6 +1156,11 @@ internal static string GetTranscriptPath(string baseDirectory, bool includeDate) } } + if (string.IsNullOrEmpty(baseDirectory)) + { + return string.Empty; + } + if (includeDate) { baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture)); diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 5cd728e6c55..f72ac4eade4 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -163,6 +163,8 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet s_knownSubsystemNames; + private static readonly string s_uuidPath; + /// Gets a value indicating whether telemetry can be sent. public static bool CanSendTelemetry { get; private set; } = false; @@ -176,470 +178,474 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); - if (CanSendTelemetry) + CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) + && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); + + if (!CanSendTelemetry) { - s_sessionId = Guid.NewGuid().ToString(); - TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); - configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; + return; + } - // Set this to true to reduce latency during development - configuration.TelemetryChannel.DeveloperMode = false; + s_sessionId = Guid.NewGuid().ToString(); + TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); + configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; - // Be sure to obscure any information about the client node name. - configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); + // Set this to true to reduce latency during development + configuration.TelemetryChannel.DeveloperMode = false; - s_telemetryClient = new TelemetryClient(configuration); + // Be sure to obscure any information about the client node name. + configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModules = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "AADRM", - "activedirectory", - "adcsadministration", - "adcsdeployment", - "addsadministration", - "addsdeployment", - "adfs", - "adrms", - "adrmsadmin", - "agpm", - "AIShell", - "appbackgroundtask", - "applocker", - "appv", - "appvclient", - "appvsequencer", - "appvserver", - "appx", - "assignedaccess", - "Az", - "Az.Accounts", - "Az.Advisor", - "Az.Aks", - "Az.AlertsManagement", - "Az.AnalysisServices", - "Az.ApiManagement", - "Az.ApplicationInsights", - "Az.Attestation", - "Az.Automation", - "Az.Batch", - "Az.Billing", - "Az.Blueprint", - "Az.Cdn", - "Az.CognitiveServices", - "Az.Compute", - "Az.ContainerInstance", - "Az.ContainerRegistry", - "Az.DataBox", - "Az.DataFactory", - "Az.DataLakeAnalytics", - "Az.DataLakeStore", - "Az.DataMigration", - "Az.DataShare", - "Az.DeploymentManager", - "Az.DeviceProvisioningServices", - "Az.DevSpaces", - "Az.DevTestLabs", - "Az.Dns", - "Az.EventGrid", - "Az.EventHub", - "Az.FrontDoor", - "Az.GuestConfiguration", - "Az.HDInsight", - "Az.HealthcareApis", - "Az.IotCentral", - "Az.IotHub", - "Az.KeyVault", - "Az.Kusto", - "Az.LogicApp", - "Az.MachineLearning", - "Az.ManagedServiceIdentity", - "Az.ManagedServices", - "Az.ManagementPartner", - "Az.Maps", - "Az.MarketplaceOrdering", - "Az.Media", - "Az.MixedReality", - "Az.Monitor", - "Az.NetAppFiles", - "Az.Network", - "Az.NotificationHubs", - "Az.OperationalInsights", - "Az.Peering", - "Az.PolicyInsights", - "Az.PowerBIEmbedded", - "Az.PrivateDns", - "Az.RecoveryServices", - "Az.RedisCache", - "Az.Relay", - "Az.Reservations", - "Az.ResourceGraph", - "Az.Resources", - "Az.Search", - "Az.Security", - "Az.ServiceBus", - "Az.ServiceFabric", - "Az.SignalR", - "Az.Sql", - "Az.Storage", - "Az.StorageSync", - "Az.StorageTable", - "Az.StreamAnalytics", - "Az.Subscription", - "Az.Tools.Predictor", - "Az.TrafficManager", - "Az.Websites", - "Azs.Azurebridge.Admin", - "Azs.Backup.Admin", - "Azs.Commerce.Admin", - "Azs.Compute.Admin", - "Azs.Fabric.Admin", - "Azs.Gallery.Admin", - "Azs.Infrastructureinsights.Admin", - "Azs.Keyvault.Admin", - "Azs.Network.Admin", - "Azs.Storage.Admin", - "Azs.Subscriptions", - "Azs.Subscriptions.Admin", - "Azs.Update.Admin", - "AzStorageTable", - "Azure", - "Azure.AnalysisServices", - "Azure.Storage", - "AzureAD", - "AzureInformationProtection", - "AzureRM.Aks", - "AzureRM.AnalysisServices", - "AzureRM.ApiManagement", - "AzureRM.ApplicationInsights", - "AzureRM.Automation", - "AzureRM.Backup", - "AzureRM.Batch", - "AzureRM.Billing", - "AzureRM.Cdn", - "AzureRM.CognitiveServices", - "AzureRm.Compute", - "AzureRM.Compute.ManagedService", - "AzureRM.Consumption", - "AzureRM.ContainerInstance", - "AzureRM.ContainerRegistry", - "AzureRM.DataFactories", - "AzureRM.DataFactoryV2", - "AzureRM.DataLakeAnalytics", - "AzureRM.DataLakeStore", - "AzureRM.DataMigration", - "AzureRM.DeploymentManager", - "AzureRM.DeviceProvisioningServices", - "AzureRM.DevSpaces", - "AzureRM.DevTestLabs", - "AzureRm.Dns", - "AzureRM.EventGrid", - "AzureRM.EventHub", - "AzureRM.FrontDoor", - "AzureRM.HDInsight", - "AzureRm.Insights", - "AzureRM.IotCentral", - "AzureRM.IotHub", - "AzureRm.Keyvault", - "AzureRM.LocationBasedServices", - "AzureRM.LogicApp", - "AzureRM.MachineLearning", - "AzureRM.MachineLearningCompute", - "AzureRM.ManagedServiceIdentity", - "AzureRM.ManagementPartner", - "AzureRM.Maps", - "AzureRM.MarketplaceOrdering", - "AzureRM.Media", - "AzureRM.Network", - "AzureRM.NotificationHubs", - "AzureRM.OperationalInsights", - "AzureRM.PolicyInsights", - "AzureRM.PowerBIEmbedded", - "AzureRM.Profile", - "AzureRM.RecoveryServices", - "AzureRM.RecoveryServices.Backup", - "AzureRM.RecoveryServices.SiteRecovery", - "AzureRM.RedisCache", - "AzureRM.Relay", - "AzureRM.Reservations", - "AzureRM.ResourceGraph", - "AzureRM.Resources", - "AzureRM.Scheduler", - "AzureRM.Search", - "AzureRM.Security", - "AzureRM.ServerManagement", - "AzureRM.ServiceBus", - "AzureRM.ServiceFabric", - "AzureRM.SignalR", - "AzureRM.SiteRecovery", - "AzureRM.Sql", - "AzureRm.Storage", - "AzureRM.StorageSync", - "AzureRM.StreamAnalytics", - "AzureRM.Subscription", - "AzureRM.Subscription.Preview", - "AzureRM.Tags", - "AzureRM.TrafficManager", - "AzureRm.UsageAggregates", - "AzureRm.Websites", - "AzureRmStorageTable", - "bestpractices", - "bitlocker", - "bitstransfer", - "booteventcollector", - "branchcache", - "CimCmdlets", - "clusterawareupdating", - "CompatPowerShellGet", - "configci", - "ConfigurationManager", - "CompletionPredictor", - "DataProtectionManager", - "dcbqos", - "deduplication", - "defender", - "devicehealthattestation", - "dfsn", - "dfsr", - "dhcpserver", - "directaccessclient", - "directaccessclientcomponent", - "directaccessclientcomponents", - "dism", - "dnsclient", - "dnsserver", - "ElasticDatabaseJobs", - "EventTracingManagement", - "failoverclusters", - "fileserverresourcemanager", - "FIMAutomation", - "GPRegistryPolicy", - "grouppolicy", - "hardwarecertification", - "hcs", - "hgsattestation", - "hgsclient", - "hgsdiagnostics", - "hgskeyprotection", - "hgsserver", - "hnvdiagnostics", - "hostcomputeservice", - "hpc", - "HPC.ACM", - "HPC.ACM.API.PS", - "HPCPack2016", - "hyper-v", - "IISAdministration", - "international", - "ipamserver", - "iscsi", - "iscsitarget", - "ISE", - "kds", - "Microsoft.MBAM", - "Microsoft.MEDV", - "MgmtSvcAdmin", - "MgmtSvcConfig", - "MgmtSvcMySql", - "MgmtSvcSqlServer", - "Microsoft.AzureStack.ReadinessChecker", - "Microsoft.Crm.PowerShell", - "Microsoft.DiagnosticDataViewer", - "Microsoft.DirectoryServices.MetadirectoryServices.Config", - "Microsoft.Dynamics.Nav.Apps.Management", - "Microsoft.Dynamics.Nav.Apps.Tools", - "Microsoft.Dynamics.Nav.Ide", - "Microsoft.Dynamics.Nav.Management", - "Microsoft.Dynamics.Nav.Model.Tools", - "Microsoft.Dynamics.Nav.Model.Tools.Crm", - "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", - "Microsoft.Medv.Administration.Commands.WorkspacePackager", - "Microsoft.PowerApps.Checker.PowerShell", - "Microsoft.PowerShell.Archive", - "Microsoft.PowerShell.ConsoleGuiTools", - "Microsoft.PowerShell.Core", - "Microsoft.PowerShell.Crescendo", - "Microsoft.PowerShell.Diagnostics", - "Microsoft.PowerShell.Host", - "Microsoft.PowerShell.LocalAccounts", - "Microsoft.PowerShell.Management", - "Microsoft.PowerShell.ODataUtils", - "Microsoft.PowerShell.Operation.Validation", - "Microsoft.PowerShell.PSAdapter", - "Microsoft.PowerShell.PSResourceGet", - "Microsoft.PowerShell.RemotingTools", - "Microsoft.PowerShell.SecretManagement", - "Microsoft.PowerShell.SecretStore", - "Microsoft.PowerShell.Security", - "Microsoft.PowerShell.TextUtility", - "Microsoft.PowerShell.Utility", - "Microsoft.SharePoint.Powershell", - "Microsoft.SystemCenter.ServiceManagementAutomation", - "Microsoft.Windows.ServerManager.Migration", - "Microsoft.WSMan.Management", - "Microsoft.Xrm.OnlineManagementAPI", - "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", - "Microsoft.Xrm.Tooling.PackageDeployment", - "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", - "Microsoft.Xrm.Tooling.Testing", - "MicrosoftPowerBIMgmt", - "MicrosoftPowerBIMgmt.Data", - "MicrosoftPowerBIMgmt.Profile", - "MicrosoftPowerBIMgmt.Reports", - "MicrosoftPowerBIMgmt.Workspaces", - "MicrosoftStaffHub", - "MicrosoftTeams", - "MIMPAM", - "mlSqlPs", - "MMAgent", - "MPIO", - "MsDtc", - "MSMQ", - "MSOnline", - "MSOnlineBackup", - "WmsCmdlets", - "WmsCmdlets3", - "NanoServerImageGenerator", - "NAVWebClientManagement", - "NetAdapter", - "NetConnection", - "NetEventPacketCapture", - "Netlbfo", - "Netldpagent", - "NetNat", - "Netqos", - "NetSecurity", - "NetSwitchtTeam", - "Nettcpip", - "Netwnv", - "NetworkConnectivity", - "NetworkConnectivityStatus", - "NetworkController", - "NetworkControllerDiagnostics", - "NetworkloadBalancingClusters", - "NetworkSwitchManager", - "NetworkTransition", - "NFS", - "NPS", - "OfficeWebapps", - "OperationsManager", - "PackageManagement", - "PartnerCenter", - "pcsvdevice", - "pef", - "Pester", - "pkiclient", - "platformidentifier", - "pnpdevice", - "PowerShellEditorServices", - "PowerShellGet", - "powershellwebaccess", - "printmanagement", - "ProcessMitigations", - "provisioning", - "PSDesiredStateConfiguration", - "PSDiagnostics", - "PSReadLine", - "PSScheduledJob", - "PSScriptAnalyzer", - "PSWorkflow", - "PSWorkflowUtility", - "RemoteAccess", - "RemoteDesktop", - "RemoteDesktopServices", - "ScheduledTasks", - "Secureboot", - "ServerCore", - "ServerManager", - "ServerManagerTasks", - "ServerMigrationcmdlets", - "ServiceFabric", - "Microsoft.Online.SharePoint.PowerShell", - "shieldedvmdatafile", - "shieldedvmprovisioning", - "shieldedvmtemplate", - "SkypeOnlineConnector", - "SkypeForBusinessHybridHealth", - "smbshare", - "smbwitness", - "smisconfig", - "softwareinventorylogging", - "SPFAdmin", - "Microsoft.SharePoint.MigrationTool.PowerShell", - "sqlps", - "SqlServer", - "StartLayout", - "StartScreen", - "Storage", - "StorageDsc", - "storageqos", - "Storagereplica", - "Storagespaces", - "Syncshare", - "System.Center.Service.Manager", - "TLS", - "TroubleshootingPack", - "TrustedPlatformModule", - "UEV", - "UpdateServices", - "UserAccessLogging", - "vamt", - "VirtualMachineManager", - "vpnclient", - "WasPSExt", - "WDAC", - "WDS", - "WebAdministration", - "WebAdministrationDsc", - "WebApplicationProxy", - "WebSites", - "Whea", - "WhiteboardAdmin", - "WindowsDefender", - "WindowsDefenderDsc", - "WindowsDeveloperLicense", - "WindowsDiagnosticData", - "WindowsErrorReporting", - "WindowServerRackup", - "WindowsSearch", - "WindowsServerBackup", - "WindowsUpdate", - "WinGetCommandNotFound", - "wsscmdlets", - "wsssetup", - "wsus", - "xActiveDirectory", - "xBitLocker", - "xDefender", - "xDhcpServer", - "xDismFeature", - "xDnsServer", - "xHyper-V", - "xHyper-VBackup", - "xPSDesiredStateConfiguration", - "xSmbShare", - "xSqlPs", - "xStorage", - "xWebAdministration", - "xWindowsUpdate", - }; - - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModuleTags = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "CrescendoBuilt", - }; + s_telemetryClient = new TelemetryClient(configuration); - s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); - s_knownSubsystemNames = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Completion", - "General Feedback", - "Windows Package Manager - WinGet", - "Az Predictor" - }; - } + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModules = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "AADRM", + "activedirectory", + "adcsadministration", + "adcsdeployment", + "addsadministration", + "addsdeployment", + "adfs", + "adrms", + "adrmsadmin", + "agpm", + "AIShell", + "appbackgroundtask", + "applocker", + "appv", + "appvclient", + "appvsequencer", + "appvserver", + "appx", + "assignedaccess", + "Az", + "Az.Accounts", + "Az.Advisor", + "Az.Aks", + "Az.AlertsManagement", + "Az.AnalysisServices", + "Az.ApiManagement", + "Az.ApplicationInsights", + "Az.Attestation", + "Az.Automation", + "Az.Batch", + "Az.Billing", + "Az.Blueprint", + "Az.Cdn", + "Az.CognitiveServices", + "Az.Compute", + "Az.ContainerInstance", + "Az.ContainerRegistry", + "Az.DataBox", + "Az.DataFactory", + "Az.DataLakeAnalytics", + "Az.DataLakeStore", + "Az.DataMigration", + "Az.DataShare", + "Az.DeploymentManager", + "Az.DeviceProvisioningServices", + "Az.DevSpaces", + "Az.DevTestLabs", + "Az.Dns", + "Az.EventGrid", + "Az.EventHub", + "Az.FrontDoor", + "Az.GuestConfiguration", + "Az.HDInsight", + "Az.HealthcareApis", + "Az.IotCentral", + "Az.IotHub", + "Az.KeyVault", + "Az.Kusto", + "Az.LogicApp", + "Az.MachineLearning", + "Az.ManagedServiceIdentity", + "Az.ManagedServices", + "Az.ManagementPartner", + "Az.Maps", + "Az.MarketplaceOrdering", + "Az.Media", + "Az.MixedReality", + "Az.Monitor", + "Az.NetAppFiles", + "Az.Network", + "Az.NotificationHubs", + "Az.OperationalInsights", + "Az.Peering", + "Az.PolicyInsights", + "Az.PowerBIEmbedded", + "Az.PrivateDns", + "Az.RecoveryServices", + "Az.RedisCache", + "Az.Relay", + "Az.Reservations", + "Az.ResourceGraph", + "Az.Resources", + "Az.Search", + "Az.Security", + "Az.ServiceBus", + "Az.ServiceFabric", + "Az.SignalR", + "Az.Sql", + "Az.Storage", + "Az.StorageSync", + "Az.StorageTable", + "Az.StreamAnalytics", + "Az.Subscription", + "Az.Tools.Predictor", + "Az.TrafficManager", + "Az.Websites", + "Azs.Azurebridge.Admin", + "Azs.Backup.Admin", + "Azs.Commerce.Admin", + "Azs.Compute.Admin", + "Azs.Fabric.Admin", + "Azs.Gallery.Admin", + "Azs.Infrastructureinsights.Admin", + "Azs.Keyvault.Admin", + "Azs.Network.Admin", + "Azs.Storage.Admin", + "Azs.Subscriptions", + "Azs.Subscriptions.Admin", + "Azs.Update.Admin", + "AzStorageTable", + "Azure", + "Azure.AnalysisServices", + "Azure.Storage", + "AzureAD", + "AzureInformationProtection", + "AzureRM.Aks", + "AzureRM.AnalysisServices", + "AzureRM.ApiManagement", + "AzureRM.ApplicationInsights", + "AzureRM.Automation", + "AzureRM.Backup", + "AzureRM.Batch", + "AzureRM.Billing", + "AzureRM.Cdn", + "AzureRM.CognitiveServices", + "AzureRm.Compute", + "AzureRM.Compute.ManagedService", + "AzureRM.Consumption", + "AzureRM.ContainerInstance", + "AzureRM.ContainerRegistry", + "AzureRM.DataFactories", + "AzureRM.DataFactoryV2", + "AzureRM.DataLakeAnalytics", + "AzureRM.DataLakeStore", + "AzureRM.DataMigration", + "AzureRM.DeploymentManager", + "AzureRM.DeviceProvisioningServices", + "AzureRM.DevSpaces", + "AzureRM.DevTestLabs", + "AzureRm.Dns", + "AzureRM.EventGrid", + "AzureRM.EventHub", + "AzureRM.FrontDoor", + "AzureRM.HDInsight", + "AzureRm.Insights", + "AzureRM.IotCentral", + "AzureRM.IotHub", + "AzureRm.Keyvault", + "AzureRM.LocationBasedServices", + "AzureRM.LogicApp", + "AzureRM.MachineLearning", + "AzureRM.MachineLearningCompute", + "AzureRM.ManagedServiceIdentity", + "AzureRM.ManagementPartner", + "AzureRM.Maps", + "AzureRM.MarketplaceOrdering", + "AzureRM.Media", + "AzureRM.Network", + "AzureRM.NotificationHubs", + "AzureRM.OperationalInsights", + "AzureRM.PolicyInsights", + "AzureRM.PowerBIEmbedded", + "AzureRM.Profile", + "AzureRM.RecoveryServices", + "AzureRM.RecoveryServices.Backup", + "AzureRM.RecoveryServices.SiteRecovery", + "AzureRM.RedisCache", + "AzureRM.Relay", + "AzureRM.Reservations", + "AzureRM.ResourceGraph", + "AzureRM.Resources", + "AzureRM.Scheduler", + "AzureRM.Search", + "AzureRM.Security", + "AzureRM.ServerManagement", + "AzureRM.ServiceBus", + "AzureRM.ServiceFabric", + "AzureRM.SignalR", + "AzureRM.SiteRecovery", + "AzureRM.Sql", + "AzureRm.Storage", + "AzureRM.StorageSync", + "AzureRM.StreamAnalytics", + "AzureRM.Subscription", + "AzureRM.Subscription.Preview", + "AzureRM.Tags", + "AzureRM.TrafficManager", + "AzureRm.UsageAggregates", + "AzureRm.Websites", + "AzureRmStorageTable", + "bestpractices", + "bitlocker", + "bitstransfer", + "booteventcollector", + "branchcache", + "CimCmdlets", + "clusterawareupdating", + "CompatPowerShellGet", + "configci", + "ConfigurationManager", + "CompletionPredictor", + "DataProtectionManager", + "dcbqos", + "deduplication", + "defender", + "devicehealthattestation", + "dfsn", + "dfsr", + "dhcpserver", + "directaccessclient", + "directaccessclientcomponent", + "directaccessclientcomponents", + "dism", + "dnsclient", + "dnsserver", + "ElasticDatabaseJobs", + "EventTracingManagement", + "failoverclusters", + "fileserverresourcemanager", + "FIMAutomation", + "GPRegistryPolicy", + "grouppolicy", + "hardwarecertification", + "hcs", + "hgsattestation", + "hgsclient", + "hgsdiagnostics", + "hgskeyprotection", + "hgsserver", + "hnvdiagnostics", + "hostcomputeservice", + "hpc", + "HPC.ACM", + "HPC.ACM.API.PS", + "HPCPack2016", + "hyper-v", + "IISAdministration", + "international", + "ipamserver", + "iscsi", + "iscsitarget", + "ISE", + "kds", + "Microsoft.MBAM", + "Microsoft.MEDV", + "MgmtSvcAdmin", + "MgmtSvcConfig", + "MgmtSvcMySql", + "MgmtSvcSqlServer", + "Microsoft.AzureStack.ReadinessChecker", + "Microsoft.Crm.PowerShell", + "Microsoft.DiagnosticDataViewer", + "Microsoft.DirectoryServices.MetadirectoryServices.Config", + "Microsoft.Dynamics.Nav.Apps.Management", + "Microsoft.Dynamics.Nav.Apps.Tools", + "Microsoft.Dynamics.Nav.Ide", + "Microsoft.Dynamics.Nav.Management", + "Microsoft.Dynamics.Nav.Model.Tools", + "Microsoft.Dynamics.Nav.Model.Tools.Crm", + "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", + "Microsoft.Medv.Administration.Commands.WorkspacePackager", + "Microsoft.PowerApps.Checker.PowerShell", + "Microsoft.PowerShell.Archive", + "Microsoft.PowerShell.ConsoleGuiTools", + "Microsoft.PowerShell.Core", + "Microsoft.PowerShell.Crescendo", + "Microsoft.PowerShell.Diagnostics", + "Microsoft.PowerShell.Host", + "Microsoft.PowerShell.LocalAccounts", + "Microsoft.PowerShell.Management", + "Microsoft.PowerShell.ODataUtils", + "Microsoft.PowerShell.Operation.Validation", + "Microsoft.PowerShell.PSAdapter", + "Microsoft.PowerShell.PSResourceGet", + "Microsoft.PowerShell.RemotingTools", + "Microsoft.PowerShell.SecretManagement", + "Microsoft.PowerShell.SecretStore", + "Microsoft.PowerShell.Security", + "Microsoft.PowerShell.TextUtility", + "Microsoft.PowerShell.Utility", + "Microsoft.SharePoint.Powershell", + "Microsoft.SystemCenter.ServiceManagementAutomation", + "Microsoft.Windows.ServerManager.Migration", + "Microsoft.WSMan.Management", + "Microsoft.Xrm.OnlineManagementAPI", + "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", + "Microsoft.Xrm.Tooling.PackageDeployment", + "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", + "Microsoft.Xrm.Tooling.Testing", + "MicrosoftPowerBIMgmt", + "MicrosoftPowerBIMgmt.Data", + "MicrosoftPowerBIMgmt.Profile", + "MicrosoftPowerBIMgmt.Reports", + "MicrosoftPowerBIMgmt.Workspaces", + "MicrosoftStaffHub", + "MicrosoftTeams", + "MIMPAM", + "mlSqlPs", + "MMAgent", + "MPIO", + "MsDtc", + "MSMQ", + "MSOnline", + "MSOnlineBackup", + "WmsCmdlets", + "WmsCmdlets3", + "NanoServerImageGenerator", + "NAVWebClientManagement", + "NetAdapter", + "NetConnection", + "NetEventPacketCapture", + "Netlbfo", + "Netldpagent", + "NetNat", + "Netqos", + "NetSecurity", + "NetSwitchtTeam", + "Nettcpip", + "Netwnv", + "NetworkConnectivity", + "NetworkConnectivityStatus", + "NetworkController", + "NetworkControllerDiagnostics", + "NetworkloadBalancingClusters", + "NetworkSwitchManager", + "NetworkTransition", + "NFS", + "NPS", + "OfficeWebapps", + "OperationsManager", + "PackageManagement", + "PartnerCenter", + "pcsvdevice", + "pef", + "Pester", + "pkiclient", + "platformidentifier", + "pnpdevice", + "PowerShellEditorServices", + "PowerShellGet", + "powershellwebaccess", + "printmanagement", + "ProcessMitigations", + "provisioning", + "PSDesiredStateConfiguration", + "PSDiagnostics", + "PSReadLine", + "PSScheduledJob", + "PSScriptAnalyzer", + "PSWorkflow", + "PSWorkflowUtility", + "RemoteAccess", + "RemoteDesktop", + "RemoteDesktopServices", + "ScheduledTasks", + "Secureboot", + "ServerCore", + "ServerManager", + "ServerManagerTasks", + "ServerMigrationcmdlets", + "ServiceFabric", + "Microsoft.Online.SharePoint.PowerShell", + "shieldedvmdatafile", + "shieldedvmprovisioning", + "shieldedvmtemplate", + "SkypeOnlineConnector", + "SkypeForBusinessHybridHealth", + "smbshare", + "smbwitness", + "smisconfig", + "softwareinventorylogging", + "SPFAdmin", + "Microsoft.SharePoint.MigrationTool.PowerShell", + "sqlps", + "SqlServer", + "StartLayout", + "StartScreen", + "Storage", + "StorageDsc", + "storageqos", + "Storagereplica", + "Storagespaces", + "Syncshare", + "System.Center.Service.Manager", + "TLS", + "TroubleshootingPack", + "TrustedPlatformModule", + "UEV", + "UpdateServices", + "UserAccessLogging", + "vamt", + "VirtualMachineManager", + "vpnclient", + "WasPSExt", + "WDAC", + "WDS", + "WebAdministration", + "WebAdministrationDsc", + "WebApplicationProxy", + "WebSites", + "Whea", + "WhiteboardAdmin", + "WindowsDefender", + "WindowsDefenderDsc", + "WindowsDeveloperLicense", + "WindowsDiagnosticData", + "WindowsErrorReporting", + "WindowServerRackup", + "WindowsSearch", + "WindowsServerBackup", + "WindowsUpdate", + "WinGetCommandNotFound", + "wsscmdlets", + "wsssetup", + "wsus", + "xActiveDirectory", + "xBitLocker", + "xDefender", + "xDhcpServer", + "xDismFeature", + "xDnsServer", + "xHyper-V", + "xHyper-VBackup", + "xPSDesiredStateConfiguration", + "xSmbShare", + "xSqlPs", + "xStorage", + "xWebAdministration", + "xWindowsUpdate", + }; + + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModuleTags = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "CrescendoBuilt", + }; + + s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); + s_knownSubsystemNames = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Completion", + "General Feedback", + "Windows Package Manager - WinGet", + "Az Predictor" + }; } /// @@ -984,8 +990,7 @@ private static Guid GetUniqueIdentifier() // Try to get the unique id. If this returns false, we'll // create/recreate the telemetry.uuid file to persist for next startup. Guid id = Guid.Empty; - string uuidPath = Path.Join(Platform.CacheDirectory, "telemetry.uuid"); - if (TryGetIdentifier(uuidPath, out id)) + if (TryGetIdentifier(s_uuidPath, out id)) { return id; } @@ -1000,7 +1005,7 @@ private static Guid GetUniqueIdentifier() m.WaitOne(); try { - return CreateUniqueIdentifierAndFile(uuidPath); + return CreateUniqueIdentifierAndFile(s_uuidPath); } finally { From 1b3a3215d2ef79ac3c937a5b7e422d211adb2f09 Mon Sep 17 00:00:00 2001 From: ThioJoe <12518330+ThioJoe@users.noreply.github.com> Date: Wed, 22 Oct 2025 21:09:26 -0700 Subject: [PATCH 152/378] Fix a few simple typos in comments and string outputs (#25805) Co-authored-by: Travis Plunk --- assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 | 4 ++-- .../engine/remoting/common/RunspaceConnectionInfo.cs | 2 +- .../Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 | 2 +- .../Microsoft.PowerShell.RemotingTools.psm1 | 2 +- tools/packaging/packaging.psm1 | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 b/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 index db756063da4..da89768f74a 100644 --- a/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 +++ b/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 @@ -17,14 +17,14 @@ switch ($TestHook) { } default { $jobScript = { - # This registers Microsoft Update via a predifened GUID with the Windows Update Agent. + # This registers Microsoft Update via a predefined GUID with the Windows Update Agent. # https://learn.microsoft.com/windows/win32/wua_sdk/opt-in-to-microsoft-update $serviceManager = (New-Object -ComObject Microsoft.Update.ServiceManager) $isRegistered = $serviceManager.QueryServiceRegistration('7971f918-a847-4430-9279-4a52d1efe18d').Service.IsRegisteredWithAu if (!$isRegistered) { - Write-Verbose -Verbose "Opting into Microsoft Update as the Autmatic Update Service" + Write-Verbose -Verbose "Opting into Microsoft Update as the Automatic Update Service" # 7 is the combination of asfAllowPendingRegistration, asfAllowOnlineRegistration, asfRegisterServiceWithAU # AU means Automatic Updates $null = $serviceManager.AddService2('7971f918-a847-4430-9279-4a52d1efe18d', 7, '') diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 5f25851337e..b6913e0cc1c 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2255,7 +2255,7 @@ internal int StartSSHProcess( DiscoveryExceptions.CommandNotFoundException); } - // Create a local ssh process (client) that conects to a remote sshd process (server) using a 'powershell' subsystem. + // Create a local ssh process (client) that connects to a remote sshd process (server) using a 'powershell' subsystem. // // Local ssh invoked as: // windows: diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 index 27d5cfb8359..58f6a4f3353 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 @@ -286,7 +286,7 @@ Describe "Deserializing corrupted Cim classes should not instantiate non-Cim typ BeforeAll { # Only run on Windows platform. - # Ensure calc.exe is avaiable for test. + # Ensure calc.exe is available for test. $shouldRunTest = $IsWindows -and ((Get-Command calc.exe -ErrorAction SilentlyContinue) -ne $null) $skipNotWindows = ! $shouldRunTest if ( $shouldRunTest ) diff --git a/test/tools/Modules/Microsoft.PowerShell.RemotingTools/Microsoft.PowerShell.RemotingTools.psm1 b/test/tools/Modules/Microsoft.PowerShell.RemotingTools/Microsoft.PowerShell.RemotingTools.psm1 index 41a57772fd3..911aa8da0ce 100644 --- a/test/tools/Modules/Microsoft.PowerShell.RemotingTools/Microsoft.PowerShell.RemotingTools.psm1 +++ b/test/tools/Modules/Microsoft.PowerShell.RemotingTools/Microsoft.PowerShell.RemotingTools.psm1 @@ -321,7 +321,7 @@ $typeDef = @' .Parameter PowerShellFilePath Specifies the file path to the PowerShell command used to host the SSH remoting PowerShell endpoint. If no value is specified then the currently running PowerShell executable path is used - in the subsytem command. + in the subsystem command. .Parameter Force When true, this cmdlet will update the sshd_config configuration file without prompting. #> diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 894323a4b98..435fe2d49bc 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1069,7 +1069,7 @@ function New-UnixPackage { DynamicParam { if ($Type -eq "deb" -or $Type -like 'rpm*') { # Add a dynamic parameter '-Distribution' when the specified package type is 'deb'. - # The '-Distribution' parameter can be used to indicate which Debian distro this pacakge is targeting. + # The '-Distribution' parameter can be used to indicate which Debian distro this package is targeting. $ParameterAttr = New-Object "System.Management.Automation.ParameterAttribute" if($type -eq 'deb') { @@ -1838,7 +1838,7 @@ function Get-PackageDependencies param() DynamicParam { # Add a dynamic parameter '-Distribution' when the specified package type is 'deb'. - # The '-Distribution' parameter can be used to indicate which Debian distro this pacakge is targeting. + # The '-Distribution' parameter can be used to indicate which Debian distro this package is targeting. $ParameterAttr = New-Object "System.Management.Automation.ParameterAttribute" $ParameterAttr.Mandatory = $true $ValidateSetAttr = New-Object "System.Management.Automation.ValidateSetAttribute" -ArgumentList $Script:AllDistributions From e5d40dc06de24cf3fe6d6316414673af8aba5d2e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 23 Oct 2025 11:15:30 -0700 Subject: [PATCH 153/378] Update PSReadLine to v2.4.5 (#26282) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 327c293e72c..6cec561a07a 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -15,7 +15,7 @@ - + From b0507ca4cf9f70cc184336a7fcffee980bd40380 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 23 Oct 2025 11:21:01 -0700 Subject: [PATCH 154/378] Fix build to only enable ready-to-run for the Release configuration (#26290) --- PowerShell.Common.props | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 91d44c21f03..dfc16f830d7 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -193,12 +193,20 @@ Global + + + + true true AppLocal + + + + true true From 38f9885173eeea363e9650b317d3c35149540f17 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 23 Oct 2025 16:19:55 -0700 Subject: [PATCH 155/378] Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26291) --- .../CommandCompletion/CompletionCompleters.cs | 4 ++-- .../Host/TabCompletion/BugFix.Tests.ps1 | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 80ba4545ff4..335a704dd62 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -4580,8 +4580,8 @@ internal static IEnumerable CompleteFilename(CompletionContext return CommandCompletion.EmptyCompletionResult; } - var lastAst = context.RelatedAsts[^1]; - if (lastAst.Parent is UsingStatementAst usingStatement + var lastAst = context.RelatedAsts?[^1]; + if (lastAst?.Parent is UsingStatementAst usingStatement && usingStatement.UsingStatementKind is UsingStatementKind.Module or UsingStatementKind.Assembly && lastAst.Extent.File is not null) { diff --git a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 index 32fd73f8c09..a7191d06e9b 100644 --- a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 @@ -126,4 +126,27 @@ Describe "Tab completion bug fix" -Tags "CI" { $Runspace.Dispose() } } + + It "Issue#26277 - [CompletionCompleters]::CompleteFilename('') should work" { + $testDir = Join-Path $TestDrive "TempTestDir" + $file1 = Join-Path $testDir "abc.ps1" + $file2 = Join-Path $testDir "def.py" + + New-Item -ItemType Directory -Path $testDir > $null + New-Item -ItemType File -Path $file1 > $null + New-Item -ItemType File -Path $file2 > $null + + try { + Push-Location -Path $testDir + $result = [System.Management.Automation.CompletionCompleters]::CompleteFilename("") + $result | Should -Not -Be $null + $result | Measure-Object | ForEach-Object -MemberName Count | Should -Be 2 + + $item1, $item2 = @($result) + $item1.ListItemText | Should -BeExactly 'abc.ps1' + $item2.ListItemText | Should -BeExactly 'def.py' + } finally { + Pop-Location + } + } } From 7ec01116351c928e79951c91a2b62f839538bf40 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 23 Oct 2025 20:21:16 -0700 Subject: [PATCH 156/378] Create github copilot setup workflow (#26285) Co-authored-by: Dongbo Wang --- .github/workflows/copilot-setup-steps.yml | 61 +++++++++++++ build.psm1 | 106 ++++++++++++++++++++-- 2 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/copilot-setup-steps.yml diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 00000000000..ac57bd87b5a --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,61 @@ +name: "Copilot Setup Steps" + +# Allow testing of the setup steps from your repository's "Actions" tab. +on: + workflow_dispatch: + + pull_request: + branches: + - master + paths: + - ".github/workflows/copilot-setup-steps.yml" + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + # See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent + copilot-setup-steps: + runs-on: ubuntu-latest + + permissions: + contents: read + + # You can define any steps you want, and they will run before the agent starts. + # If you do not check out your code, Copilot will do this for you. + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 1000 + + - name: Bootstrap + if: success() + run: |- + $title = 'Import Build.psm1' + Write-Host "::group::$title" + Import-Module ./build.psm1 -Verbose -ErrorAction Stop + Write-LogGroupEnd -Title $title + + $title = 'Switch to public feed' + Write-LogGroupStart -Title $title + Switch-PSNugetConfig -Source Public + Write-LogGroupEnd -Title $title + + $title = 'Bootstrap' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario DotNet + Write-LogGroupEnd -Title $title + + $title = 'Install .NET Tools' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario Tools + Write-LogGroupEnd -Title $title + + $title = 'Sync Tags' + Write-LogGroupStart -Title $title + Sync-PSTags -AddRemoteIfMissing + Write-LogGroupEnd -Title $title + + $title = 'Setup .NET environment variables' + Write-LogGroupStart -Title $title + Find-DotNet -SetDotnetRoot + Write-LogGroupEnd -Title $title + shell: pwsh diff --git a/build.psm1 b/build.psm1 index 88878bdd635..1b56d9d545d 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2282,7 +2282,12 @@ function Start-PSBootstrap { [switch]$BuildLinuxArm, [switch]$Force, [Parameter(Mandatory = $true)] - [ValidateSet("Package", "DotNet", "Both")] + # Package: Install dependencies for packaging tools (fpm, rpmbuild, WiX) + # DotNet: Install the .NET SDK + # Both: Package and DotNet scenarios + # Tools: Install .NET global tools (e.g., dotnet-format) + # All: Install all dependencies (packaging, .NET SDK, and tools) + [ValidateSet("Package", "DotNet", "Both", "Tools", "All")] [string]$Scenario = "Package" ) @@ -2402,7 +2407,7 @@ function Start-PSBootstrap { # Install [fpm](https://github.com/jordansissel/fpm) # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { + if ($Scenario -in 'All', 'Both', 'Package') { # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" @@ -2410,7 +2415,7 @@ function Start-PSBootstrap { Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" } - + # For RPM-based systems, ensure rpmbuild is available if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for rpmbuild..." @@ -2422,7 +2427,7 @@ function Start-PSBootstrap { } } - if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + if ($Scenario -in 'All', 'Both', 'DotNet') { Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" @@ -2479,6 +2484,19 @@ function Start-PSBootstrap { } } + if ($Scenario -in 'All', 'Tools') { + Write-Log -message "Installing .NET global tools" + + # Ensure dotnet is available + Find-Dotnet + + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + } + if ($env:TF_BUILD) { Write-Verbose -Verbose "--- Start - Capturing nuget sources" dotnet nuget list source --format detailed @@ -2646,6 +2664,63 @@ function Start-ResGen } } +function Add-PSEnvironmentPath { + <# + .SYNOPSIS + Adds a path to the process PATH and persists to GitHub Actions workflow if running in GitHub Actions + .PARAMETER Path + Path to add to PATH + .PARAMETER Prepend + If specified, prepends the path instead of appending + #> + param ( + [Parameter(Mandatory)] + [string]$Path, + + [switch]$Prepend + ) + + # Set in current process + if ($Prepend) { + $env:PATH = $Path + [IO.Path]::PathSeparator + $env:PATH + } else { + $env:PATH += [IO.Path]::PathSeparator + $Path + } + + # Persist to GitHub Actions workflow if running in GitHub Actions + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Verbose -Verbose "Adding $Path to GITHUB_PATH" + Add-Content -Path $env:GITHUB_PATH -Value $Path + } +} + +function Set-PSEnvironmentVariable { + <# + .SYNOPSIS + Sets an environment variable in the process and persists to GitHub Actions workflow if running in GitHub Actions + .PARAMETER Name + The name of the environment variable + .PARAMETER Value + The value of the environment variable + #> + param ( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Value + ) + + # Set in current process + Set-Item -Path "env:$Name" -Value $Value + + # Persist to GitHub Actions workflow if running in GitHub Actions + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Verbose -Verbose "Setting $Name in GITHUB_ENV" + Add-Content -Path $env:GITHUB_ENV -Value "$Name=$Value" + } +} + function Find-Dotnet { param ( [switch] $SetDotnetRoot @@ -2676,25 +2751,40 @@ function Find-Dotnet { if ($dotnetCLIInstalledVersion -ne $chosenDotNetVersion) { Write-Warning "The 'dotnet' in the current path can't find SDK version ${dotnetCLIRequiredVersion}, prepending $dotnetPath to PATH." # Globally installed dotnet doesn't have the required SDK version, prepend the user local dotnet location - $env:PATH = $dotnetPath + [IO.Path]::PathSeparator + $env:PATH + Add-PSEnvironmentPath -Path $dotnetPath -Prepend if ($SetDotnetRoot) { Write-Verbose -Verbose "Setting DOTNET_ROOT to $dotnetPath" - $env:DOTNET_ROOT = $dotnetPath + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath } } elseif ($SetDotnetRoot) { Write-Verbose -Verbose "Expected dotnet version found, setting DOTNET_ROOT to $dotnetPath" - $env:DOTNET_ROOT = $dotnetPath + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath } } else { Write-Warning "Could not find 'dotnet', appending $dotnetPath to PATH." - $env:PATH += [IO.Path]::PathSeparator + $dotnetPath + Add-PSEnvironmentPath -Path $dotnetPath + + if ($SetDotnetRoot) { + Write-Verbose -Verbose "Setting DOTNET_ROOT to $dotnetPath" + Set-PSEnvironmentVariable -Name 'DOTNET_ROOT' -Value $dotnetPath + } } if (-not (precheck 'dotnet' "Still could not find 'dotnet', restoring PATH.")) { + # Give up, restore original PATH. There is nothing to persist since we didn't make a change. $env:PATH = $originalPath } + elseif ($SetDotnetRoot) { + # If we found dotnet, also add the global tools path to PATH + # Add .NET global tools to PATH when setting up the environment + $dotnetToolsPath = Join-Path $dotnetPath "tools" + if (Test-Path $dotnetToolsPath) { + Write-Verbose -Verbose "Adding .NET tools path to PATH: $dotnetToolsPath" + Add-PSEnvironmentPath -Path $dotnetToolsPath + } + } } <# From 4e694526d97ee32d282bfca9b87139079d36042f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:10:29 +0100 Subject: [PATCH 157/378] Enable CA2022: Avoid inexact read with 'Stream.Read' (#25814) --- .globalconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.globalconfig b/.globalconfig index ed1d6c1a335..7395d94ea62 100644 --- a/.globalconfig +++ b/.globalconfig @@ -574,6 +574,10 @@ dotnet_diagnostic.CA2016.severity = suggestion # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021 dotnet_diagnostic.CA2021.severity = warning +# CA2022: Avoid inexact read with 'Stream.Read' +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2022 +dotnet_diagnostic.CA2022.severity = warning + # CA2100: Review SQL queries for security vulnerabilities # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2100 dotnet_diagnostic.CA2100.severity = none From 82d59136b2a5ed1e35c97145c86b6ff2c54ec16a Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:54:03 +0100 Subject: [PATCH 158/378] Use `[initialsessionstate]` type accelerator (#25912) --- .../Language/Classes/Scripting.Classes.BasicParsing.Tests.ps1 | 4 ++-- .../Language/Classes/scripting.Classes.using.tests.ps1 | 2 +- .../Microsoft.PowerShell.Utility/Export-FormatData.Tests.ps1 | 4 ++-- .../Microsoft.PowerShell.Utility/Implicit.Remoting.Tests.ps1 | 2 +- .../Microsoft.PowerShell.Utility/Remove-TypeData.Tests.ps1 | 2 +- .../Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 | 2 +- .../Microsoft.PowerShell.Utility/Update-TypeData.Tests.ps1 | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/powershell/Language/Classes/Scripting.Classes.BasicParsing.Tests.ps1 b/test/powershell/Language/Classes/Scripting.Classes.BasicParsing.Tests.ps1 index 4e5668071d7..6674697ca2f 100644 --- a/test/powershell/Language/Classes/Scripting.Classes.BasicParsing.Tests.ps1 +++ b/test/powershell/Language/Classes/Scripting.Classes.BasicParsing.Tests.ps1 @@ -833,7 +833,7 @@ class Derived : Base [Derived]::new().foo() '@) - $iss = [System.Management.Automation.Runspaces.initialsessionstate]::CreateDefault2() + $iss = [initialsessionstate]::CreateDefault2() $iss.Commands.Add($ssfe) $ps = [powershell]::Create($iss) @@ -929,7 +929,7 @@ class A : Foo.Bar return [A]::new() '@) - $iss = [System.Management.Automation.Runspaces.initialsessionstate]::CreateDefault() + $iss = [initialsessionstate]::CreateDefault() $iss.Commands.Add($ssfe) $ps = [powershell]::Create($iss) diff --git a/test/powershell/Language/Classes/scripting.Classes.using.tests.ps1 b/test/powershell/Language/Classes/scripting.Classes.using.tests.ps1 index fb3778463da..d4e86e341b1 100644 --- a/test/powershell/Language/Classes/scripting.Classes.using.tests.ps1 +++ b/test/powershell/Language/Classes/scripting.Classes.using.tests.ps1 @@ -417,7 +417,7 @@ function foo() '@ # resolve name to absolute path $scriptToProcessPath = (Get-ChildItem $scriptToProcessPath).FullName - $iss = [System.Management.Automation.Runspaces.initialsessionstate]::CreateDefault() + $iss = [initialsessionstate]::CreateDefault() $iss.StartupScripts.Add($scriptToProcessPath) $ps = [powershell]::Create($iss) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-FormatData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-FormatData.Tests.ps1 index c024f364c68..3325b21a9c4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-FormatData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-FormatData.Tests.ps1 @@ -16,7 +16,7 @@ Describe "Export-FormatData" -Tags "CI" { { $fd | Export-FormatData -Path $TESTDRIVE\allformat.ps1xml -IncludeScriptBlock - $sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() + $sessionState = [initialsessionstate]::CreateDefault() $sessionState.Formats.Clear() $sessionState.Types.Clear() @@ -135,7 +135,7 @@ Describe "Export-FormatData" -Tags "CI" { $testfile = Join-Path -Path $TestDrive -ChildPath "$testfilename.ps1xml" Set-Content -Path $testfile -Value $xmlContent - $sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() + $sessionState = [initialsessionstate]::CreateDefault() $sessionState.Formats.Clear() $sessionState.Types.Clear() diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Implicit.Remoting.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Implicit.Remoting.Tests.ps1 index b532d7523ef..0c15fe6d359 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Implicit.Remoting.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Implicit.Remoting.Tests.ps1 @@ -1901,7 +1901,7 @@ try Export-PSSession -Session $session -OutputModule $tempdir\Diag -CommandName New-Guid -AllowClobber > $null # Only the snapin Microsoft.PowerShell.Core is loaded - $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault2() + $iss = [initialsessionstate]::CreateDefault2() $ps = [PowerShell]::Create($iss) $result = $ps.AddScript(" & $tempdir\TestBug450687.ps1").Invoke() diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Remove-TypeData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Remove-TypeData.Tests.ps1 index ba009de4b1b..96178fa13c0 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Remove-TypeData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Remove-TypeData.Tests.ps1 @@ -36,7 +36,7 @@ Describe "Remove-TypeData DRT Unit Tests" -Tags "CI" { BeforeEach { $ps = [powershell]::Create() - $iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault2() + $iss = [initialsessionstate]::CreateDefault2() $rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace($iss) $rs.Open() $ps.Runspace = $rs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 index d7cfa1f3204..0c2969dfb2a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-FormatData.Tests.ps1 @@ -110,7 +110,7 @@ Describe "Update-FormatData with resources in CustomControls" -Tags "CI" { $templatePath = Join-Path $PSScriptRoot (Join-Path 'assets' 'UpdateFormatDataTests.format.ps1xml') $formatFilePath = Join-Path $TestDrive 'UpdateFormatDataTests.format.ps1xml' $ps = [powershell]::Create() - $iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault2() + $iss = [initialsessionstate]::CreateDefault2() $rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace($iss) $rs.Open() $ps.Runspace = $rs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-TypeData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-TypeData.Tests.ps1 index e2666ea6199..07a5f8ae2e6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-TypeData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Update-TypeData.Tests.ps1 @@ -37,7 +37,7 @@ Describe "Update-TypeData basic functionality" -Tags "CI" { BeforeEach { $ps = [powershell]::Create() - $iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault2() + $iss = [initialsessionstate]::CreateDefault2() $rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace($iss) $rs.Open() $ps.Runspace = $rs From 70b0e8768cc875a69a85014826340ffdfee74436 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 13:48:21 -0700 Subject: [PATCH 159/378] Bump actions/checkout from 4 to 5 (#26273) --- .github/workflows/verify-markdown-links.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml index db9fb7e416a..b26539eb0cf 100644 --- a/.github/workflows/verify-markdown-links.yml +++ b/.github/workflows/verify-markdown-links.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Verify markdown links id: verify From f51860c1d14ee16d9055e0b818460dba0c935242 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sat, 25 Oct 2025 16:58:16 +0100 Subject: [PATCH 160/378] Remove unused timeout variable from RemoteHyperVTests class (#26297) --- test/xUnit/csharp/test_RemoteHyperV.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/xUnit/csharp/test_RemoteHyperV.cs b/test/xUnit/csharp/test_RemoteHyperV.cs index 27f7fb17375..c7cda754161 100644 --- a/test/xUnit/csharp/test_RemoteHyperV.cs +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -20,7 +20,6 @@ namespace PSTests.Sequential public class RemoteHyperVTests { private static ITestOutputHelper _output; - private static TimeSpan timeout = TimeSpan.FromSeconds(15); public RemoteHyperVTests(ITestOutputHelper output) { From 00efbe60767d2b3f91377c7eb6ac67d24c358600 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:55:23 +0000 Subject: [PATCH 161/378] Enable CA1200: Avoid using cref tags with a prefix (#26298) --- .globalconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index 7395d94ea62..d60227efcbc 100644 --- a/.globalconfig +++ b/.globalconfig @@ -215,7 +215,7 @@ dotnet_diagnostic.CA1070.severity = warning # CA1200: Avoid using cref tags with a prefix # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1200 -dotnet_diagnostic.CA1200.severity = silent +dotnet_diagnostic.CA1200.severity = warning # CA1303: Do not pass literals as localized parameters # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1303 From fde5305e84d0865cc8090d8d943a5475bdaf360b Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 27 Oct 2025 04:12:53 +0000 Subject: [PATCH 162/378] Enable analyzers: Use char overload (#26301) --- .globalconfig | 12 ++++++++++++ .../commands/management/ControlPanelItemCommand.cs | 2 +- src/Microsoft.WSMan.Management/ConfigProvider.cs | 2 +- src/ResGen/Program.cs | 2 +- .../engine/NativeCommandParameterBinder.cs | 2 +- .../BenchmarkDotNet.Extensions/CommandLineOptions.cs | 2 +- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.globalconfig b/.globalconfig index d60227efcbc..21ecbc766aa 100644 --- a/.globalconfig +++ b/.globalconfig @@ -522,6 +522,18 @@ dotnet_diagnostic.CA1858.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1860 dotnet_diagnostic.CA1860.severity = warning +# CA1865: Use char overload +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1865 +dotnet_diagnostic.CA1865.severity = warning + +# CA1866: Use char overload +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1866 +dotnet_diagnostic.CA1866.severity = warning + +# CA1867: Use char overload +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1867 +dotnet_diagnostic.CA1867.severity = warning + # CA1868: Unnecessary call to 'Contains' for sets # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1868 dotnet_diagnostic.CA1868.severity = warning diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs index fffb36d2979..3734eb82b0c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ControlPanelItemCommand.cs @@ -300,7 +300,7 @@ internal void GetCategoryMap() foreach (ShellFolderItem category in catItems) { string path = category.Path; - string catNum = path.Substring(path.LastIndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1); + string catNum = path.Substring(path.LastIndexOf('\\') + 1); CategoryMap.Add(catNum, category.Name); } diff --git a/src/Microsoft.WSMan.Management/ConfigProvider.cs b/src/Microsoft.WSMan.Management/ConfigProvider.cs index f1fc3a36277..55141379faa 100644 --- a/src/Microsoft.WSMan.Management/ConfigProvider.cs +++ b/src/Microsoft.WSMan.Management/ConfigProvider.cs @@ -62,7 +62,7 @@ public sealed class WSManConfigProvider : NavigationCmdletProvider, ICmdletProvi string ICmdletProviderSupportsHelp.GetHelpMaml(string helpItemName, string path) { // Get the leaf node from the path for which help is requested. - int ChildIndex = path.LastIndexOf("\\", StringComparison.OrdinalIgnoreCase); + int ChildIndex = path.LastIndexOf('\\'); if (ChildIndex == -1) { // Means we are at host level, where no new-item is supported. Return empty string. diff --git a/src/ResGen/Program.cs b/src/ResGen/Program.cs index 3359226a99e..a69fd05e64f 100644 --- a/src/ResGen/Program.cs +++ b/src/ResGen/Program.cs @@ -52,7 +52,7 @@ public static void Main(string[] args) if (className.StartsWith("public.", StringComparison.InvariantCultureIgnoreCase)) { accessModifier = "public"; - className = className.Substring(className.IndexOf(".") + 1); + className = className.Substring(className.IndexOf('.') + 1); } string sourceCode = GetStronglyTypeCsFileForResx(resxPath, moduleName, className, accessModifier); diff --git a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs index 4115546a758..2e62274ee53 100644 --- a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs +++ b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs @@ -161,7 +161,7 @@ internal string[] ArgumentList /// The value used with parameter. internal void AddToArgumentList(CommandParameterInternal parameter, string argument) { - if (parameter.ParameterNameSpecified && parameter.ParameterText.EndsWith(":")) + if (parameter.ParameterNameSpecified && parameter.ParameterText.EndsWith(':')) { if (argument != parameter.ParameterText) { diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/CommandLineOptions.cs b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/CommandLineOptions.cs index aa60c7cc2e6..48856632317 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/CommandLineOptions.cs +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/CommandLineOptions.cs @@ -37,7 +37,7 @@ public static List ParseAndRemoveStringsParameter(List argsList, if (parameterIndex + 1 < argsList.Count) { - while (parameterIndex + 1 < argsList.Count && !argsList[parameterIndex + 1].StartsWith("-")) + while (parameterIndex + 1 < argsList.Count && !argsList[parameterIndex + 1].StartsWith('-')) { // remove each filter string and stop when we get to the next argument flag parameterValue.Add(argsList[parameterIndex + 1]); From 0e1019ff31fc45ddcf1d766bded6b05ced74791b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:45:59 -0700 Subject: [PATCH 163/378] Bump actions/upload-artifact from 4 to 5 (#26309) --- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-packaging-reusable.yml | 2 +- .github/workflows/xunit-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f612ed0e22a..35a9301eae4 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index a48e071e7a1..0afa912273c 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -80,7 +80,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index c80ee40d039..efd05b76045 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -46,7 +46,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: always() with: name: ${{ inputs.test_results_artifact_name }} From ba02868d0fa1d724fcde39e612534d3db693eb39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:46:22 -0700 Subject: [PATCH 164/378] Bump github/codeql-action from 4.30.9 to 4.31.0 (#26308) --- .github/workflows/linux-ci.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 18defb738e2..a2a8fc4c79e 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -188,7 +188,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -214,7 +214,7 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 35a9301eae4..ffd2f3f1420 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v3.29.5 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 with: sarif_file: results.sarif From be195a4c22c61321387e1460b5f58fa0a643d0bd Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Tue, 28 Oct 2025 16:28:44 +0000 Subject: [PATCH 165/378] Avoid regex for exact word matching in `DscClassCache` (#26306) --- .../DscSupport/CimDSCParser.cs | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/System.Management.Automation/DscSupport/CimDSCParser.cs b/src/System.Management.Automation/DscSupport/CimDSCParser.cs index 417f1931c8a..283ec1bcad8 100644 --- a/src/System.Management.Automation/DscSupport/CimDSCParser.cs +++ b/src/System.Management.Automation/DscSupport/CimDSCParser.cs @@ -525,9 +525,6 @@ public DscClassCacheEntry(DSCResourceRunAsCredential aDSCResourceRunAsCredential public static class DscClassCache { private const string InboxDscResourceModulePath = "WindowsPowershell\\v1.0\\Modules\\PsDesiredStateConfiguration"; - private const string reservedDynamicKeywords = "^(Synchronization|Certificate|IIS|SQL)$"; - - private const string reservedProperties = "^(Require|Trigger|Notify|Before|After|Subscribe)$"; private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("DSC", "DSC Class Cache"); @@ -1264,13 +1261,6 @@ public static void ValidateInstanceText(string instanceText) parser.ValidateInstanceText(instanceText); } - private static bool IsMagicProperty(string propertyName) - { - return System.Text.RegularExpressions.Regex.Match(propertyName, - "^(ResourceId|SourceInfo|ModuleName|ModuleVersion|ConfigurationName)$", - System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success; - } - private static string GetFriendlyName(CimClass cimClass) { try @@ -1367,7 +1357,8 @@ private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Versi // // Skip all of the base, meta, registration and other classes that are not intended to be used directly by a script author // - if (System.Text.RegularExpressions.Regex.Match(keywordString, "^OMI_Base|^OMI_.*Registration", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) + if (keywordString.StartsWith("OMI_Base", StringComparison.OrdinalIgnoreCase) || + (keywordString.StartsWith("OMI_", StringComparison.OrdinalIgnoreCase) && keywordString.IndexOf("Registration", 4, StringComparison.OrdinalIgnoreCase) >= 0)) { return null; } @@ -1383,7 +1374,7 @@ private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Versi }; // If it's one of reserved dynamic keyword, mark it - if (System.Text.RegularExpressions.Regex.Match(keywordString, reservedDynamicKeywords, System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) + if (IsReservedDynamicKeyword(keywordString)) { keyword.IsReservedKeyword = true; } @@ -1441,7 +1432,7 @@ private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Versi } } // If it's one of our reserved properties, save it for error reporting - if (System.Text.RegularExpressions.Regex.Match(prop.Name, reservedProperties, System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) + if (IsReservedProperty(prop.Name)) { keyword.HasReservedProperties = true; continue; @@ -1540,6 +1531,27 @@ private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Versi UpdateKnownRestriction(keyword); return keyword; + + static bool IsMagicProperty(string propertyName) => + string.Equals(propertyName, "ResourceId", StringComparison.OrdinalIgnoreCase) || + string.Equals(propertyName, "SourceInfo", StringComparison.OrdinalIgnoreCase) || + string.Equals(propertyName, "ModuleName", StringComparison.OrdinalIgnoreCase) || + string.Equals(propertyName, "ModuleVersion", StringComparison.OrdinalIgnoreCase) || + string.Equals(propertyName, "ConfigurationName", StringComparison.OrdinalIgnoreCase); + + static bool IsReservedDynamicKeyword(string keyword) => + string.Equals(keyword, "Synchronization", StringComparison.OrdinalIgnoreCase) || + string.Equals(keyword, "Certificate", StringComparison.OrdinalIgnoreCase) || + string.Equals(keyword, "IIS", StringComparison.OrdinalIgnoreCase) || + string.Equals(keyword, "SQL", StringComparison.OrdinalIgnoreCase); + + static bool IsReservedProperty(string name) => + string.Equals(name, "Require", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "Trigger", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "Notify", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "Before", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "After", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "Subscribe", StringComparison.OrdinalIgnoreCase); } /// From d13cdadd9629a1364d522a5ded4293a16edfdd0b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:30:29 -0700 Subject: [PATCH 166/378] Fix linux_packaging job being skipped when only packaging files change (#26315) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../infrastructure/path-filters/action.yml | 6 +- .../actions/test/linux-packaging/action.yml | 59 +------- .../build-and-packaging-steps.instructions.md | 127 ++++++++++++++++++ .github/workflows/linux-ci.yml | 1 - 4 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 .github/instructions/build-and-packaging-steps.instructions.md diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 09ed7c22d17..ff07c4510fc 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -88,12 +88,14 @@ runs: const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); - const packagingChanged = files.some(file => + const packagingChanged = files.some(file => file.filename === '.github/workflows/windows-ci.yml' || + file.filename === '.github/workflows/linux-ci.yml' || file.filename.startsWith('assets/wix/') || file.filename === 'PowerShell.Common.props' || file.filename.match(/^src\/.*\.csproj$/) || file.filename.startsWith('test/packaging/windows/') || + file.filename.startsWith('test/packaging/linux/') || file.filename.startsWith('tools/packaging/') || file.filename.startsWith('tools/wix/') ) || @@ -112,7 +114,7 @@ runs: core.setOutput('globalConfigChanged', globalConfigChanged); core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); - + - name: Capture outputs run: | diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b7bbdf37185..374205f2a56 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -13,68 +13,19 @@ runs: with: global-json-file: ./global.json - - name: Download Build Artifacts - uses: actions/download-artifact@v4 - with: - name: build - path: "${{ runner.workspace }}/build" - - - name: Capture Artifacts Directory - continue-on-error: true - run: Get-ChildItem "${{ runner.workspace }}/build/*" -Recurse - shell: pwsh - - name: Bootstrap run: |- Import-Module ./build.psm1 Start-PSBootstrap -Scenario Package - Write-Verbose -Verbose "Start Sync-PSTags" - Sync-PSTags -AddRemoteIfMissing - Write-Verbose -Verbose "End Sync-PSTags" - shell: pwsh - - - name: Extract Build ZIP - run: |- - $destinationFolder = "${{ runner.workspace }}/bins" - $archiveFile = "${{ runner.workspace }}/build/build.zip" - - Write-Verbose "Extracting $archiveFile to $destinationFolder" -Verbose - New-Item -ItemType Directory -Path $destinationFolder -Force | Out-Null - Expand-Archive -Path $archiveFile -DestinationPath $destinationFolder -Force - shell: pwsh - - - name: Fix permissions - continue-on-error: true - run: |- - find "${{ runner.workspace }}/bins" -type d -exec chmod +rwx {} \; - find "${{ runner.workspace }}/bins" -type f -exec chmod +rw {} \; - shell: bash - - - name: Capture Extracted Build ZIP - continue-on-error: true - run: Get-ChildItem "${{ runner.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser shell: pwsh - - name: Create Packages - env: - BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ runner.workspace }}/packages + - name: Build and Package run: |- - # Create the artifacts staging directory - New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null - - # Import packaging module to ensure RPM packaging changes are loaded - Import-Module ./build.psm1 -Force - Import-Module ./tools/packaging/packaging.psm1 -Force Import-Module ./tools/ci.psm1 - Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' - $options = (Get-PSOptions) - $rootPath = '${{ runner.workspace }}/bins' - $originalRootPath = Split-Path -path $options.Output - $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) - $pwshPath = Join-Path -path $path -ChildPath 'pwsh' - chmod a+x $pwshPath - $options.Output = $pwshPath - Set-PSOptions $options + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag Invoke-CIFinish shell: pwsh diff --git a/.github/instructions/build-and-packaging-steps.instructions.md b/.github/instructions/build-and-packaging-steps.instructions.md new file mode 100644 index 00000000000..934b1539593 --- /dev/null +++ b/.github/instructions/build-and-packaging-steps.instructions.md @@ -0,0 +1,127 @@ +--- +applyTo: + - ".github/actions/**/*.yml" + - ".github/workflows/**/*.yml" +--- + +# Build and Packaging Steps Pattern + +## Important Rule + +**Build and packaging must run in the same step OR you must save and restore PSOptions between steps.** + +## Why This Matters + +When `Start-PSBuild` runs, it creates PSOptions that contain build configuration details (runtime, configuration, output path, etc.). The packaging functions like `Start-PSPackage` and `Invoke-CIFinish` rely on these PSOptions to know where the build output is located and how it was built. + +GitHub Actions steps run in separate PowerShell sessions. This means PSOptions from one step are not available in the next step. + +## Pattern 1: Combined Build and Package (Recommended) + +Run build and packaging in the same step to keep PSOptions in memory: + +```yaml +- name: Build and Package + run: |- + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag + Invoke-CIFinish + shell: pwsh +``` + +**Benefits:** +- Simpler code +- No need for intermediate files +- PSOptions automatically available to packaging + +## Pattern 2: Separate Steps with Save/Restore + +If you must separate build and packaging into different steps: + +```yaml +- name: Build PowerShell + run: |- + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag + Save-PSOptions -PSOptionsPath "${{ runner.workspace }}/psoptions.json" + shell: pwsh + +- name: Create Packages + run: |- + Import-Module ./tools/ci.psm1 + Restore-PSOptions -PSOptionsPath "${{ runner.workspace }}/psoptions.json" + Invoke-CIFinish + shell: pwsh +``` + +**When to use:** +- When you need to run other steps between build and packaging +- When build and packaging require different permissions or environments + +## Common Mistakes + +### ❌ Incorrect: Separate steps without save/restore + +```yaml +- name: Build PowerShell + run: |- + Start-PSBuild -Configuration 'Release' + shell: pwsh + +- name: Create Packages + run: |- + Invoke-CIFinish # ❌ FAILS: PSOptions not available + shell: pwsh +``` + +### ❌ Incorrect: Using artifacts without PSOptions + +```yaml +- name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + name: build + +- name: Create Packages + run: |- + Invoke-CIFinish # ❌ FAILS: PSOptions not restored + shell: pwsh +``` + +## Related Functions + +- `Start-PSBuild` - Builds PowerShell and sets PSOptions +- `Save-PSOptions` - Saves PSOptions to a JSON file +- `Restore-PSOptions` - Loads PSOptions from a JSON file +- `Get-PSOptions` - Gets current PSOptions +- `Set-PSOptions` - Sets PSOptions +- `Start-PSPackage` - Creates packages (requires PSOptions) +- `Invoke-CIFinish` - Calls packaging (requires PSOptions on Linux/macOS) + +## Examples + +### Linux Packaging Action + +```yaml +- name: Build and Package + run: |- + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag + Invoke-CIFinish + shell: pwsh +``` + +### Windows Packaging Workflow + +```yaml +- name: Build and Package + run: | + Import-Module .\tools\ci.psm1 + Invoke-CIFinish -Runtime ${{ matrix.runtimePrefix }}-${{ matrix.architecture }} -channel ${{ matrix.channel }} + shell: pwsh +``` + +Note: `Invoke-CIFinish` for Windows includes both build and packaging in its logic when `Stage` contains 'Build'. diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index a2a8fc4c79e..55cf112ea43 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -233,7 +233,6 @@ jobs: linux_packaging: name: Linux Packaging needs: - - ci_build - changes if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: ubuntu-latest From 5e5e17766be554173b18ae8faf243b6d905ce2ff Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 16:23:38 -0400 Subject: [PATCH 167/378] Refactor analyze job to reusable workflow and enable on Windows CI (#26322) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 76 ++++++++++++++++++++++++++ .github/workflows/linux-ci.yml | 63 +++------------------ .github/workflows/windows-ci.yml | 12 ++++ tools/ci.psm1 | 7 ++- 4 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/analyze-reusable.yml diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml new file mode 100644 index 00000000000..1797e2234a6 --- /dev/null +++ b/.github/workflows/analyze-reusable.yml @@ -0,0 +1,76 @@ +name: CodeQL Analysis (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for CodeQL analysis' + type: string + required: false + default: ubuntu-latest + +permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + +jobs: + analyze: + name: Analyze + runs-on: ${{ inputs.runner_os }} + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['csharp'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: '0' + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + name: Capture Environment + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + name: Bootstrap + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIBuild -Configuration 'StaticAnalysis' + name: Build + shell: pwsh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 55cf112ea43..1650638be8e 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -158,63 +158,16 @@ jobs: test_results_artifact_name: testResults-xunit analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/analyze to upload SARIF results - name: Analyze - runs-on: ubuntu-latest + name: CodeQL Analysis needs: changes if: ${{ needs.changes.outputs.source == 'true' }} - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: '0' - - - uses: actions/setup-dotnet@v5 - with: - global-json-file: ./global.json - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - name: Capture Environment - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIInstall -SkipUser - name: Bootstrap - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIBuild - name: Build - shell: pwsh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: ./.github/workflows/analyze-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + runner_os: ubuntu-latest ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index e3fbe7f7185..f33f1a3f589 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -156,6 +156,17 @@ jobs: with: runner_os: windows-latest test_results_artifact_name: testResults-xunit + analyze: + name: CodeQL Analysis + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} + uses: ./.github/workflows/analyze-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + runner_os: windows-latest windows_packaging: name: Windows Packaging needs: @@ -170,6 +181,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - analyze - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 9e95e68c843..44651c26109 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -101,6 +101,11 @@ function Invoke-CIFull # Implements the CI 'build_script' step function Invoke-CIBuild { + param( + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis')] + [string]$Configuration = 'Release' + ) + $releaseTag = Get-ReleaseTag # check to be sure our test tags are correct $result = Get-PesterTag @@ -115,7 +120,7 @@ function Invoke-CIBuild Start-PSBuild -Configuration 'CodeCoverage' -PSModuleRestore -CI -ReleaseTag $releaseTag } - Start-PSBuild -PSModuleRestore -Configuration 'Release' -CI -ReleaseTag $releaseTag -UseNuGetOrg + Start-PSBuild -PSModuleRestore -Configuration $Configuration -CI -ReleaseTag $releaseTag -UseNuGetOrg Save-PSOptions $options = (Get-PSOptions) From 47e8e900ab5e156405a926c4e9916f029f90d290 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:09:26 -0700 Subject: [PATCH 168/378] Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26268) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk --- .../build-configuration-guide.instructions.md | 48 ++- .../start-native-execution.instructions.md | 149 ++++++++ .github/workflows/macos-ci.yml | 55 ++- docs/maintainers/releasing.md | 17 +- tools/packaging/packaging.psm1 | 360 ++++++++++++++---- .../releaseTests/macOSPackage.tests.ps1 | 162 ++++++++ 6 files changed, 705 insertions(+), 86 deletions(-) create mode 100644 .github/instructions/start-native-execution.instructions.md create mode 100644 tools/packaging/releaseTests/macOSPackage.tests.ps1 diff --git a/.github/instructions/build-configuration-guide.instructions.md b/.github/instructions/build-configuration-guide.instructions.md index 848aacef496..56844777d95 100644 --- a/.github/instructions/build-configuration-guide.instructions.md +++ b/.github/instructions/build-configuration-guide.instructions.md @@ -35,13 +35,15 @@ applyTo: ### For Release/Packaging -**Use: Release with version tag** +**Use: Release with version tag and public NuGet feeds** ```yaml - name: Build for Release shell: pwsh run: | + Import-Module ./build.psm1 Import-Module ./tools/ci.psm1 + Switch-PSNugetConfig -Source Public $releaseTag = Get-ReleaseTag Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag ``` @@ -51,6 +53,11 @@ applyTo: - No debug symbols (smaller size) - Production-ready +**Why Switch-PSNugetConfig -Source Public:** +- Switches NuGet package sources to public feeds (nuget.org and public Azure DevOps feeds) +- Required for CI/CD environments that don't have access to private feeds +- Uses publicly available packages instead of Microsoft internal feeds + ### For Code Coverage **Use: CodeCoverage configuration** @@ -101,3 +108,42 @@ src/powershell-win-core/bin/Debug///publish/ 3. Match configuration to purpose 4. Use `-CI` only when needed 5. Always specify `-ReleaseTag` for release or packaging builds +6. Use `Switch-PSNugetConfig -Source Public` in CI/CD for release builds + +## NuGet Feed Configuration + +### Switch-PSNugetConfig + +The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source configuration. + +**Available Sources:** + +- **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) + - Required for: CI/CD environments, public builds, packaging + - Does not require authentication + +- **Private**: Uses internal PowerShell team feeds + - Required for: Internal development with preview packages + - Requires authentication credentials + +- **NuGetOnly**: Uses only nuget.org + - Required for: Minimal dependency scenarios + +**Usage:** + +```powershell +# Switch to public feeds (most common for CI/CD) +Switch-PSNugetConfig -Source Public + +# Switch to private feeds with authentication +Switch-PSNugetConfig -Source Private -UserName $userName -ClearTextPAT $pat + +# Switch to nuget.org only +Switch-PSNugetConfig -Source NuGetOnly +``` + +**When to Use:** + +- **Always use `-Source Public`** before building in CI/CD workflows +- Use before any build that will create packages for distribution +- Use in forks or environments without access to Microsoft internal feeds diff --git a/.github/instructions/start-native-execution.instructions.md b/.github/instructions/start-native-execution.instructions.md new file mode 100644 index 00000000000..347e496b3bf --- /dev/null +++ b/.github/instructions/start-native-execution.instructions.md @@ -0,0 +1,149 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# Using Start-NativeExecution for Native Command Execution + +## Purpose + +`Start-NativeExecution` is the standard function for executing native commands (external executables) in PowerShell scripts within this repository. It provides consistent error handling and better diagnostics when native commands fail. + +## When to Use + +Use `Start-NativeExecution` whenever you need to: +- Execute external commands (e.g., `git`, `dotnet`, `pkgbuild`, `productbuild`, `fpm`, `rpmbuild`) +- Ensure proper exit code checking +- Get better error messages with caller information +- Handle verbose output on error + +## Basic Usage + +```powershell +Start-NativeExecution { + git clone https://github.com/PowerShell/PowerShell.git +} +``` + +## With Parameters + +Use backticks for line continuation within the script block: + +```powershell +Start-NativeExecution { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + $outputPath +} +``` + +## Common Parameters + +### -VerboseOutputOnError + +Captures command output and displays it only if the command fails: + +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet build --configuration Release +} +``` + +### -IgnoreExitcode + +Allows the command to fail without throwing an exception: + +```powershell +Start-NativeExecution -IgnoreExitcode { + git diff --exit-code # Returns 1 if differences exist +} +``` + +## Availability + +The function is defined in `tools/buildCommon/startNativeExecution.ps1` and is available in: +- `build.psm1` (dot-sourced automatically) +- `tools/packaging/packaging.psm1` (dot-sourced automatically) +- Test modules that include `HelpersCommon.psm1` + +To use in other scripts, dot-source the function: + +```powershell +. "$PSScriptRoot/../buildCommon/startNativeExecution.ps1" +``` + +## Error Handling + +When a native command fails (non-zero exit code), `Start-NativeExecution`: +1. Captures the exit code +2. Identifies the calling location (file and line number) +3. Throws a descriptive error with full context + +Example error message: +``` +Execution of {git clone ...} by /path/to/script.ps1: line 42 failed with exit code 1 +``` + +## Examples from the Codebase + +### Git Operations +```powershell +Start-NativeExecution { + git fetch --tags --quiet upstream +} +``` + +### Build Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet publish --configuration Release +} +``` + +### Packaging Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot --identifier $pkgId --version $version $outputPath +} +``` + +### Permission Changes +```powershell +Start-NativeExecution { + find $staging -type d | xargs chmod 755 + find $staging -type f | xargs chmod 644 +} +``` + +## Anti-Patterns + +**Don't do this:** +```powershell +& somecommand $args +if ($LASTEXITCODE -ne 0) { + throw "Command failed" +} +``` + +**Do this instead:** +```powershell +Start-NativeExecution { + somecommand $args +} +``` + +## Best Practices + +1. **Always use Start-NativeExecution** for native commands to ensure consistent error handling +2. **Use -VerboseOutputOnError** for commands with useful diagnostic output +3. **Use backticks for readability** when commands have multiple arguments +4. **Don't capture output unnecessarily** - let the function handle it +5. **Use -IgnoreExitcode sparingly** - only when non-zero exit codes are expected and acceptable + +## Related Documentation + +- Source: `tools/buildCommon/startNativeExecution.ps1` +- Blog post: https://mnaoumov.wordpress.com/2015/01/11/execution-of-external-commands-in-powershell-done-right/ diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index b0242a6d212..95edb2b8d96 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -153,7 +153,7 @@ jobs: runner_os: macos-15-large test_results_artifact_name: testResults-xunit PackageMac-macos_packaging: - name: macOS packaging (bootstrap only) + name: macOS packaging and testing needs: - changes if: ${{ needs.changes.outputs.source == 'true' }} @@ -162,12 +162,63 @@ jobs: steps: - name: checkout uses: actions/checkout@v5 + with: + fetch-depth: 1000 + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json - name: Bootstrap packaging - if: success() || failure() + if: success() run: |- import-module ./build.psm1 start-psbootstrap -Scenario package shell: pwsh + - name: Build PowerShell and Create macOS package + if: success() + run: |- + import-module ./build.psm1 + import-module ./tools/ci.psm1 + import-module ./tools/packaging/packaging.psm1 + Switch-PSNugetConfig -Source Public + Sync-PSTags -AddRemoteIfMissing + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration Release -PSModuleRestore -ReleaseTag $releaseTag + $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } + Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks + shell: pwsh + - name: Test package contents + if: success() + run: |- + $env:PACKAGE_FOLDER = Get-Location + $testResultsPath = Join-Path $env:RUNNER_WORKSPACE "testResults" + if (-not (Test-Path $testResultsPath)) { + New-Item -ItemType Directory -Path $testResultsPath -Force | Out-Null + } + Import-Module Pester + $pesterConfig = New-PesterConfiguration + $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.PassThru = $true + $pesterConfig.Output.Verbosity = 'Detailed' + $pesterConfig.TestResult.Enabled = $true + $pesterConfig.TestResult.OutputFormat = 'NUnitXml' + $pesterConfig.TestResult.OutputPath = Join-Path $testResultsPath "macOSPackage.xml" + $result = Invoke-Pester -Configuration $pesterConfig + if ($result.FailedCount -gt 0) { + throw "Package validation failed with $($result.FailedCount) failed test(s)" + } + shell: pwsh + - name: Publish and Upload Pester Test Results + if: always() + uses: "./.github/actions/test/process-pester-results" + with: + name: "macOSPackage" + testResultsFolder: "${{ runner.workspace }}/testResults" + - name: Upload package artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: macos-package + path: "*.pkg" ready_to_merge: name: macos ready to merge needs: diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index 5aae87582c9..3562962e68f 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -72,11 +72,18 @@ The output of `Start-PSBuild` includes a `powershell.exe` executable which can s #### Linux / macOS The `Start-PSPackage` function delegates to `New-UnixPackage`. -It relies on the [Effing Package Management][fpm] project, -which makes building packages for any (non-Windows) platform a breeze. -Similarly, the PowerShell man-page is generated from the Markdown-like file + +For **Linux** (Debian-based distributions), it relies on the [Effing Package Management][fpm] project, +which makes building packages a breeze. + +For **macOS**, it uses native packaging tools (`pkgbuild` and `productbuild`) from Xcode Command Line Tools, +eliminating the need for Ruby or fpm. + +For **Linux** (Red Hat-based distributions), it uses `rpmbuild` directly. + +The PowerShell man-page is generated from the Markdown-like file [`assets/pwsh.1.ronn`][man] using [Ronn][]. -The function `Start-PSBootstrap -Package` will install both these tools. +The function `Start-PSBootstrap -Package` will install these tools. To modify any property of the packages, edit the `New-UnixPackage` function. Please also refer to the function for details on the package properties @@ -131,7 +138,7 @@ Without `-Name` specified, the primary `powershell` package will instead be created. [fpm]: https://github.com/jordansissel/fpm -[man]: ../../assets/pwsh.1.ronn +[man]: ../../assets/manpage/pwsh.1.ronn [ronn]: https://github.com/rtomayko/ronn ### Build and Packaging Examples diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 435fe2d49bc..257b3694510 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. "$PSScriptRoot\..\buildCommon\startNativeExecution.ps1" + $Environment = Get-EnvironmentInformation $RepoRoot = (Resolve-Path -Path "$PSScriptRoot/../..").Path @@ -1197,19 +1199,7 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # there is a weird bug in fpm - # if the target of the powershell symlink exists, `fpm` aborts - # with a `utime` error on macOS. - # so we move it to make symlink broken - # refers to executable, does not vary by channel - $symlink_dest = "$Destination/pwsh" - $hack_dest = "./_fpm_symlink_hack_powershell" - if ($Environment.IsMacOS) { - if (Test-Path $symlink_dest) { - Write-Warning "Move $symlink_dest to $hack_dest (fpm utime bug)" - Start-NativeExecution ([ScriptBlock]::Create("$sudo mv $symlink_dest $hack_dest")) - } - } + # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1329,8 +1319,38 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'osxpkg') { + # Use native macOS packaging tools + if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { + Write-Log "Creating macOS package with native tools..." + + $macPkgArgs = @{ + Name = $Name + Version = $packageVersion + Iteration = $Iteration + Staging = $Staging + Destination = $Destination + ManGzipFile = $ManGzipInfo.GzipFile + ManDestination = $ManGzipInfo.ManFile + LinkInfo = $Links + AfterInstallScript = $AfterScriptInfo.AfterInstallScript + AppsFolder = $AppsFolder + HostArchitecture = $HostArchitecture + CurrentLocation = $CurrentLocation + } + + try { + $packageFile = New-MacOSPackage @macPkgArgs + $Output = @("Created package {:path=>""$($packageFile.Name)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in macOS packaging!!!" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } + } } else { - # Use fpm for DEB and macOS packages + # Use fpm for DEB packages $Arguments = @() $Arguments += Get-FpmArguments ` @@ -1372,12 +1392,6 @@ function New-UnixPackage { { Clear-MacOSLauncher } - - # this is continuation of a fpm hack for a weird bug - if (Test-Path $hack_dest) { - Write-Warning "Move $hack_dest to $symlink_dest (fpm utime bug)" - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError - } } # Clean up rpmbuild directory if it was created @@ -1401,12 +1415,9 @@ function New-UnixPackage { # Magic to get path output $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) - if ($Environment.IsMacOS) { - if ($PSCmdlet.ShouldProcess("Add distribution information and Fix PackageName")) - { - $createdPackage = New-MacOsDistributionPackage -FpmPackage $createdPackage -HostArchitecture $HostArchitecture -IsPreview:$IsPreview - } - } + # For macOS with native tools, the package is already in the correct format + # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage + # For other platforms, the package name from fpm/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1451,14 +1462,27 @@ Function New-LinkInfo function New-MacOsDistributionPackage { + [CmdletBinding(SupportsShouldProcess=$true)] param( - [Parameter(Mandatory,HelpMessage='The FileInfo of the file created by FPM')] - [System.IO.FileInfo]$FpmPackage, + [Parameter(Mandatory,HelpMessage='The FileInfo of the component package')] + [System.IO.FileInfo]$ComponentPackage, + + [Parameter(Mandatory,HelpMessage='Package name for the output file')] + [string]$PackageName, + + [Parameter(Mandatory,HelpMessage='Package version')] + [string]$Version, + + [Parameter(Mandatory,HelpMessage='Output directory for the final package')] + [string]$OutputDirectory, [Parameter(HelpMessage='x86_64 for Intel or arm64 for Apple Silicon')] [ValidateSet("x86_64", "arm64")] [string] $HostArchitecture = "x86_64", + [Parameter(HelpMessage='Package identifier')] + [string]$PackageIdentifier, + [Switch] $IsPreview ) @@ -1467,64 +1491,81 @@ function New-MacOsDistributionPackage throw 'New-MacOsDistributionPackage is only supported on macOS!' } - $packageName = Split-Path -Leaf -Path $FpmPackage - # Create a temp directory to store the needed files $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName()) New-Item -ItemType Directory -Path $tempDir -Force > $null $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - #Copy background file to temp directory + + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" - Copy-Item -Path $backgroundFile -Destination $resourcesDir - # Move the current package to the temp directory - $tempPackagePath = Join-Path -Path $tempDir -ChildPath $packageName - Move-Item -Path $FpmPackage -Destination $tempPackagePath -Force - - # Add the OS information to the macOS package file name. - $packageExt = [System.IO.Path]::GetExtension($FpmPackage.Name) - - # get the package name from fpm without the extension, but replace powershell-preview at the beginning of the name with powershell. - $packageNameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($FpmPackage.Name) -replace '^powershell\-preview' , 'powershell' - - $newPackageName = "{0}-{1}{2}" -f $packageNameWithoutExt, $script:Options.Runtime, $packageExt - $newPackagePath = Join-Path $FpmPackage.DirectoryName $newPackageName - - # -Force is not deleting the NewName if it exists, so delete it if it does - if ($Force -and (Test-Path -Path $newPackagePath)) - { - Remove-Item -Force $newPackagePath + if (Test-Path $backgroundFile) { + Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } + + # Copy the component package to temp directory + $componentFileName = Split-Path -Leaf -Path $ComponentPackage + $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName + Copy-Item -Path $ComponentPackage -Destination $tempComponentPath -Force # Create the distribution xml $distributionXmlPath = Join-Path -Path $tempDir -ChildPath 'powershellDistribution.xml' - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + # Get package ID if not provided + if (-not $PackageIdentifier) { + $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + } + # Minimum OS version + $minOSVersion = "11.0" # macOS Big Sur minimum + # format distribution template with: # 0 - title # 1 - version - # 2 - package path + # 2 - package path (component package filename) # 3 - minimum os version # 4 - Package Identifier # 5 - host architecture (x86_64 for Intel or arm64 for Apple Silicon) - $PackagingStrings.OsxDistributionTemplate -f "PowerShell - $packageVersion", $packageVersion, $packageName, '10.14', $packageId, $HostArchitecture | Out-File -Encoding ascii -FilePath $distributionXmlPath -Force + $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force - Write-Log "Applying distribution.xml to package..." - Push-Location $tempDir - try - { - # productbuild is an xcode command line tool, and those tools are installed when you install brew - Start-NativeExecution -sb {productbuild --distribution $distributionXmlPath --resources $resourcesDir $newPackagePath} -VerboseOutputOnError + # Build final package path + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" + + # Remove existing package if it exists + if (Test-Path $finalPackagePath) { + Write-Warning "Removing existing package: $finalPackagePath" + Remove-Item $finalPackagePath -Force } - finally - { - Pop-Location - Remove-Item -Path $tempDir -Recurse -Force + + if ($PSCmdlet.ShouldProcess("Build product package with productbuild")) { + Write-Log "Applying distribution.xml to package..." + Push-Location $tempDir + try + { + # productbuild is an xcode command line tool + Start-NativeExecution -VerboseOutputOnError { + productbuild --distribution $distributionXmlPath ` + --package-path $tempDir ` + --resources $resourcesDir ` + $finalPackagePath + } + + if (Test-Path $finalPackagePath) { + Write-Log "Successfully created macOS package: $finalPackagePath" + } + else { + throw "Package was not created at expected location: $finalPackagePath" + } + } + finally + { + Pop-Location + Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue + } } - return (Get-Item $newPackagePath) + return (Get-Item $finalPackagePath) } Class LinkInfo @@ -1692,6 +1733,157 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-MacOSPackage +{ + [CmdletBinding(SupportsShouldProcess=$true)] + param( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Version, + + [Parameter(Mandatory)] + [string]$Iteration, + + [Parameter(Mandatory)] + [string]$Staging, + + [Parameter(Mandatory)] + [string]$Destination, + + [Parameter(Mandatory)] + [string]$ManGzipFile, + + [Parameter(Mandatory)] + [string]$ManDestination, + + [Parameter(Mandatory)] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory)] + [string]$AfterInstallScript, + + [Parameter(Mandatory)] + [string]$AppsFolder, + + [Parameter(Mandatory)] + [string]$HostArchitecture, + + [string]$CurrentLocation = (Get-Location) + ) + + Write-Log "Creating macOS package using pkgbuild and productbuild..." + + # Create a temporary directory for package building + $tempRoot = New-TempFolder + $componentPkgPath = Join-Path $tempRoot "component.pkg" + $scriptsDir = Join-Path $tempRoot "scripts" + $resourcesDir = Join-Path $tempRoot "resources" + $distributionFile = Join-Path $tempRoot "distribution.xml" + + try { + # Create scripts directory + New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null + + # Copy and prepare the postinstall script + $postInstallPath = Join-Path $scriptsDir "postinstall" + Copy-Item -Path $AfterInstallScript -Destination $postInstallPath -Force + Start-NativeExecution { + chmod 755 $postInstallPath + } + + # Create a temporary directory for the package root + $pkgRoot = Join-Path $tempRoot "pkgroot" + New-Item -ItemType Directory -Path $pkgRoot -Force | Out-Null + + # Copy staging files to destination path in package root + $destInPkg = Join-Path $pkgRoot $Destination + New-Item -ItemType Directory -Path $destInPkg -Force | Out-Null + Write-Verbose "Copying staging files from $Staging to $destInPkg" -Verbose + Copy-Item -Path "$Staging/*" -Destination $destInPkg -Recurse -Force + + # Create man page directory structure + $manDir = Join-Path $pkgRoot (Split-Path $ManDestination -Parent) + New-Item -ItemType Directory -Path $manDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination (Join-Path $pkgRoot $ManDestination) -Force + + # Create symlinks in package root + # The LinkInfo contains Source (a temp file that IS a symlink) and Destination (where to install it) + foreach ($link in $LinkInfo) { + $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) + New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null + $finalLinkPath = Join-Path $pkgRoot $link.Destination + + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose + + # Remove if exists + if (Test-Path $finalLinkPath) { + Remove-Item $finalLinkPath -Force + } + + # Get the target of the original symlink and recreate it in the package root + if (Test-Path $link.Source) { + $linkTarget = (Get-Item $link.Source).Target + if ($linkTarget) { + Write-Verbose "Creating symlink to target: $linkTarget" -Verbose + New-Item -ItemType SymbolicLink -Path $finalLinkPath -Target $linkTarget -Force | Out-Null + } else { + Write-Warning "Could not determine target for symlink at $($link.Source), copying file instead" + Copy-Item -Path $link.Source -Destination $finalLinkPath -Force + } + } else { + Write-Warning "Source symlink $($link.Source) does not exist" + } + } + + # Copy launcher app folder if provided + if ($AppsFolder) { + $appsInPkg = Join-Path $pkgRoot "Applications" + New-Item -ItemType Directory -Path $appsInPkg -Force | Out-Null + Write-Verbose "Copying launcher app from $AppsFolder to $appsInPkg" -Verbose + Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force + } + + # Build the component package using pkgbuild + $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { + Write-Log "Running pkgbuild to create component package..." + + Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + --install-location "/" ` + $componentPkgPath + } + + Write-Verbose "Component package created: $componentPkgPath" -Verbose + } + + # Create the final distribution package using the refactored function + $distributionPackage = New-MacOsDistributionPackage ` + -ComponentPackage (Get-Item $componentPkgPath) ` + -PackageName $Name ` + -Version $Version ` + -OutputDirectory $CurrentLocation ` + -HostArchitecture $HostArchitecture ` + -PackageIdentifier $pkgIdentifier ` + -IsPreview:($Name -like '*-preview') + + return $distributionPackage + } + finally { + # Clean up temporary directory + if (Test-Path $tempRoot) { + Write-Verbose "Cleaning up temporary directory: $tempRoot" -Verbose + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function Get-FpmArguments { param( @@ -1905,6 +2097,7 @@ function Get-PackageDependencies function Test-Dependencies { # Note: RPM packages no longer require fpm; they use rpmbuild directly + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools # DEB packages still use fpm $Dependencies = @() @@ -1913,22 +2106,31 @@ function Test-Dependencies $Dependencies += "fpm" } + # Check for macOS packaging tools + if ($Environment.IsMacOS) { + $Dependencies += "pkgbuild" + $Dependencies += "productbuild" + } + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath + # For Debian systems, try adding ruby gems to the path + if ($Environment.IsDebianFamily) { + # These tools are not added to the path automatically on OpenSUSE 13.2 + # try adding them to the path and re-tesing first + [string] $gemsPath = $null + [string] $depenencyPath = $null + $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName + if ($gemsPath) { + $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName + $originalPath = $env:PATH + $env:PATH = $ENV:PATH +":" + $depenencyPath + if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { + continue + } + else { + $env:PATH = $originalPath + } } } @@ -2086,10 +2288,12 @@ function New-MacOSLauncher # Set permissions for plist and shell script. Start-NativeExecution { chmod 644 $plist + } + Start-NativeExecution { chmod 755 $shellscript } - # Add app folder to fpm paths. + # Return the app folder path for packaging $appsfolder = (Resolve-Path -Path "$macosapp/..").Path return $appsfolder diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/tools/packaging/releaseTests/macOSPackage.tests.ps1 new file mode 100644 index 00000000000..c1de1091562 --- /dev/null +++ b/tools/packaging/releaseTests/macOSPackage.tests.ps1 @@ -0,0 +1,162 @@ +Describe "Verify macOS Package" { + BeforeAll { + Write-Verbose "In Describe BeforeAll" -Verbose + Import-Module $PSScriptRoot/../../../build.psm1 + + # Find the macOS package + $packagePath = $env:PACKAGE_FOLDER + if (-not $packagePath) { + $packagePath = Get-Location + } + + Write-Verbose "Looking for package in: $packagePath" -Verbose + $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 + + if (-not $package) { + Write-Warning "No .pkg file found in $packagePath" + } else { + Write-Verbose "Found package: $($package.FullName)" -Verbose + } + + # Set up test directories + $script:package = $package + $script:expandDir = $null + $script:payloadDir = $null + $script:extractedFiles = @() + + if ($package) { + # Use TestDrive for temporary directories - pkgutil will create the expand directory + $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" + $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" + + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose + # pkgutil will create the directory itself, so don't pre-create it + Start-NativeExecution { + pkgutil --expand $package.FullName $script:expandDir + } + + # Extract the payload to verify files + $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" + $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" + + # Create payload directory since cpio needs it + if (-not (Test-Path $script:payloadDir)) { + $null = New-Item -ItemType Directory -Path $script:payloadDir -Force + } + + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 + if ($componentPkg) { + Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose + Push-Location $script:payloadDir + try { + $payloadFile = Join-Path $componentPkg.FullName "Payload" + Get-Content -Path $payloadFile -Raw -AsByteStream | & cpio -i 2>&1 | Out-Null + } finally { + Pop-Location + } + } + + # Get all extracted files for verification + $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue + Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose + } + } + + AfterAll { + # TestDrive automatically cleans up, but we can ensure cleanup happens + # No manual cleanup needed as TestDrive handles it + } + + Context "Package existence and structure" { + It "Package file should exist" { + $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" + $script:package.Extension | Should -Be ".pkg" + } + + It "Package should expand successfully" { + $script:expandDir | Should -Exist + Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty + } + + It "Package should have a component package" { + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue + $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" + } + + It "Payload should extract successfully" { + $script:payloadDir | Should -Exist + $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" + } + } + + Context "Required files in package" { + BeforeAll { + $expectedFilePatterns = @{ + "PowerShell executable" = "usr/local/microsoft/powershell/*/pwsh" + "PowerShell symlink in /usr/local/bin" = "usr/local/bin/pwsh*" + "Man page" = "usr/local/share/man/man1/pwsh*.gz" + "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" + } + + $testCases = @() + foreach ($key in $expectedFilePatterns.Keys) { + $testCases += @{ + Description = $key + Pattern = $expectedFilePatterns[$key] + } + } + + $script:testCases = $testCases + } + + It "Should contain " -TestCases $script:testCases { + param($Description, $Pattern) + + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } + $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" + } + } + + Context "PowerShell binary verification" { + It "PowerShell executable should be executable" { + $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } + $pwshBinary | Should -Not -BeNullOrEmpty + + # Check if file has executable permissions (on Unix-like systems) + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode + # Executable bit should be set + $permissions.ToString() | Should -Match 'x' -Because "pwsh binary should have execute permissions" + } + } + } + + Context "Launcher application" { + It "Launcher app should have proper bundle structure" { + $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } + $plistFile | Should -Not -BeNullOrEmpty + + # Verify the bundle has required components + $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent + $macOSDir = Join-Path $appPath "Contents/MacOS" + $resourcesDir = Join-Path $appPath "Contents/Resources" + + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" + Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" + } + + It "Launcher script should exist and be executable" { + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + } + $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" + + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode + $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" + } + } + } +} From 7e1ef1f7448beabfc6292e1b97bc97512726438c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 16:39:28 -0700 Subject: [PATCH 169/378] Replace `fpm` with `dpkg-deb` for DEB package generation (#26281) --- build.psm1 | 76 +-- .../linux/package-validation.tests.ps1 | 48 +- tools/packaging/packaging.psm1 | 462 ++++++++++-------- 3 files changed, 315 insertions(+), 271 deletions(-) diff --git a/build.psm1 b/build.psm1 index 1b56d9d545d..e4e1a1f69f2 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2234,43 +2234,6 @@ function Get-RedHatPackageManager { } } -function Install-GlobalGem { - param( - [Parameter()] - [string] - $Sudo = "", - - [Parameter(Mandatory)] - [string] - $GemName, - - [Parameter(Mandatory)] - [string] - $GemVersion - ) - try { - # We cannot guess if the user wants to run gem install as root on linux and windows, - # but macOs usually requires sudo - $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { - $gemsudo = $sudo - } - - Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install $GemName -v $GemVersion --no-document")) - - } catch { - Write-Warning "Installation of gem $GemName $GemVersion failed! Must resolve manually." - $logs = Get-ChildItem "/var/lib/gems/*/extensions/x86_64-linux/*/$GemName-*/gem_make.out" | Select-Object -ExpandProperty FullName - foreach ($log in $logs) { - Write-Verbose "Contents of: $log" -Verbose - Get-Content -Raw -Path $log -ErrorAction Ignore | ForEach-Object { Write-Verbose $_ -Verbose } - Write-Verbose "END Contents of: $log" -Verbose - } - - throw - } -} - function Start-PSBootstrap { [CmdletBinding()] param( @@ -2282,7 +2245,7 @@ function Start-PSBootstrap { [switch]$BuildLinuxArm, [switch]$Force, [Parameter(Mandatory = $true)] - # Package: Install dependencies for packaging tools (fpm, rpmbuild, WiX) + # Package: Install dependencies for packaging tools (rpmbuild, dpkg-deb, pkgbuild, WiX) # DotNet: Install the .NET SDK # Both: Package and DotNet scenarios # Tools: Install .NET global tools (e.g., dotnet-format) @@ -2321,7 +2284,9 @@ function Start-PSBootstrap { elseif ($environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" } + # Note: ruby-dev, libffi-dev, g++, and make are no longer needed for DEB packaging + # DEB packages now use native dpkg-deb (pre-installed) + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "groff", "rpm" } # Install dependencies # change the fontend from apt-get to noninteractive @@ -2345,7 +2310,9 @@ function Start-PSBootstrap { $Deps += "libicu", "openssl-libs" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" } + # Note: ruby-devel and libffi-devel are no longer needed + # RPM packages use rpmbuild, DEB packages use dpkg-deb + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpm-build", "groff" } $PackageManager = Get-RedHatPackageManager @@ -2366,7 +2333,8 @@ function Start-PSBootstrap { $Deps += "wget" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" } + # Note: ruby-devel and libffi-devel are no longer needed for packaging + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpmbuild", "groff" } $PackageManager = "zypper --non-interactive install" $baseCommand = "$sudo $PackageManager" @@ -2405,17 +2373,7 @@ function Start-PSBootstrap { } } - # Install [fpm](https://github.com/jordansissel/fpm) - # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly if ($Scenario -in 'All', 'Both', 'Package') { - # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) - if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" - } - # For RPM-based systems, ensure rpmbuild is available if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for rpmbuild..." @@ -2424,6 +2382,22 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } + + # For Debian-based systems and Mariner, ensure dpkg-deb is available + if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for dpkg-deb..." + if (!(Get-Command dpkg-deb -ErrorAction SilentlyContinue)) { + Write-Warning "dpkg-deb not found. Installing dpkg package..." + if ($environment.IsMariner) { + # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y azurelinux-repos-extended")) -IgnoreExitcode + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y dpkg")) -IgnoreExitcode + } else { + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode + } + } + } } } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 index 241863de45d..594a729fa77 100644 --- a/test/packaging/linux/package-validation.tests.ps1 +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -21,10 +21,7 @@ Describe "Linux Package Name Validation" { It "Should have valid RPM package names" { $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue - if ($rpmPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" - return - } + $rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory" $invalidPackages = @() # Regex pattern for valid RPM package names. @@ -49,8 +46,42 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } + } + } + + Context "DEB Package Names" { + It "Should have valid DEB package names" { + $debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue + + $debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory" + + $invalidPackages = @() + # Regex pattern for valid DEB package names. + # Valid examples: + # - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb + # - powershell-lts_7.4.13-1.deb_amd64.deb + # - powershell_7.4.13-1.deb_amd64.deb + # Breakdown: + # ^powershell : Starts with 'powershell' + # (-preview|-lts)? : Optionally '-preview' or '-lts' + # _\d+\.\d+\.\d+ : Underscore followed by version number (e.g., _7.6.0) + # (-[a-z]+\.\d+)? : Optional dash, letters, dot, and digits (e.g., -preview.6) + # -1 : Literal '-1' + # \.deb_ : Literal '.deb_' + # (amd64|arm64) : Architecture + # \.deb$ : File extension + $debPackageNamePattern = '^powershell(-preview|-lts)?_\d+\.\d+\.\d+(-[a-z]+\.\d+)?-1\.deb_(amd64|arm64)\.deb$' + + foreach ($package in $debPackages) { + if ($package.Name -notmatch $debPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid DEB package name" + Write-Warning "$($package.Name) is not a valid DEB package name" + } + } - $rpmPackages.Count | Should -BeGreaterThan 0 + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } } } @@ -58,10 +89,7 @@ Describe "Linux Package Name Validation" { It "Should have valid tar.gz package names" { $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue - if ($tarPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" - return - } + $tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory" $invalidPackages = @() foreach ($package in $tarPackages) { @@ -76,8 +104,6 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } - - $tarPackages.Count | Should -BeGreaterThan 0 } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 257b3694510..ccdc4e1cf08 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1199,8 +1199,6 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools - # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1319,6 +1317,33 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'deb') { + # Use native DEB package builder + if ($PSCmdlet.ShouldProcess("Create DEB package natively")) { + Write-Log "Creating DEB package natively..." + try { + $result = New-NativeDeb ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -HostArchitecture $HostArchitecture ` + -CurrentLocation $CurrentLocation + + $Output = @("Created package {:path=>""$($result.PackageName)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in native DEB creation!!!" -Verbose -ErrorAction SilentlyContinue + } + } } elseif ($Type -eq 'osxpkg') { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { @@ -1350,40 +1375,8 @@ function New-UnixPackage { } } } else { - # Use fpm for DEB packages - $Arguments = @() - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } - } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw - } - } + # Nothing should reach here + throw "Unknown package type: $Type" } } finally { if ($Environment.IsMacOS) { @@ -1416,8 +1409,7 @@ function New-UnixPackage { $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) # For macOS with native tools, the package is already in the correct format - # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage - # For other platforms, the package name from fpm/rpmbuild is sufficient + # For other platforms, the package name from dpkg-deb/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1695,8 +1687,8 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination foreach ($link in $LinkInfo) { $linkDir = Split-Path -Parent $link.Destination $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" - # For RPM, we copy the symlink itself (which fpm does by including it in the source) - # The symlink at $link.Source points to the actual target, so we'll copy it + # For RPM, we copy the symlink itself. + # The symlink at $link.Source points to the actual target, so we'll copy it. # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" } @@ -1733,6 +1725,217 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-NativeDeb +{ + param( + [Parameter(Mandatory, HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory, HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory, HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory, HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory, HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory, HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory, HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory, HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(HelpMessage='Packages required to install this package.')] + [String[]]$Dependencies, + + [Parameter(HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [string]$HostArchitecture, + + [string]$CurrentLocation + ) + + Write-Log "Creating native DEB package..." + + # Create temporary build directory + $debBuildRoot = Join-Path $env:HOME "debbuild-$(Get-Random)" + $debianDir = Join-Path $debBuildRoot "DEBIAN" + $dataDir = Join-Path $debBuildRoot "data" + + try { + New-Item -ItemType Directory -Path $debianDir -Force | Out-Null + New-Item -ItemType Directory -Path $dataDir -Force | Out-Null + + # Calculate installed size (in KB) + $installedSize = 0 + Get-ChildItem -Path $Staging -Recurse -File | ForEach-Object { $installedSize += $_.Length } + $installedSize += (Get-Item $ManGzipFile).Length + $installedSizeKB = [Math]::Ceiling($installedSize / 1024) + + # Create control file with all fields in proper order + # Description must be single line (first line) followed by extended description with leading space + $descriptionLines = $Description -split "`n" + $shortDescription = $descriptionLines[0] + $extendedDescription = if ($descriptionLines.Count -gt 1) { + ($descriptionLines[1..($descriptionLines.Count-1)] | ForEach-Object { " $_" }) -join "`n" + } + + $controlContent = @" +Package: $Name +Version: $Version-$Iteration +Architecture: $HostArchitecture +Maintainer: PowerShell Team +Installed-Size: $installedSizeKB +Priority: optional +Section: shells +Homepage: https://microsoft.com/powershell +Depends: $(if ($Dependencies) { $Dependencies -join ', ' }) +Description: $shortDescription +$(if ($extendedDescription) { $extendedDescription + "`n" }) +"@ + + $controlFile = Join-Path $debianDir "control" + $controlContent | Out-File -FilePath $controlFile -Encoding ascii -NoNewline + + Write-Verbose "Control file created: $controlFile" -Verbose + Write-LogGroup -Title "DEB Control File Content" -Message $controlContent + + # Copy postinst script if provided + if ($AfterInstallScript -and (Test-Path $AfterInstallScript)) { + $postinstFile = Join-Path $debianDir "postinst" + Copy-Item -Path $AfterInstallScript -Destination $postinstFile -Force + Start-NativeExecution { chmod 755 $postinstFile } + Write-Verbose "Postinst script copied to: $postinstFile" -Verbose + } + + # Copy postrm script if provided + if ($AfterRemoveScript -and (Test-Path $AfterRemoveScript)) { + $postrmFile = Join-Path $debianDir "postrm" + Copy-Item -Path $AfterRemoveScript -Destination $postrmFile -Force + Start-NativeExecution { chmod 755 $postrmFile } + Write-Verbose "Postrm script copied to: $postrmFile" -Verbose + } + + # Copy staging files to data directory + $targetPath = Join-Path $dataDir $Destination.TrimStart('/') + New-Item -ItemType Directory -Path $targetPath -Force | Out-Null + Copy-Item -Path "$Staging/*" -Destination $targetPath -Recurse -Force + Write-Verbose "Copied staging files to: $targetPath" -Verbose + + # Copy man page + $manDestPath = Join-Path $dataDir $ManDestination.TrimStart('/') + $manDestDir = Split-Path $manDestPath -Parent + New-Item -ItemType Directory -Path $manDestDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination $manDestPath -Force + Write-Verbose "Copied man page to: $manDestPath" -Verbose + + # Copy symlinks from temporary locations + foreach ($link in $LinkInfo) { + $linkPath = Join-Path $dataDir $link.Destination.TrimStart('/') + $linkDir = Split-Path $linkPath -Parent + New-Item -ItemType Directory -Path $linkDir -Force | Out-Null + + # Copy the temporary symlink file that was created by New-LinkInfo + # The Source contains a temporary symlink that points to the correct target + if (Test-Path $link.Source) { + # Use cp to preserve the symlink + Start-NativeExecution { cp -P $link.Source $linkPath } + Write-Verbose "Copied symlink: $linkPath (from $($link.Source))" -Verbose + } else { + Write-Warning "Symlink source not found: $($link.Source)" + } + } + + # Set proper permissions + Write-Verbose "Setting file permissions..." -Verbose + # 755 = rwxr-xr-x (owner can read/write/execute, group and others can read/execute) + Get-ChildItem $dataDir -Directory -Recurse | ForEach-Object { + Start-NativeExecution { chmod 755 $_.FullName } + } + # 644 = rw-r--r-- (owner can read/write, group and others can read only) + # Exclude symlinks to avoid "cannot operate on dangling symlink" error + Get-ChildItem $dataDir -File -Recurse | + Where-Object { -not $_.Target } | + ForEach-Object { + Start-NativeExecution { chmod 644 $_.FullName } + } + + # Set executable permission for pwsh if it exists + # 755 = rwxr-xr-x (executable permission) + $pwshPath = "$targetPath/pwsh" + if (Test-Path $pwshPath) { + Start-NativeExecution { chmod 755 $pwshPath } + } + + # Calculate md5sums for all files in data directory (excluding symlinks) + $md5sumsFile = Join-Path $debianDir "md5sums" + $md5Content = "" + Get-ChildItem -Path $dataDir -Recurse -File | + Where-Object { -not $_.Target } | + ForEach-Object { + $relativePath = $_.FullName.Substring($dataDir.Length + 1) + $md5Hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash.ToLower() + $md5Content += "$md5Hash $relativePath`n" + } + $md5Content | Out-File -FilePath $md5sumsFile -Encoding ascii -NoNewline + Write-Verbose "MD5 sums file created: $md5sumsFile" -Verbose + + # Build the package using dpkg-deb + $debFileName = "${Name}_${Version}-${Iteration}_${HostArchitecture}.deb" + $debFilePath = Join-Path $CurrentLocation $debFileName + + Write-Verbose "Building DEB package: $debFileName" -Verbose + + # Copy DEBIAN directory and data files to build root + $buildDir = Join-Path $debBuildRoot "build" + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null + + Write-Verbose "debianDir: $debianDir" -Verbose + Write-Verbose "dataDir: $dataDir" -Verbose + Write-Verbose "buildDir: $buildDir" -Verbose + + # Use cp to preserve symlinks + Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } + Start-NativeExecution { cp -a $dataDir/* $buildDir } + + # Build package with dpkg-deb + Start-NativeExecution -VerboseOutputOnError { + dpkg-deb --build $buildDir $debFilePath + } + + if (Test-Path $debFilePath) { + Write-Log "Successfully created DEB package: $debFileName" + return @{ + PackagePath = $debFilePath + PackageName = $debFileName + } + } else { + throw "DEB package file not found after build: $debFilePath" + } + } + finally { + # Cleanup temporary directory + if (Test-Path $debBuildRoot) { + Write-Verbose "Cleaning up temporary build directory: $debBuildRoot" -Verbose + Remove-Item -Path $debBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function New-MacOSPackage { [CmdletBinding(SupportsShouldProcess=$true)] @@ -1884,146 +2087,6 @@ function New-MacOSPackage } } -function Get-FpmArguments -{ - param( - [Parameter(Mandatory,HelpMessage='Package Name')] - [String]$Name, - - [Parameter(Mandatory,HelpMessage='Package Version')] - [String]$Version, - - [Parameter(Mandatory)] - [String]$Iteration, - - [Parameter(Mandatory,HelpMessage='Package description')] - [String]$Description, - - # From start-PSPackage without modification, already validated - # Values: deb, rpm, osxpkg - [Parameter(Mandatory,HelpMessage='Installer Type')] - [String]$Type, - - [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] - [String]$Staging, - - [Parameter(Mandatory,HelpMessage='Install path on target machine')] - [String]$Destination, - - [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] - [String]$ManGzipFile, - - [Parameter(Mandatory,HelpMessage='The destination of the man file')] - [String]$ManDestination, - - [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] - [LinkInfo[]]$LinkInfo, - - [Parameter(HelpMessage='Packages required to install this package. Not applicable for MacOS.')] - [ValidateScript({ - if (!$Environment.IsMacOS -and $_.Count -eq 0) - { - throw "Must not be null or empty on this environment." - } - return $true - })] - [String[]]$Dependencies, - - [Parameter(HelpMessage='Script to run after the package installation.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterInstallScript, - - [Parameter(HelpMessage='Script to run after the package removal.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterRemoveScript, - - [Parameter(HelpMessage='AppsFolder used to add macOS launcher')] - [AllowNull()] - [ValidateScript({ - if ($Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AppsFolder, - [String]$Distribution = 'rhel.7', - [string]$HostArchitecture - ) - - $Arguments = @( - "--force", "--verbose", - "--name", $Name, - "--version", $Version, - "--iteration", $Iteration, - "--maintainer", "PowerShell Team ", - "--vendor", "Microsoft Corporation", - "--url", "https://microsoft.com/powershell", - "--description", $Description, - "--architecture", $HostArchitecture, - "--category", "shells", - "-t", $Type, - "-s", "dir" - ) - if ($Distribution -in $script:RedHatDistributions) { - $Arguments += @("--rpm-digest", "sha256") - $Arguments += @("--rpm-dist", $Distribution) - $Arguments += @("--rpm-os", "linux") - $Arguments += @("--license", "MIT") - $Arguments += @("--rpm-rpmbuild-define", "_build_id_links none") - } else { - $Arguments += @("--license", "MIT License") - } - - if ($Environment.IsMacOS) { - $Arguments += @("--osxpkg-identifier-prefix", "com.microsoft") - } - - foreach ($Dependency in $Dependencies) { - $Arguments += @("--depends", $Dependency) - } - - if ($AfterInstallScript) { - $Arguments += @("--after-install", $AfterInstallScript) - } - - if ($AfterRemoveScript) { - $Arguments += @("--after-remove", $AfterRemoveScript) - } - - $Arguments += @( - "$Staging/=$Destination/", - "$ManGzipFile=$ManDestination" - ) - - foreach($link in $LinkInfo) - { - $linkArgument = "$($link.Source)=$($link.Destination)" - $Arguments += $linkArgument - } - - if ($AppsFolder) - { - $Arguments += "$AppsFolder=/" - } - - return $Arguments -} - function Get-PackageDependencies { [CmdletBinding()] @@ -2096,44 +2159,25 @@ function Get-PackageDependencies function Test-Dependencies { - # Note: RPM packages no longer require fpm; they use rpmbuild directly - # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools - # DEB packages still use fpm + # RPM packages use rpmbuild directly. + # DEB packages use dpkg-deb directly. + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools. $Dependencies = @() - - # Only check for fpm on Debian-based systems - if ($Environment.IsDebianFamily) { - $Dependencies += "fpm" + + # Check for 'rpmbuild' and 'dpkg-deb' on Azure Linux. + if ($Environment.IsMariner) { + $Dependencies += "dpkg-deb" + $Dependencies += "rpmbuild" } - + # Check for macOS packaging tools if ($Environment.IsMacOS) { $Dependencies += "pkgbuild" $Dependencies += "productbuild" } - + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # For Debian systems, try adding ruby gems to the path - if ($Environment.IsDebianFamily) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath - } - } - } - throw "Dependency precheck failed!" } } From df8fe254b9ee0c04d24fe5ac010fdda7b26b9c71 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 28 Oct 2025 16:49:53 -0700 Subject: [PATCH 170/378] Update SDK to 10.0.100-rc.2.25502.107 (#26305) Co-authored-by: Dongbo Wang Co-authored-by: Travis Plunk --- .github/workflows/linux-ci.yml | 25 ++-- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 5 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 114 ++++++++++-------- 14 files changed, 97 insertions(+), 87 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 1650638be8e..9c0652a9359 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -157,17 +157,18 @@ jobs: runner_os: ubuntu-latest test_results_artifact_name: testResults-xunit - analyze: - name: CodeQL Analysis - needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} - uses: ./.github/workflows/analyze-reusable.yml - permissions: - actions: read - contents: read - security-events: write - with: - runner_os: ubuntu-latest + ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. + # analyze: + # name: CodeQL Analysis + # needs: changes + # if: ${{ needs.changes.outputs.source == 'true' }} + # uses: ./.github/workflows/analyze-reusable.yml + # permissions: + # actions: read + # contents: read + # security-events: write + # with: + # runner_os: ubuntu-latest ready_to_merge: name: Linux ready to merge @@ -177,8 +178,8 @@ jobs: - linux_test_elevated_others - linux_test_unelevated_ci - linux_test_unelevated_others - - analyze - linux_packaging + # - analyze if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: diff --git a/global.json b/global.json index e7cce33e5d9..83e6a8b43e0 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-rc.1.25451.107" + "version": "10.0.100-rc.2.25502.107" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 547911668e9..cc3760db39f 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 029571c4145..f5f6fede1af 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index a35f4258e56..da15fe82350 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + @@ -33,8 +33,7 @@ - - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index d60337d5d90..228d6360022 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 2c796312a1a..31c48def673 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,13 +16,13 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 710102ca2fa..bef80519d56 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 033c39034ac..0e435448b5f 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,17 +32,17 @@ - - + + - + - + - - + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 10c707c176a..de06b206f37 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f50e3bccf60..d2004ea2fdd 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 46638197255..056f6810c71 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 90ae1a9b453..5cb4a1e48d8 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -29,7 +29,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 11c7447ff7d..26936804614 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -65,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.42.0" + "Version": "0.43.0" } }, "DevelopmentDependency": false @@ -85,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -125,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -335,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -375,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -435,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -615,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -625,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -655,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -665,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -725,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -735,7 +736,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -745,7 +746,17 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.9" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Text.Encoding.CodePages", + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -755,7 +766,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -775,11 +786,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From bf3d978b9df2c831413016a93711120acf3bb079 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:05:28 -0700 Subject: [PATCH 171/378] Bump actions/upload-artifact from 4 to 5 (#26328) --- .github/workflows/macos-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 95edb2b8d96..077218d66e7 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -215,7 +215,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: macos-package path: "*.pkg" From 0d7c24fb7e4580a8000a2b574b073349f9ce66d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:05:55 -0700 Subject: [PATCH 172/378] Bump actions/setup-dotnet from 4 to 5 (#26327) --- .github/workflows/macos-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 077218d66e7..f43fa6a4b89 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -164,7 +164,7 @@ jobs: uses: actions/checkout@v5 with: fetch-depth: 1000 - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v5 with: global-json-file: ./global.json - name: Bootstrap packaging From cdeda2a50140a965a31d2ff7a575524b6caa2814 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:52:59 -0700 Subject: [PATCH 173/378] Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26326) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/actions/build/ci/action.yml | 4 +- .../actions/test/linux-packaging/action.yml | 4 +- .github/actions/test/nix/action.yml | 6 +- .github/actions/test/windows/action.yml | 6 +- .../log-grouping-guidelines.instructions.md | 181 ++++++++++++++++++ .github/workflows/analyze-reusable.yml | 3 +- .github/workflows/linux-ci.yml | 13 +- .github/workflows/macos-ci.yml | 15 +- .github/workflows/windows-ci.yml | 15 +- .../workflows/windows-packaging-reusable.yml | 3 +- build.psm1 | 28 ++- tools/ci.psm1 | 8 + 12 files changed, 253 insertions(+), 33 deletions(-) create mode 100644 .github/instructions/log-grouping-guidelines.instructions.md diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 997be8b264c..be9c0ecd20b 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -5,7 +5,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Set Build Name for Non-PR if: github.event_name != 'PullRequest' diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 374205f2a56..d0c72c7b035 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -6,7 +6,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - uses: actions/setup-dotnet@v5 diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index b338c398340..ef943bfce78 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -21,10 +21,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 734e30208f0..3b3ce0cafe8 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -21,10 +21,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/instructions/log-grouping-guidelines.instructions.md b/.github/instructions/log-grouping-guidelines.instructions.md new file mode 100644 index 00000000000..ff845db4e4b --- /dev/null +++ b/.github/instructions/log-grouping-guidelines.instructions.md @@ -0,0 +1,181 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Log Grouping Guidelines for GitHub Actions + +## Purpose + +Guidelines for using `Write-LogGroupStart` and `Write-LogGroupEnd` to create collapsible log sections in GitHub Actions CI/CD runs. + +## Key Principles + +### 1. Groups Cannot Be Nested + +GitHub Actions does not support nested groups. Only use one level of grouping. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Outer Group" +Write-LogGroupStart -Title "Inner Group" +# ... operations ... +Write-LogGroupEnd -Title "Inner Group" +Write-LogGroupEnd -Title "Outer Group" +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Operation A" +# ... operations ... +Write-LogGroupEnd -Title "Operation A" + +Write-LogGroupStart -Title "Operation B" +# ... operations ... +Write-LogGroupEnd -Title "Operation B" +``` + +### 2. Groups Should Be Substantial + +Only create groups for operations that generate substantial output (5+ lines). Small groups add clutter without benefit. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Generate Resource Files" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files" +``` + +**✅ Do:** +```powershell +Write-Log -message "Run ResGen (generating C# bindings for resx files)" +Start-ResGen +``` + +### 3. Groups Should Represent Independent Operations + +Each group should be a logically independent operation that users might want to expand/collapse separately. + +**✅ Good examples:** +- Install Native Dependencies +- Install .NET SDK +- Build PowerShell +- Restore NuGet Packages + +**❌ Bad examples:** +- Individual project restores (too granular) +- Small code generation steps (too small) +- Sub-steps of a larger operation (would require nesting) + +### 4. One Group Per Iteration Is Excessive + +Avoid putting log groups inside loops where each iteration creates a separate group. This would probably cause nesting. + +**❌ Don't:** +```powershell +$projects | ForEach-Object { + Write-LogGroupStart -Title "Restore Project: $_" + dotnet restore $_ + Write-LogGroupEnd -Title "Restore Project: $_" +} +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Restore All Projects" +$projects | ForEach-Object { + Write-Log -message "Restoring $_" + dotnet restore $_ +} +Write-LogGroupEnd -Title "Restore All Projects" +``` + +## Usage Pattern + +```powershell +Write-LogGroupStart -Title "Descriptive Operation Name" +try { + # ... operation code ... + Write-Log -message "Status updates" +} +finally { + # Ensure group is always closed +} +Write-LogGroupEnd -Title "Descriptive Operation Name" +``` + +## When to Use Log Groups + +Use log groups for: +- Major build phases (bootstrap, restore, build, test, package) +- Installation operations (dependencies, SDKs, tools) +- Operations that produce 5+ lines of output +- Operations where users might want to collapse verbose output + +Don't use log groups for: +- Single-line operations +- Code that's already inside another group +- Loop iterations with minimal output per iteration +- Diagnostic or debug output that should always be visible + +## Examples from build.psm1 + +### Good Usage + +```powershell +function Start-PSBootstrap { + # Multiple independent operations, each with substantial output + Write-LogGroupStart -Title "Install Native Dependencies" + # ... apt-get/yum/brew install commands ... + Write-LogGroupEnd -Title "Install Native Dependencies" + + Write-LogGroupStart -Title "Install .NET SDK" + # ... dotnet installation ... + Write-LogGroupEnd -Title "Install .NET SDK" +} +``` + +### Avoid + +```powershell +# Too small - just 2-3 lines +Write-LogGroupStart -Title "Generate Resource Files (ResGen)" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files (ResGen)" +``` + +## GitHub Actions Syntax + +These functions emit GitHub Actions workflow commands: +- `Write-LogGroupStart` → `::group::Title` +- `Write-LogGroupEnd` → `::endgroup::` + +In the GitHub Actions UI, this renders as collapsible sections with the specified title. + +## Testing + +Test log grouping locally: +```powershell +$env:GITHUB_ACTIONS = 'true' +Import-Module ./build.psm1 +Write-LogGroupStart -Title "Test" +Write-Log -Message "Content" +Write-LogGroupEnd -Title "Test" +``` + +Output should show: +``` +::group::Test +Content +::endgroup:: +``` + +## References + +- [GitHub Actions: Grouping log lines](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines) +- `build.psm1`: `Write-LogGroupStart` and `Write-LogGroupEnd` function definitions diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 1797e2234a6..10b2f0893a3 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -56,7 +56,8 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment name: Capture Environment shell: pwsh diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 9c0652a9359..8dc0e738ffd 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -70,7 +71,7 @@ jobs: name: Build PowerShell runs-on: ubuntu-latest needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v5 @@ -84,7 +85,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -101,7 +102,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -118,7 +119,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -135,7 +136,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -151,7 +152,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: ubuntu-latest diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index f43fa6a4b89..8a80b79f1c0 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -67,7 +68,7 @@ jobs: name: Build PowerShell runs-on: macos-15-large needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v5 @@ -80,7 +81,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -97,7 +98,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -114,7 +115,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -131,7 +132,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -147,7 +148,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: macos-15-large @@ -156,7 +157,7 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: - macos-15-large steps: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index f33f1a3f589..582860de34c 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -56,6 +56,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -70,7 +71,7 @@ jobs: ci_build: name: Build PowerShell needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -84,7 +85,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -101,7 +102,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -118,7 +119,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -135,7 +136,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -151,7 +152,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: windows-latest @@ -159,7 +160,7 @@ jobs: analyze: name: CodeQL Analysis needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/analyze-reusable.yml permissions: actions: read diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 0afa912273c..1f03aaf5944 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -43,7 +43,8 @@ jobs: - name: Capture Environment if: success() || failure() run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Capture PowerShell Version Table diff --git a/build.psm1 b/build.psm1 index e4e1a1f69f2..c56303524be 100644 --- a/build.psm1 +++ b/build.psm1 @@ -385,7 +385,7 @@ function Start-PSBuild { } if ($Clean) { - Write-Log -message "Cleaning your working directory. You can also do it with 'git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3'" + Write-LogGroupStart -Title "Cleaning your working directory" Push-Location $PSScriptRoot try { # Excluded sqlite3 folder is due to this Roslyn issue: https://github.com/dotnet/roslyn/issues/23060 @@ -393,6 +393,7 @@ function Start-PSBuild { # Excluded nuget.config as this is required for release build. git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3 --exclude src/Modules/nuget.config --exclude nuget.config } finally { + Write-LogGroupEnd -Title "Cleaning your working directory" Pop-Location } } @@ -536,7 +537,9 @@ Fix steps: } # handle Restore + Write-LogGroupStart -Title "Restore NuGet Packages" Restore-PSPackage -Options $Options -Force:$Restore -InteractiveAuth:$InteractiveAuth + Write-LogGroupEnd -Title "Restore NuGet Packages" # handle ResGen # Heuristic to run ResGen on the fresh machine @@ -566,6 +569,7 @@ Fix steps: $publishPath = $Options.Output } + Write-LogGroupStart -Title "Build PowerShell" try { # Relative paths do not work well if cwd is not changed to project Push-Location $Options.Top @@ -620,6 +624,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Build PowerShell" # 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. if ($SMAOnly) { @@ -627,6 +632,7 @@ Fix steps: } # publish reference assemblies + Write-LogGroupStart -Title "Publish Reference Assemblies" try { Push-Location "$PSScriptRoot/src/TypeCatalogGen" $refAssemblies = Get-Content -Path $incFileName | Where-Object { $_ -like "*microsoft.netcore.app*" } | ForEach-Object { $_.TrimEnd(';') } @@ -640,6 +646,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Publish Reference Assemblies" if ($ReleaseTag) { $psVersion = $ReleaseTag @@ -682,10 +689,13 @@ Fix steps: # download modules from powershell gallery. # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive if ($PSModuleRestore) { + Write-LogGroupStart -Title "Restore PowerShell Modules" Restore-PSModuleToBuild -PublishPath $publishPath + Write-LogGroupEnd -Title "Restore PowerShell Modules" } # publish powershell.config.json + Write-LogGroupStart -Title "Generate PowerShell Configuration" $config = [ordered]@{} if ($Options.Runtime -like "*win*") { @@ -731,10 +741,13 @@ Fix steps: } else { Write-Warning "No powershell.config.json generated for $publishPath" } + Write-LogGroupEnd -Title "Generate PowerShell Configuration" # Restore the Pester module if ($CI) { + Write-LogGroupStart -Title "Restore Pester Module" Restore-PSPester -Destination (Join-Path $publishPath "Modules") + Write-LogGroupEnd -Title "Restore Pester Module" } Clear-NativeDependencies -PublishFolder $publishPath @@ -2086,6 +2099,7 @@ function Install-Dotnet { [string]$FeedCredential ) + Write-LogGroupStart -Title "Install .NET SDK $Version" Write-Verbose -Verbose "In install-dotnet" # This allows sudo install to be optional; needed when running in containers / as root @@ -2220,6 +2234,7 @@ function Install-Dotnet { } } } + Write-LogGroupEnd -Title "Install .NET SDK $Version" } function Get-RedHatPackageManager { @@ -2264,12 +2279,14 @@ function Start-PSBootstrap { try { if ($environment.IsLinux -or $environment.IsMacOS) { + Write-LogGroupStart -Title "Install Native Dependencies" # This allows sudo install to be optional; needed when running in containers / as root # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { Write-Error "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" + Write-LogGroupEnd -Title "Install Native Dependencies" return } @@ -2399,9 +2416,11 @@ function Start-PSBootstrap { } } } + Write-LogGroupEnd -Title "Install Native Dependencies" } if ($Scenario -in 'All', 'Both', 'DotNet') { + Write-LogGroupStart -Title "Install .NET SDK" Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" @@ -2440,10 +2459,12 @@ function Start-PSBootstrap { else { Write-Log -message "dotnet is already installed. Skipping installation." } + Write-LogGroupEnd -Title "Install .NET SDK" } # Install Windows dependencies if `-Package` or `-BuildWindowsNative` is specified if ($environment.IsWindows) { + Write-LogGroupStart -Title "Install Windows Dependencies" ## The VSCode build task requires 'pwsh.exe' to be found in Path if (-not (Get-Command -Name pwsh.exe -CommandType Application -ErrorAction Ignore)) { @@ -2456,9 +2477,11 @@ function Start-PSBootstrap { $isArm64 = "$env:RUNTIME" -eq 'arm64' Install-Wix -arm64:$isArm64 } + Write-LogGroupEnd -Title "Install Windows Dependencies" } if ($Scenario -in 'All', 'Tools') { + Write-LogGroupStart -Title "Install .NET Global Tools" Write-Log -message "Installing .NET global tools" # Ensure dotnet is available @@ -2469,12 +2492,15 @@ function Start-PSBootstrap { Start-NativeExecution { dotnet tool install --global dotnet-format } + Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { + Write-LogGroupStart -Title "Capture NuGet Sources" Write-Verbose -Verbose "--- Start - Capturing nuget sources" dotnet nuget list source --format detailed Write-Verbose -Verbose "--- End - Capturing nuget sources" + Write-LogGroupEnd -Title "Capture NuGet Sources" } } finally { Pop-Location diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 44651c26109..478435e8543 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -688,6 +688,14 @@ function Set-Path } } +# Display environment variables in a log group for GitHub Actions +function Show-Environment +{ + Write-LogGroupStart -Title 'Environment' + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + Write-LogGroupEnd -Title 'Environment' +} + # Bootstrap script for Linux and macOS function Invoke-BootstrapStage { From d38d6fadf9064b508dc47a49e1df7cc923d10967 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 30 Oct 2025 10:28:52 -0700 Subject: [PATCH 174/378] Update the `Microsoft.PowerShell.Native` package version (#26347) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 0e435448b5f..f3d73f72dd4 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -47,7 +47,7 @@ - + From 943257b247ba16dc67b1f7c126248bbc00ae1a21 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 30 Oct 2025 14:26:03 -0700 Subject: [PATCH 175/378] Make some experimental features stable (#26348) The following experimental features are made stable: - PSNativeWindowsTildeExpansion - PSRedirectToVariable - PSSubsystemPluginModel --- .../commands/utility/Var.cs | 1 - .../ExperimentalFeature.cs | 11 ---- .../engine/InitialSessionState.cs | 6 +-- .../engine/NativeCommandParameterBinder.cs | 7 +-- .../Commands/GetPSSubsystemCommand.cs | 1 - .../engine/runtime/Operations/MiscOps.cs | 17 +++---- .../Parser/RedirectionOperator.Tests.ps1 | 8 +-- .../NativeWindowsTildeExpansion.Tests.ps1 | 16 +++--- .../Set-Variable.Tests.ps1 | 50 +++++++------------ .../engine/Basic/DefaultCommands.Tests.ps1 | 1 + test/tools/TestMetadata.json | 3 -- 11 files changed, 37 insertions(+), 84 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs index 12cfb784c72..a41b284f568 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs @@ -697,7 +697,6 @@ public SwitchParameter PassThru /// Gets whether we will append to the variable if it exists. /// [Parameter] - [Experimental(ExperimentalFeature.PSRedirectToVariable, ExperimentAction.Show)] public SwitchParameter Append { get; set; } private bool _nameIsFormalParameter; diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 6ff7e1d6820..4ac98cb485e 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -22,8 +22,6 @@ public class ExperimentalFeature internal const string EngineSource = "PSEngine"; internal const string PSFeedbackProvider = "PSFeedbackProvider"; - internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); - internal const string PSRedirectToVariable = "PSRedirectToVariable"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); #endregion @@ -107,21 +105,12 @@ static ExperimentalFeature() name: "PSFileSystemProviderV2", description: "Replace the old FileSystemProvider with cleaner design and faster code"), */ - new ExperimentalFeature( - name: "PSSubsystemPluginModel", - description: "A plugin model for registering and un-registering PowerShell subsystems"), new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), new ExperimentalFeature( name: PSFeedbackProvider, description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), - new ExperimentalFeature( - name: PSNativeWindowsTildeExpansion, - description: "On Windows, expand unquoted tilde (`~`) with the user's current home folder."), - new ExperimentalFeature( - name: PSRedirectToVariable, - description: "Add support for redirecting to the variable drive"), new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index ba508560ee7..62308282d17 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -5478,6 +5478,7 @@ private static void InitializeCoreCmdletsAndProviders( { "Get-Module", new SessionStateCmdletEntry("Get-Module", typeof(GetModuleCommand), helpFile) }, { "Get-PSHostProcessInfo", new SessionStateCmdletEntry("Get-PSHostProcessInfo", typeof(GetPSHostProcessInfoCommand), helpFile) }, { "Get-PSSession", new SessionStateCmdletEntry("Get-PSSession", typeof(GetPSSessionCommand), helpFile) }, + { "Get-PSSubsystem", new SessionStateCmdletEntry("Get-PSSubsystem", typeof(Subsystem.GetPSSubsystemCommand), helpFile) }, { "Import-Module", new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), helpFile) }, { "Invoke-Command", new SessionStateCmdletEntry("Invoke-Command", typeof(InvokeCommandCommand), helpFile) }, { "Invoke-History", new SessionStateCmdletEntry("Invoke-History", typeof(InvokeHistoryCommand), helpFile) }, @@ -5518,11 +5519,6 @@ private static void InitializeCoreCmdletsAndProviders( { "Format-Default", new SessionStateCmdletEntry("Format-Default", typeof(FormatDefaultCommand), helpFile) }, }; - if (ExperimentalFeature.IsEnabled("PSSubsystemPluginModel")) - { - cmdlets.Add("Get-PSSubsystem", new SessionStateCmdletEntry("Get-PSSubsystem", typeof(Subsystem.GetPSSubsystemCommand), helpFile)); - } - #if UNIX cmdlets.Add("Switch-Process", new SessionStateCmdletEntry("Switch-Process", typeof(SwitchProcessCommand), helpFile)); #endif diff --git a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs index 2e62274ee53..31ac506c86a 100644 --- a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs +++ b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs @@ -406,12 +406,9 @@ private void PossiblyGlobArg(string arg, CommandParameterInternal parameter, boo } } #else - if (!usedQuotes && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeWindowsTildeExpansion)) + if (!usedQuotes && ExpandTilde(arg, parameter)) { - if (ExpandTilde(arg, parameter)) - { - argExpanded = true; - } + argExpanded = true; } #endif diff --git a/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs b/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs index 1ad79404f51..df828c724a2 100644 --- a/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs +++ b/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs @@ -8,7 +8,6 @@ namespace System.Management.Automation.Subsystem /// /// Implementation of 'Get-PSSubsystem' cmdlet. /// - [Experimental("PSSubsystemPluginModel", ExperimentAction.Show)] [Cmdlet(VerbsCommon.Get, "PSSubsystem", DefaultParameterSetName = AllSet)] [OutputType(typeof(SubsystemInfo))] public sealed class GetPSSubsystemCommand : PSCmdlet diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index ddc70fabd50..50054f6501d 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -1092,14 +1092,11 @@ internal override void Bind(PipelineProcessor pipelineProcessor, CommandProcesso { // Check first to see if File is a variable path. If so, we'll not create the FileBytePipe bool redirectToVariable = false; - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSRedirectToVariable)) + + context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out ProviderInfo p, out _); + if (p != null && p.NameEquals(context.ProviderNames.Variable)) { - ProviderInfo p; - context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out p, out _); - if (p != null && p.NameEquals(context.ProviderNames.Variable)) - { - redirectToVariable = true; - } + redirectToVariable = true; } if (commandProcessor is NativeCommandProcessor nativeCommand @@ -1223,12 +1220,10 @@ internal Pipe GetRedirectionPipe(ExecutionContext context, PipelineProcessor par // determine whether we're trying to set a variable by inspecting the file path // if we can determine that it's a variable, we'll use Set-Variable rather than Out-File - ProviderInfo p; - PSDriveInfo d; CommandProcessorBase commandProcessor; - var name = context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out p, out d); + var name = context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out ProviderInfo p, out _); - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSRedirectToVariable) && p != null && p.NameEquals(context.ProviderNames.Variable)) + if (p != null && p.NameEquals(context.ProviderNames.Variable)) { commandProcessor = context.CreateCommand("Set-Variable", false); Diagnostics.Assert(commandProcessor != null, "CreateCommand returned null"); diff --git a/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 b/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 index d948881f1de..140d92fae88 100644 --- a/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 +++ b/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 @@ -127,12 +127,6 @@ Describe "File redirection should have 'DoComplete' called on the underlying pip Describe "Redirection and Set-Variable -append tests" -tags CI { Context "variable redirection should work" { BeforeAll { - if ( $EnabledExperimentalFeatures -contains "PSRedirectToVariable" ) { - $skipTest = $false - } - else { - $skipTest = $true - } $testCases = @{ Name = "Variable should be created"; scriptBlock = { 1..3>variable:a }; Validation = { ($a -join "") | Should -Be ((1..3) -join "") } }, @{ Name = "variable should be appended"; scriptBlock = {1..3>variable:a; 4..6>>variable:a}; Validation = { ($a -join "") | Should -Be ((1..6) -join "")}}, @{ Name = "variable should maintain type"; scriptBlock = {@{one=1}>variable:a};Validation = {$a | Should -BeOfType [hashtable]}}, @@ -220,7 +214,7 @@ Describe "Redirection and Set-Variable -append tests" -tags CI { } - It "" -TestCases $testCases -skip:$skipTest { + It "" -TestCases $testCases { param ( $scriptBlock, $validation ) . $scriptBlock . $validation diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 index 04156099fa4..3a478607c08 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 @@ -5,7 +5,6 @@ Describe 'Native Windows tilde expansion tests' -tags "CI" { BeforeAll { $originalDefaultParams = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = -Not $IsWindows - $EnabledExperimentalFeatures.Contains('PSNativeWindowsTildeExpansion') | Should -BeTrue } AfterAll { @@ -21,12 +20,13 @@ Describe 'Native Windows tilde expansion tests' -tags "CI" { cmd /c echo ~/foo | Should -BeExactly "$($ExecutionContext.SessionState.Provider.Get("FileSystem").Home)/foo" cmd /c echo ~\foo | Should -BeExactly "$($ExecutionContext.SessionState.Provider.Get("FileSystem").Home)\foo" } - It '~ should not be replaced when quoted' { - cmd /c echo '~' | Should -BeExactly '~' - cmd /c echo "~" | Should -BeExactly '~' - cmd /c echo '~/foo' | Should -BeExactly '~/foo' - cmd /c echo "~/foo" | Should -BeExactly '~/foo' + + It '~ should not be replaced when quoted' { + cmd /c echo '~' | Should -BeExactly '~' + cmd /c echo "~" | Should -BeExactly '~' + cmd /c echo '~/foo' | Should -BeExactly '~/foo' + cmd /c echo "~/foo" | Should -BeExactly '~/foo' cmd /c echo '~\foo' | Should -BeExactly '~\foo' - cmd /c echo "~\foo" | Should -BeExactly '~\foo' - } + cmd /c echo "~\foo" | Should -BeExactly '~\foo' + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 index d11fd5cfbb3..6e6fc1a2e1d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 @@ -244,44 +244,30 @@ Describe "Set-Variable" -Tags "CI" { Context "Set-Variable -Append tests" { BeforeAll { - if (! (Get-ExperimentalFeature PSRedirectToVariable).Enabled) { - $skipTest = $true - } - - $testCases = @{ value = 2; Count = 2 }, - @{ value = @(2,3,4); Count = 2}, - @{ value = "abc",(Get-Process -Id $PID) ; count = 2} + $testCases = @{ value = 2; Count = 2 }, + @{ value = @(2,3,4); Count = 2}, + @{ value = "abc",(Get-Process -Id $PID) ; count = 2} } - It "Can append values to a variable" -testCases $testCases { - param ($value, $count) - - if ($skipTest) { - Set-ItResult -skip -because "Experimental Feature PSRedirectToVariable not enabled" - return - } - - $variableName = "testVar" - Set-Variable -Name $variableName -Value 1 - Set-Variable -Name $variableName -Value $value -Append + It "Can append values to a variable" -testCases $testCases { + param ($value, $count) - $observedValues = Get-Variable $variableName -Value + $variableName = "testVar" + Set-Variable -Name $variableName -Value 1 + Set-Variable -Name $variableName -Value $value -Append - $observedValues.Count | Should -Be $count - $observedValues[0] | Should -Be 1 + $observedValues = Get-Variable $variableName -Value - $observedValues[1] | Should -Be $value - } + $observedValues.Count | Should -Be $count + $observedValues[0] | Should -Be 1 - It "Can use set-variable via streaming and append values" { - if ($skipTest) { - Set-ItResult -skip -because "Experimental Feature PSRedirectToVariable not enabled" - return - } + $observedValues[1] | Should -Be $value + } - $testVar = 1 - 4..6 | Set-Variable -Name testVar -Append - $testVar | Should -Be @(1,4,5,6) - } + It "Can use set-variable via streaming and append values" { + $testVar = 1 + 4..6 | Set-Variable -Name testVar -Append + $testVar | Should -Be @(1,4,5,6) + } } } diff --git a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 index 312c34b6706..7a757e6eac4 100644 --- a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 +++ b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 @@ -337,6 +337,7 @@ Describe "Verify aliases and cmdlets" -Tags "CI" { "Cmdlet", "Get-PSSessionCapability", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-PSSessionConfiguration", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-PSSnapin", "", $($FullCLR ), "", "", "" +"Cmdlet", "Get-PSSubsystem", "", $( $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Random", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Runspace", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-RunspaceDebug", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index bd716ccec7b..19ffb93ce92 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -1,9 +1,6 @@ { "ExperimentalFeatures": { "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], - "PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ], - "Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/RunspaceBreakpointManagement.Tests.ps1" ], - "PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ], "PSSerializeJSONLongEnumAsNumber": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1" ] } } From a9368846380d6b35706239e880cb088c64e36013 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 30 Oct 2025 14:27:19 -0700 Subject: [PATCH 176/378] Add reusable get-changed-files action and refactor existing actions (#26355) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../get-changed-files/README.md | 122 ++++++++++++++++++ .../get-changed-files/action.yml | 117 +++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 47 ++----- .../infrastructure/path-filters/action.yml | 104 ++++++++------- 4 files changed, 304 insertions(+), 86 deletions(-) create mode 100644 .github/actions/infrastructure/get-changed-files/README.md create mode 100644 .github/actions/infrastructure/get-changed-files/action.yml diff --git a/.github/actions/infrastructure/get-changed-files/README.md b/.github/actions/infrastructure/get-changed-files/README.md new file mode 100644 index 00000000000..277b28c0674 --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/README.md @@ -0,0 +1,122 @@ +# Get Changed Files Action + +A reusable composite action that retrieves the list of files changed in a pull request or push event. + +## Features + +- Supports both `pull_request` and `push` events +- Optional filtering by file pattern +- Returns files as JSON array for easy consumption +- Filters out deleted files (only returns added, modified, or renamed files) +- Handles up to 100 changed files per request + +## Usage + +### Basic Usage (Pull Requests Only) + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process files + run: | + echo "Changed files: ${{ steps.changed-files.outputs.files }}" + echo "Count: ${{ steps.changed-files.outputs.count }}" +``` + +### With Filtering + +```yaml +# Get only markdown files +- name: Get changed markdown files + id: changed-md + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '*.md' + +# Get only GitHub workflow/action files +- name: Get changed GitHub files + id: changed-github + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '.github/' +``` + +### Support Both PR and Push Events + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + with: + event-types: 'pull_request,push' +``` + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `filter` | Optional filter pattern (e.g., `*.md` for markdown files, `.github/` for GitHub files) | No | `''` | +| `event-types` | Comma-separated list of event types to support (`pull_request`, `push`) | No | `pull_request` | + +## Outputs + +| Name | Description | +|------|-------------| +| `files` | JSON array of changed file paths | +| `count` | Number of changed files | + +## Filter Patterns + +The action supports simple filter patterns: + +- **Extension matching**: Use `*.ext` to match files with a specific extension + - Example: `*.md` matches all markdown files + - Example: `*.yml` matches all YAML files + +- **Path prefix matching**: Use a path prefix to match files in a directory + - Example: `.github/` matches all files in the `.github` directory + - Example: `tools/` matches all files in the `tools` directory + +## Example: Processing Changed Files + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process each file + shell: pwsh + env: + CHANGED_FILES: ${{ steps.changed-files.outputs.files }} + run: | + $changedFilesJson = $env:CHANGED_FILES + $changedFiles = $changedFilesJson | ConvertFrom-Json + + foreach ($file in $changedFiles) { + Write-Host "Processing: $file" + # Your processing logic here + } +``` + +## Limitations + +- Simple filter patterns only (no complex glob or regex patterns) + +## Pagination + +The action automatically handles pagination to fetch **all** changed files in a PR, regardless of how many files were changed: + +- Fetches files in batches of 100 per page +- Continues fetching until all files are retrieved +- Logs a note when pagination occurs, showing the total file count +- **No file limit** - all changed files will be processed, even in very large PRs + +This ensures that critical workflows (such as merge conflict checking, link validation, etc.) don't miss files due to pagination limits. + +## Related Actions + +- **markdownlinks**: Uses this pattern to get changed markdown files +- **merge-conflict-checker**: Uses this pattern to get changed files for conflict detection +- **path-filters**: Similar functionality but with more complex filtering logic diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml new file mode 100644 index 00000000000..c897d4f388d --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -0,0 +1,117 @@ +name: 'Get Changed Files' +description: 'Gets the list of files changed in a pull request or push event' +inputs: + filter: + description: 'Optional filter pattern (e.g., "*.md" for markdown files, ".github/" for GitHub files)' + required: false + default: '' + event-types: + description: 'Comma-separated list of event types to support (pull_request, push)' + required: false + default: 'pull_request' +outputs: + files: + description: 'JSON array of changed file paths' + value: ${{ steps.get-files.outputs.files }} + count: + description: 'Number of changed files' + value: ${{ steps.get-files.outputs.count }} +runs: + using: 'composite' + steps: + - name: Get changed files + id: get-files + uses: actions/github-script@v7 + with: + script: | + const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); + const filter = '${{ inputs.filter }}'; + let changedFiles = []; + + if (eventTypes.includes('pull_request') && context.eventName === 'pull_request') { + console.log(`Getting files changed in PR #${context.payload.pull_request.number}`); + + // Fetch all files changed in the PR with pagination + let allFiles = []; + let page = 1; + let fetchedCount; + + do { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + per_page: 100, + page: page + }); + + allFiles = allFiles.concat(files); + fetchedCount = files.length; + page++; + } while (fetchedCount === 100); + + if (allFiles.length >= 100) { + console.log(`Note: This PR has ${allFiles.length} changed files. All files fetched using pagination.`); + } + + changedFiles = allFiles + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else if (eventTypes.includes('push') && context.eventName === 'push') { + console.log(`Getting files changed in push to ${context.ref}`); + + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedFiles = comparison.files + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. Supported types: ${eventTypes.join(', ')}`); + return; + } + + // Apply filter if provided + if (filter) { + const filterLower = filter.toLowerCase(); + const beforeFilter = changedFiles.length; + changedFiles = changedFiles.filter(file => { + const fileLower = file.toLowerCase(); + // Support simple patterns like "*.md" or ".github/" + if (filterLower.startsWith('*.')) { + const ext = filterLower.substring(1); + return fileLower.endsWith(ext); + } else { + return fileLower.startsWith(filterLower); + } + }); + console.log(`Filter '${filter}' applied: ${beforeFilter} → ${changedFiles.length} files`); + } + + // Calculate simple hash for verification + const crypto = require('crypto'); + const filesJson = JSON.stringify(changedFiles.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + + // Log changed files in a collapsible group + core.startGroup(`Changed Files (${changedFiles.length} total, hash: ${hash})`); + if (changedFiles.length > 0) { + changedFiles.forEach(file => console.log(` - ${file}`)); + } else { + console.log(' (no files changed)'); + } + core.endGroup(); + + console.log(`Found ${changedFiles.length} changed files`); + core.setOutput('files', JSON.stringify(changedFiles)); + core.setOutput('count', changedFiles.length); + +branding: + icon: 'file-text' + color: 'blue' diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml index 1d6d0864784..de2952252d4 100644 --- a/.github/actions/infrastructure/markdownlinks/action.yml +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -31,52 +31,23 @@ runs: steps: - name: Get changed markdown files id: changed-files - uses: actions/github-script@v7 + uses: "./.github/actions/infrastructure/get-changed-files" with: - script: | - let changedMarkdownFiles = []; - - if (context.eventName === 'pull_request') { - const { data: files } = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.pull_request.number, - }); - - changedMarkdownFiles = files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else if (context.eventName === 'push') { - const { data: comparison } = await github.rest.repos.compareCommits({ - owner: context.repo.owner, - repo: context.repo.repo, - base: context.payload.before, - head: context.payload.after, - }); - - changedMarkdownFiles = comparison.files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else { - core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); - return; - } - - console.log('Changed markdown files:', changedMarkdownFiles); - core.setOutput('files', JSON.stringify(changedMarkdownFiles)); - core.setOutput('count', changedMarkdownFiles.length); - return changedMarkdownFiles; + filter: '*.md' + event-types: 'pull_request,push' - name: Verify markdown links id: verify shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} run: | Write-Host "Starting markdown link verification..." -ForegroundColor Cyan - # Get changed markdown files from previous step - $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + # Get changed markdown files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON $changedFiles = $changedFilesJson | ConvertFrom-Json - + if ($changedFiles.Count -eq 0) { Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow "total=0" >> $env:GITHUB_OUTPUT @@ -85,7 +56,7 @@ runs: "skipped=0" >> $env:GITHUB_OUTPUT exit 0 } - + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index ff07c4510fc..656719262b2 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -32,9 +32,16 @@ outputs: runs: using: composite steps: + - name: Get changed files + id: get-files + if: github.event_name == 'pull_request' + uses: "./.github/actions/infrastructure/get-changed-files" + - name: Check if GitHubWorkflowChanges is present id: filter uses: actions/github-script@v7.0.1 + env: + FILES_JSON: ${{ steps.get-files.outputs.files }} with: github-token: ${{ inputs.GITHUB_TOKEN }} script: | @@ -53,57 +60,71 @@ runs: return; } - console.log(`Getting files changed in PR #${context.issue.number}`); - - // Fetch the list of files changed in the PR - let files = []; - let page = 1; - let fetchedFiles; - do { - fetchedFiles = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - per_page: 100, - page: page++ - }); - files = files.concat(fetchedFiles.data); - } while (fetchedFiles.data.length > 0); - - const actionsChanged = files.some(file => file.filename.startsWith('.github/actions')); - const workflowsChanged = files.some(file => file.filename.startsWith('.github/workflows')); + // Get files from environment variable (secure against injection) + const files = JSON.parse(process.env.FILES_JSON || '[]'); + + // Calculate hash for verification (matches get-changed-files action) + const crypto = require('crypto'); + const filesJson = JSON.stringify(files.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + console.log(`Received ${files.length} files (hash: ${hash})`); + + // Analyze changes with detailed logging + core.startGroup('Path Filter Analysis'); + + const actionsChanged = files.some(file => file.startsWith('.github/actions')); + console.log(`✓ Actions changed: ${actionsChanged}`); + + const workflowsChanged = files.some(file => file.startsWith('.github/workflows')); + console.log(`✓ Workflows changed: ${workflowsChanged}`); + const githubChanged = actionsChanged || workflowsChanged; + console.log(`→ GitHub changed (actions OR workflows): ${githubChanged}`); + + const toolsCiPsm1Changed = files.some(file => file === 'tools/ci.psm1'); + console.log(`✓ tools/ci.psm1 changed: ${toolsCiPsm1Changed}`); + + const toolsBuildCommonChanged = files.some(file => file.startsWith('tools/buildCommon/')); + console.log(`✓ tools/buildCommon/ changed: ${toolsBuildCommonChanged}`); - const toolsCiPsm1Changed = files.some(file => file.filename.startsWith('tools/ci.psm1')); - const toolsBuildCommonChanged = files.some(file => file.filename.startsWith('tools/buildCommon/')); const toolsChanged = toolsCiPsm1Changed || toolsBuildCommonChanged; + console.log(`→ Tools changed: ${toolsChanged}`); - const propsChanged = files.some(file => file.filename.endsWith('.props')); + const propsChanged = files.some(file => file.endsWith('.props')); + console.log(`✓ Props files changed: ${propsChanged}`); - const testsChanged = files.some(file => file.filename.startsWith('test/powershell/') || file.filename.startsWith('test/tools/') || file.filename.startsWith('test/xUnit/')); + const testsChanged = files.some(file => file.startsWith('test/powershell/') || file.startsWith('test/tools/') || file.startsWith('test/xUnit/')); + console.log(`✓ Tests changed: ${testsChanged}`); - const mainSourceChanged = files.some(file => file.filename.startsWith('src/')); + const mainSourceChanged = files.some(file => file.startsWith('src/')); + console.log(`✓ Main source (src/) changed: ${mainSourceChanged}`); - const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); + const buildModuleChanged = files.some(file => file === 'build.psm1'); + console.log(`✓ build.psm1 changed: ${buildModuleChanged}`); - const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); + const globalConfigChanged = files.some(file => file === '.globalconfig' || file === 'nuget.config' || file === 'global.json'); + console.log(`✓ Global config changed: ${globalConfigChanged}`); const packagingChanged = files.some(file => - file.filename === '.github/workflows/windows-ci.yml' || - file.filename === '.github/workflows/linux-ci.yml' || - file.filename.startsWith('assets/wix/') || - file.filename === 'PowerShell.Common.props' || - file.filename.match(/^src\/.*\.csproj$/) || - file.filename.startsWith('test/packaging/windows/') || - file.filename.startsWith('test/packaging/linux/') || - file.filename.startsWith('tools/packaging/') || - file.filename.startsWith('tools/wix/') + file === '.github/workflows/windows-ci.yml' || + file === '.github/workflows/linux-ci.yml' || + file.startsWith('assets/wix/') || + file === 'PowerShell.Common.props' || + file.match(/^src\/.*\.csproj$/) || + file.startsWith('test/packaging/windows/') || + file.startsWith('test/packaging/linux/') || + file.startsWith('tools/packaging/') || + file.startsWith('tools/wix/') ) || buildModuleChanged || globalConfigChanged || toolsCiPsm1Changed; + console.log(`→ Packaging changed: ${packagingChanged}`); const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; + console.log(`→ Source (composite): ${source}`); + + core.endGroup(); core.setOutput('toolsChanged', toolsChanged); core.setOutput('githubChanged', githubChanged); @@ -114,16 +135,3 @@ runs: core.setOutput('globalConfigChanged', globalConfigChanged); core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); - - - - name: Capture outputs - run: | - Write-Verbose -Verbose "source: ${{ steps.filter.outputs.source }}" - Write-Verbose -Verbose "github: ${{ steps.filter.outputs.githubChanged }}" - Write-Verbose -Verbose "tools: ${{ steps.filter.outputs.toolsChanged }}" - Write-Verbose -Verbose "props: ${{ steps.filter.outputs.propsChanged }}" - Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" - Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" - Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" - Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" - shell: pwsh From eda7e4a889482f6b898660c9dcea6a6e878502f2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 30 Oct 2025 15:53:01 -0700 Subject: [PATCH 177/378] Make the experimental feature `PSFeedbackProvider` stable (#26343) --- .../host/msh/ConsoleHost.cs | 47 +-- .../ExperimentalFeature.cs | 5 - .../engine/hostifaces/HostUtilities.cs | 357 ------------------ .../resources/SuggestionStrings.resx | 9 - 4 files changed, 1 insertion(+), 417 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 7228cb31ee2..5f59540ecf4 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -2568,14 +2568,7 @@ internal void Run(bool inputLoopIsNested) // Evaluate any suggestions if (previousResponseWasEmpty == false) { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSFeedbackProvider)) - { - EvaluateFeedbacks(ui); - } - else - { - EvaluateSuggestions(ui); - } + EvaluateFeedbacks(ui); } // Then output the prompt @@ -2899,44 +2892,6 @@ private void EvaluateFeedbacks(ConsoleHostUserInterface ui) } } - private void EvaluateSuggestions(ConsoleHostUserInterface ui) - { - // Output any training suggestions - try - { - List suggestions = HostUtilities.GetSuggestion(_parent.Runspace); - - if (suggestions.Count > 0) - { - ui.WriteLine(); - } - - bool first = true; - foreach (string suggestion in suggestions) - { - if (!first) - ui.WriteLine(); - - ui.WriteLine(suggestion); - - first = false; - } - } - catch (TerminateException) - { - // A variable breakpoint may be hit by HostUtilities.GetSuggestion. The debugger throws TerminateExceptions to stop the execution - // of the current statement; we do not want to treat these exceptions as errors. - } - catch (Exception e) - { - // Catch-all OK. This is a third-party call-out. - ui.WriteErrorLine(e.Message); - - LocalRunspace localRunspace = (LocalRunspace)_parent.Runspace; - localRunspace.GetExecutionContext.AppendDollarError(e); - } - } - private string EvaluatePrompt() { string promptString = _promptExec.ExecuteCommandAndGetResultAsString("prompt", out _); diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 4ac98cb485e..1c17a22ae9a 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -21,7 +20,6 @@ public class ExperimentalFeature #region Const Members internal const string EngineSource = "PSEngine"; - internal const string PSFeedbackProvider = "PSFeedbackProvider"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); #endregion @@ -108,9 +106,6 @@ static ExperimentalFeature() new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), - new ExperimentalFeature( - name: PSFeedbackProvider, - description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 7c8ccd0d307..8e5d30be71f 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Management.Automation.Host; using System.Management.Automation.Internal; @@ -12,26 +10,10 @@ using System.Management.Automation.Subsystem.Feedback; using System.Runtime.InteropServices; using System.Text; -using System.Text.RegularExpressions; - -using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.Commands.Internal.Format; namespace System.Management.Automation { - internal enum SuggestionMatchType - { - /// Match on a command. - Command = 0, - /// Match based on exception message. - Error = 1, - /// Match by running a script block. - Dynamic = 2, - - /// Match by fully qualified ErrorId. - ErrorId = 3 - } - #region Public HostUtilities Class /// @@ -43,31 +25,6 @@ public static class HostUtilities private static readonly char s_actionIndicator = HostSupportUnicode() ? '\u27a4' : '>'; - private static readonly string s_checkForCommandInCurrentDirectoryScript = @" - [System.Diagnostics.DebuggerHidden()] - param() - - $foundSuggestion = $false - - if($lastError -and - ($lastError.Exception -is ""System.Management.Automation.CommandNotFoundException"")) - { - $escapedCommand = [System.Management.Automation.WildcardPattern]::Escape($lastError.TargetObject) - $foundSuggestion = @(Get-Command ($ExecutionContext.SessionState.Path.Combine(""."", $escapedCommand)) -ErrorAction Ignore).Count -gt 0 - } - - $foundSuggestion - "; - - private static readonly string s_createCommandExistsInCurrentDirectoryScript = @" - [System.Diagnostics.DebuggerHidden()] - param([string] $formatString) - - $formatString -f $lastError.TargetObject,"".\$($lastError.TargetObject)"" - "; - - private static readonly List s_suggestions = InitializeSuggestions(); - private static bool HostSupportUnicode() { // Reference: https://github.com/zkat/supports-unicode/blob/main/src/lib.rs @@ -87,23 +44,6 @@ private static bool HostSupportUnicode() return ctype.EndsWith("UTF8") || ctype.EndsWith("UTF-8"); } - private static List InitializeSuggestions() - { - var suggestions = new List() - { - NewSuggestion( - id: 3, - category: "General", - matchType: SuggestionMatchType.Dynamic, - rule: ScriptBlock.CreateDelayParsedScriptBlock(s_checkForCommandInCurrentDirectoryScript, isProductCode: true), - suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_createCommandExistsInCurrentDirectoryScript, isProductCode: true), - suggestionArgs: new object[] { SuggestionStrings.Suggestion_CommandExistsInCurrentDirectory_Legacy }, - enabled: true) - }; - - return suggestions; - } - #region GetProfileCommands /// /// Gets a PSObject whose base object is currentUserCurrentHost and with notes for the other 4 parameters. @@ -283,303 +223,6 @@ internal static string GetMaxLines(string source, int maxLines) return returnValue.ToString(); } - internal static List GetSuggestion(Runspace runspace) - { - if (runspace is not LocalRunspace localRunspace) - { - return new List(); - } - - // Get the last value of $? - bool questionMarkVariableValue = localRunspace.ExecutionContext.QuestionMarkVariableValue; - - // Get the last history item - History history = localRunspace.History; - HistoryInfo[] entries = history.GetEntries(-1, 1, true); - - if (entries.Length == 0) - return new List(); - - HistoryInfo lastHistory = entries[0]; - - // Get the last error - ArrayList errorList = (ArrayList)localRunspace.GetExecutionContext.DollarErrorVariable; - object lastError = null; - - if (errorList.Count > 0) - { - lastError = errorList[0] as Exception; - ErrorRecord lastErrorRecord = null; - - // The error was an actual ErrorRecord - if (lastError == null) - { - lastErrorRecord = errorList[0] as ErrorRecord; - } - else if (lastError is RuntimeException) - { - lastErrorRecord = ((RuntimeException)lastError).ErrorRecord; - } - - // If we got information about the error invocation, - // we can be more careful with the errors we pass along - if ((lastErrorRecord != null) && (lastErrorRecord.InvocationInfo != null)) - { - if (lastErrorRecord.InvocationInfo.HistoryId == lastHistory.Id) - lastError = lastErrorRecord; - else - lastError = null; - } - } - - Runspace oldDefault = null; - bool changedDefault = false; - if (Runspace.DefaultRunspace != runspace) - { - oldDefault = Runspace.DefaultRunspace; - changedDefault = true; - Runspace.DefaultRunspace = runspace; - } - - List suggestions = null; - - try - { - suggestions = GetSuggestion(lastHistory, lastError, errorList); - } - finally - { - if (changedDefault) - { - Runspace.DefaultRunspace = oldDefault; - } - } - - // Restore $? - localRunspace.ExecutionContext.QuestionMarkVariableValue = questionMarkVariableValue; - return suggestions; - } - - [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")] - internal static List GetSuggestion(HistoryInfo lastHistory, object lastError, ArrayList errorList) - { - var returnSuggestions = new List(); - - PSModuleInfo invocationModule = new PSModuleInfo(true); - invocationModule.SessionState.PSVariable.Set("lastHistory", lastHistory); - invocationModule.SessionState.PSVariable.Set("lastError", lastError); - - int initialErrorCount = 0; - - // Go through all of the suggestions - foreach (Hashtable suggestion in s_suggestions) - { - initialErrorCount = errorList.Count; - - // Make sure the rule is enabled - if (!LanguagePrimitives.IsTrue(suggestion["Enabled"])) - continue; - - SuggestionMatchType matchType = (SuggestionMatchType)LanguagePrimitives.ConvertTo( - suggestion["MatchType"], - typeof(SuggestionMatchType), - CultureInfo.InvariantCulture); - - // If this is a dynamic match, evaluate the ScriptBlock - if (matchType == SuggestionMatchType.Dynamic) - { - object result = null; - - ScriptBlock evaluator = suggestion["Rule"] as ScriptBlock; - if (evaluator == null) - { - suggestion["Enabled"] = false; - - throw new ArgumentException( - SuggestionStrings.RuleMustBeScriptBlock, "Rule"); - } - - try - { - result = invocationModule.Invoke(evaluator, null); - } - catch (Exception) - { - // Catch-all OK. This is a third-party call-out. - suggestion["Enabled"] = false; - continue; - } - - // If it returned results, evaluate its suggestion - if (LanguagePrimitives.IsTrue(result)) - { - string suggestionText = GetSuggestionText(suggestion["Suggestion"], (object[])suggestion["SuggestionArgs"], invocationModule); - - if (!string.IsNullOrEmpty(suggestionText)) - { - string returnString = string.Format( - CultureInfo.CurrentCulture, - "Suggestion [{0},{1}]: {2}", - (int)suggestion["Id"], - (string)suggestion["Category"], - suggestionText); - - returnSuggestions.Add(returnString); - } - } - } - else - { - string matchText = string.Empty; - - // Otherwise, this is a Regex match against the - // command or error - if (matchType == SuggestionMatchType.Command) - { - matchText = lastHistory.CommandLine; - } - else if (matchType == SuggestionMatchType.Error) - { - if (lastError != null) - { - Exception lastException = lastError as Exception; - if (lastException != null) - { - matchText = lastException.Message; - } - else - { - matchText = lastError.ToString(); - } - } - } - else if (matchType == SuggestionMatchType.ErrorId) - { - if (lastError != null && lastError is ErrorRecord errorRecord) - { - matchText = errorRecord.FullyQualifiedErrorId; - } - } - else - { - suggestion["Enabled"] = false; - - throw new ArgumentException( - SuggestionStrings.InvalidMatchType, - "MatchType"); - } - - // If the text matches, evaluate the suggestion - if (Regex.IsMatch(matchText, (string)suggestion["Rule"], RegexOptions.IgnoreCase)) - { - string suggestionText = GetSuggestionText(suggestion["Suggestion"], (object[])suggestion["SuggestionArgs"], invocationModule); - - if (!string.IsNullOrEmpty(suggestionText)) - { - string returnString = string.Format( - CultureInfo.CurrentCulture, - "Suggestion [{0},{1}]: {2}", - (int)suggestion["Id"], - (string)suggestion["Category"], - suggestionText); - - returnSuggestions.Add(returnString); - } - } - } - - // If the rule generated an error, disable it - if (errorList.Count != initialErrorCount) - { - suggestion["Enabled"] = false; - } - } - - return returnSuggestions; - } - - /// - /// Create suggestion with string rule and scriptblock suggestion. - /// - /// Identifier for the suggestion. - /// Category for the suggestion. - /// Suggestion match type. - /// Rule to match. - /// Scriptblock to run that returns the suggestion. - /// Arguments to pass to suggestion scriptblock. - /// True if the suggestion is enabled. - /// Hashtable representing the suggestion. - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, string rule, ScriptBlock suggestion, object[] suggestionArgs, bool enabled) - { - Hashtable result = new Hashtable(StringComparer.CurrentCultureIgnoreCase); - - result["Id"] = id; - result["Category"] = category; - result["MatchType"] = matchType; - result["Rule"] = rule; - result["Suggestion"] = suggestion; - result["SuggestionArgs"] = suggestionArgs; - result["Enabled"] = enabled; - - return result; - } - - /// - /// Create suggestion with scriptblock rule and suggestion. - /// - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, ScriptBlock rule, ScriptBlock suggestion, bool enabled) - { - Hashtable result = new Hashtable(StringComparer.CurrentCultureIgnoreCase); - - result["Id"] = id; - result["Category"] = category; - result["MatchType"] = matchType; - result["Rule"] = rule; - result["Suggestion"] = suggestion; - result["Enabled"] = enabled; - - return result; - } - - /// - /// Create suggestion with scriptblock rule and scriptblock suggestion with arguments. - /// - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, ScriptBlock rule, ScriptBlock suggestion, object[] suggestionArgs, bool enabled) - { - Hashtable result = NewSuggestion(id, category, matchType, rule, suggestion, enabled); - result.Add("SuggestionArgs", suggestionArgs); - - return result; - } - - /// - /// Get suggestion text from suggestion scriptblock with arguments. - /// - private static string GetSuggestionText(object suggestion, object[] suggestionArgs, PSModuleInfo invocationModule) - { - if (suggestion is ScriptBlock) - { - ScriptBlock suggestionScript = (ScriptBlock)suggestion; - - object result = null; - try - { - result = invocationModule.Invoke(suggestionScript, suggestionArgs); - } - catch (Exception) - { - // Catch-all OK. This is a third-party call-out. - return string.Empty; - } - - return (string)LanguagePrimitives.ConvertTo(result, typeof(string), CultureInfo.CurrentCulture); - } - else - { - return (string)LanguagePrimitives.ConvertTo(suggestion, typeof(string), CultureInfo.CurrentCulture); - } - } - /// /// Returns the prompt used in remote sessions: "[machine]: basePrompt" /// diff --git a/src/System.Management.Automation/resources/SuggestionStrings.resx b/src/System.Management.Automation/resources/SuggestionStrings.resx index 9e325b2616c..39fbc3469f2 100644 --- a/src/System.Management.Automation/resources/SuggestionStrings.resx +++ b/src/System.Management.Automation/resources/SuggestionStrings.resx @@ -123,16 +123,7 @@ PowerShell does not load commands from the current location by default (see 'Get If you trust this command, run the following command instead: - - The command "{0}" was not found, but does exist in the current location. PowerShell does not load commands from the current location by default. If you trust this command, instead type: "{1}". See "get-help about_Command_Precedence" for more details. - The most similar commands are: - - Rule must be a ScriptBlock for dynamic match types. - - - MatchType must be 'Command', 'Error', or 'Dynamic'. - From c12322323dff4d37781e6480aa578bd5eb9ad88f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 10:08:40 -0700 Subject: [PATCH 178/378] Bump github/codeql-action from 4.31.0 to 4.31.2 (#26359) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 10b2f0893a3..a16a840a606 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ffd2f3f1420..4246af344fd 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 with: sarif_file: results.sarif From 0c40a84abb39dfeb50c686e119bf8e18b12aab34 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:00:55 +0000 Subject: [PATCH 179/378] Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26350) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Travis Plunk (HE/HIM) --- .../merge-conflict-checker/README.md | 84 ++++++ .../merge-conflict-checker/action.yml | 36 +++ .../actions/test/linux-packaging/action.yml | 6 + ...rshell-automatic-variables.instructions.md | 159 ++++++++++++ ...rshell-module-organization.instructions.md | 201 +++++++++++++++ .github/workflows/linux-ci.yml | 58 +++++ .github/workflows/macos-ci.yml | 8 + .vsts-ci/templates/nanoserver.yml | 61 ----- test/infrastructure/ciModule.Tests.ps1 | 240 ++++++++++++++++++ tools/ci.psm1 | 210 ++++++++++++++- 10 files changed, 1001 insertions(+), 62 deletions(-) create mode 100644 .github/actions/infrastructure/merge-conflict-checker/README.md create mode 100644 .github/actions/infrastructure/merge-conflict-checker/action.yml create mode 100644 .github/instructions/powershell-automatic-variables.instructions.md create mode 100644 .github/instructions/powershell-module-organization.instructions.md delete mode 100644 .vsts-ci/templates/nanoserver.yml create mode 100644 test/infrastructure/ciModule.Tests.ps1 diff --git a/.github/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md new file mode 100644 index 00000000000..aeae4a29b93 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -0,0 +1,84 @@ +# Merge Conflict Checker + +This composite GitHub Action checks for Git merge conflict markers in files changed in pull requests. + +## Purpose + +Automatically detects leftover merge conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in pull request files to prevent them from being merged into the codebase. + +## Usage + +### In a Workflow + +```yaml +- name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +### Complete Example + +```yaml +jobs: + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +## How It Works + +1. **File Detection**: Uses GitHub's API to get the list of files changed in the pull request +2. **Marker Scanning**: Reads each changed file and searches for the following markers: + - `<<<<<<<` (conflict start marker) + - `=======` (conflict separator) + - `>>>>>>>` (conflict end marker) +3. **Result Reporting**: + - If markers are found, the action fails and lists all affected files + - If no markers are found, the action succeeds + +## Outputs + +- `files-checked`: Number of files that were checked +- `conflicts-found`: Number of files containing merge conflict markers + +## Behavior + +- **Event Support**: Only works with `pull_request` events +- **File Handling**: + - Checks only files that were added, modified, or renamed + - Skips deleted files + - Skips binary/unreadable files + - Skips directories + +## Example Output + +When conflict markers are detected: + +``` +❌ Merge conflict markers detected in the following files: + - src/example.cs + Markers found: <<<<<<<, =======, >>>>>>> + - README.md + Markers found: <<<<<<<, =======, >>>>>>> + +Please resolve these conflicts before merging. +``` + +When no markers are found: + +``` +✅ No merge conflict markers found +``` + +## Integration + +This action is integrated into the `linux-ci.yml` workflow and runs automatically on all pull requests to ensure code quality before merging. diff --git a/.github/actions/infrastructure/merge-conflict-checker/action.yml b/.github/actions/infrastructure/merge-conflict-checker/action.yml new file mode 100644 index 00000000000..a86cfa5470a --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -0,0 +1,36 @@ +name: 'Check for Merge Conflict Markers' +description: 'Checks for Git merge conflict markers in changed files for pull requests' +author: 'PowerShell Team' + +outputs: + files-checked: + description: 'Number of files checked for merge conflict markers' + value: ${{ steps.check.outputs.files-checked }} + conflicts-found: + description: 'Number of files with merge conflict markers' + value: ${{ steps.check.outputs.conflicts-found }} + +runs: + using: 'composite' + steps: + - name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + + - name: Check for merge conflict markers + id: check + shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} + run: | + # Get changed files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON + $changedFiles = $changedFilesJson | ConvertFrom-Json + + # Import ci.psm1 and run the check + Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force + Test-MergeConflictMarker -File $changedFiles -WorkspacePath $env:GITHUB_WORKSPACE + +branding: + icon: 'alert-triangle' + color: 'red' diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index d0c72c7b035..3a61e0751c7 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -31,6 +31,12 @@ runs: Invoke-CIFinish shell: pwsh + - name: Install Pester + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Validate Package Names run: |- # Run Pester tests to validate package names diff --git a/.github/instructions/powershell-automatic-variables.instructions.md b/.github/instructions/powershell-automatic-variables.instructions.md new file mode 100644 index 00000000000..5015847f41f --- /dev/null +++ b/.github/instructions/powershell-automatic-variables.instructions.md @@ -0,0 +1,159 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# PowerShell Automatic Variables - Naming Guidelines + +## Purpose + +This instruction provides guidelines for avoiding conflicts with PowerShell's automatic variables when writing PowerShell scripts and modules. + +## What Are Automatic Variables? + +PowerShell has built-in automatic variables that are created and maintained by PowerShell itself. Assigning values to these variables can cause unexpected behavior and side effects. + +## Common Automatic Variables to Avoid + +### Critical Variables (Never Use) + +- **`$matches`** - Contains the results of regular expression matches. Overwriting this can break regex operations. +- **`$_`** - Represents the current object in the pipeline. Only use within pipeline blocks. +- **`$PSItem`** - Alias for `$_`. Same rules apply. +- **`$args`** - Contains an array of undeclared parameters. Don't use as a regular variable. +- **`$input`** - Contains an enumerator of all input passed to a function. Don't reassign. +- **`$LastExitCode`** - Exit code of the last native command. Don't overwrite unless intentional. +- **`$?`** - Success status of the last command. Don't use as a variable name. +- **`$$`** - Last token in the last line received by the session. Don't use. +- **`$^`** - First token in the last line received by the session. Don't use. + +### Context Variables (Use with Caution) + +- **`$Error`** - Array of error objects. Don't replace, but can modify (e.g., `$Error.Clear()`). +- **`$PSBoundParameters`** - Parameters passed to the current function. Read-only. +- **`$MyInvocation`** - Information about the current command. Read-only. +- **`$PSCmdlet`** - Cmdlet object for advanced functions. Read-only. + +### Other Common Automatic Variables + +- `$true`, `$false`, `$null` - Boolean and null constants +- `$HOME`, `$PSHome`, `$PWD` - Path-related variables +- `$PID` - Process ID of the current PowerShell session +- `$Host` - Host application object +- `$PSVersionTable` - PowerShell version information + +For a complete list, see: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables + +## Best Practices + +### ❌ Bad - Using Automatic Variable Names + +```powershell +# Bad: $matches is an automatic variable used for regex capture groups +$matches = Select-String -Path $file -Pattern $pattern + +# Bad: $args is an automatic variable for undeclared parameters +$args = Get-ChildItem + +# Bad: $input is an automatic variable for pipeline input +$input = Read-Host "Enter value" +``` + +### ✅ Good - Using Descriptive Alternative Names + +```powershell +# Good: Use descriptive names that avoid conflicts +$matchedLines = Select-String -Path $file -Pattern $pattern + +# Good: Use specific names for arguments +$arguments = Get-ChildItem + +# Good: Use specific names for user input +$userInput = Read-Host "Enter value" +``` + +## Naming Alternatives + +When you encounter a situation where you might use an automatic variable name, use these alternatives: + +| Avoid | Use Instead | +|-------|-------------| +| `$matches` | `$matchedLines`, `$matchResults`, `$regexMatches` | +| `$args` | `$arguments`, `$parameters`, `$commandArgs` | +| `$input` | `$userInput`, `$inputValue`, `$inputData` | +| `$_` (outside pipeline) | Use a named parameter or explicit variable | +| `$Error` (reassignment) | Don't reassign; use `$Error.Clear()` if needed | + +## How to Check + +### PSScriptAnalyzer Rule + +PSScriptAnalyzer has a built-in rule that detects assignments to automatic variables: + +```powershell +# This will trigger PSAvoidAssignmentToAutomaticVariable +$matches = Get-Something +``` + +**Rule ID**: PSAvoidAssignmentToAutomaticVariable + +### Manual Review + +When writing PowerShell code, always: +1. Avoid variable names that match PowerShell keywords or automatic variables +2. Use descriptive, specific names that clearly indicate the variable's purpose +3. Run PSScriptAnalyzer on your code before committing +4. Review code for variable naming during PR reviews + +## Examples from the Codebase + +### Example 1: Regex Matching + +```powershell +# ❌ Bad - Overwrites automatic $matches variable +$matches = [regex]::Matches($content, $pattern) + +# ✅ Good - Uses descriptive name +$regexMatches = [regex]::Matches($content, $pattern) +``` + +### Example 2: Select-String Results + +```powershell +# ❌ Bad - Conflicts with automatic $matches +$matches = Select-String -Path $file -Pattern $pattern + +# ✅ Good - Clear and specific +$matchedLines = Select-String -Path $file -Pattern $pattern +``` + +### Example 3: Collecting Arguments + +```powershell +# ❌ Bad - Conflicts with automatic $args +function Process-Items { + $args = $MyItems + # ... process items +} + +# ✅ Good - Descriptive parameter name +function Process-Items { + [CmdletBinding()] + param( + [Parameter(ValueFromRemainingArguments)] + [string[]]$Items + ) + # ... process items +} +``` + +## References + +- [PowerShell Automatic Variables Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables) +- [PSScriptAnalyzer Rules](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/README.md) +- [PowerShell Best Practices](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) + +## Summary + +**Key Takeaway**: Always use descriptive, specific variable names that clearly indicate their purpose and avoid conflicts with PowerShell's automatic variables. When in doubt, choose a longer, more descriptive name over a short one that might conflict. diff --git a/.github/instructions/powershell-module-organization.instructions.md b/.github/instructions/powershell-module-organization.instructions.md new file mode 100644 index 00000000000..461d19fb5df --- /dev/null +++ b/.github/instructions/powershell-module-organization.instructions.md @@ -0,0 +1,201 @@ +--- +applyTo: + - "tools/ci.psm1" + - "build.psm1" + - "tools/packaging/**/*.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Guidelines for PowerShell Code Organization + +## When to Move Code from YAML to PowerShell Modules + +PowerShell code in GitHub Actions YAML files should be kept minimal. Move code to a module when: + +### Size Threshold +- **More than ~30 lines** of PowerShell in a YAML file step +- **Any use of .NET types** like `[regex]`, `[System.IO.Path]`, etc. +- **Complex logic** requiring multiple nested loops or conditionals +- **Reusable functionality** that might be needed elsewhere + +### Indicators to Move Code +1. Using .NET type accelerators (`[regex]`, `[PSCustomObject]`, etc.) +2. Complex string manipulation or parsing +3. File system operations beyond basic reads/writes +4. Logic that would benefit from unit testing +5. Code that's difficult to read/maintain in YAML format + +## Which Module to Use + +### ci.psm1 (`tools/ci.psm1`) +**Purpose**: CI/CD-specific operations and workflows + +**Use for**: +- Build orchestration (invoking builds, tests, packaging) +- CI environment setup and configuration +- Test execution and result processing +- Artifact handling and publishing +- CI-specific validations and checks +- Environment variable management for CI + +**Examples**: +- `Invoke-CIBuild` - Orchestrates build process +- `Invoke-CITest` - Runs Pester tests +- `Test-MergeConflictMarker` - Validates files for conflicts +- `Set-BuildVariable` - Manages CI variables + +**When NOT to use**: +- Core build operations (use build.psm1) +- Package creation logic (use packaging.psm1) +- Platform-specific build steps + +### build.psm1 (`build.psm1`) +**Purpose**: Core build operations and utilities + +**Use for**: +- Compiling source code +- Resource generation +- Build configuration management +- Core build utilities (New-PSOptions, Get-PSOutput, etc.) +- Bootstrap operations +- Cross-platform build helpers + +**Examples**: +- `Start-PSBuild` - Main build function +- `Start-PSBootstrap` - Bootstrap dependencies +- `New-PSOptions` - Create build configuration +- `Start-ResGen` - Generate resources + +**When NOT to use**: +- CI workflow orchestration (use ci.psm1) +- Package creation (use packaging.psm1) +- Test execution + +### packaging.psm1 (`tools/packaging/packaging.psm1`) +**Purpose**: Package creation and distribution + +**Use for**: +- Creating distribution packages (MSI, RPM, DEB, etc.) +- Package-specific metadata generation +- Package signing operations +- Platform-specific packaging logic + +**Examples**: +- `Start-PSPackage` - Create packages +- `New-MSIPackage` - Create Windows MSI +- `New-DotnetSdkContainerFxdPackage` - Create container packages + +**When NOT to use**: +- Building binaries (use build.psm1) +- Running tests (use ci.psm1) +- General utilities + +## Best Practices + +### Keep YAML Minimal +```yaml +# ❌ Bad - too much logic in YAML +- name: Check files + shell: pwsh + run: | + $files = Get-ChildItem -Recurse + foreach ($file in $files) { + $content = Get-Content $file -Raw + if ($content -match $pattern) { + # ... complex processing ... + } + } + +# ✅ Good - call function from module +- name: Check files + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Test-SomeCondition -Path ${{ github.workspace }} +``` + +### Document Functions +Always include comment-based help for functions: +```powershell +function Test-MyFunction +{ + <# + .SYNOPSIS + Brief description + .DESCRIPTION + Detailed description + .PARAMETER ParameterName + Parameter description + .EXAMPLE + Test-MyFunction -ParameterName Value + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $ParameterName + ) + # Implementation +} +``` + +### Error Handling +Use proper error handling in modules: +```powershell +try { + # Operation +} +catch { + Write-Error "Detailed error message: $_" + throw +} +``` + +### Verbose Output +Use `Write-Verbose` for debugging information: +```powershell +Write-Verbose "Processing file: $filePath" +``` + +## Module Dependencies + +- **ci.psm1** imports both `build.psm1` and `packaging.psm1` +- **build.psm1** is standalone (minimal dependencies) +- **packaging.psm1** imports `build.psm1` + +When adding new functions, consider these import relationships to avoid circular dependencies. + +## Testing Modules + +Functions in modules should be testable: +```powershell +# Test locally +Import-Module ./tools/ci.psm1 -Force +Test-MyFunction -Parameter Value + +# Can be unit tested with Pester +Describe "Test-MyFunction" { + It "Should return expected result" { + # Test implementation + } +} +``` + +## Migration Checklist + +When moving code from YAML to a module: + +1. ✅ Determine which module is appropriate (ci, build, or packaging) +2. ✅ Create function with proper parameter validation +3. ✅ Add comment-based help documentation +4. ✅ Use `[CmdletBinding()]` for advanced function features +5. ✅ Include error handling +6. ✅ Add verbose output for debugging +7. ✅ Test the function independently +8. ✅ Update YAML to call the new function +9. ✅ Verify the workflow still works end-to-end + +## References + +- PowerShell Advanced Functions: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_advanced +- Comment-Based Help: https://learn.microsoft.com/powershell/scripting/developer/help/writing-help-for-windows-powershell-scripts-and-functions diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 8dc0e738ffd..2058bd61568 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -67,6 +67,20 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && (startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell') + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" + ci_build: name: Build PowerShell runs-on: ubuntu-latest @@ -158,6 +172,48 @@ jobs: runner_os: ubuntu-latest test_results_artifact_name: testResults-xunit + infrastructure_tests: + name: Infrastructure Tests + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1 + + - name: Install Pester + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Install-CIPester + + - name: Run Infrastructure Tests + shell: pwsh + run: | + $testResultsFolder = Join-Path $PWD "testResults" + New-Item -ItemType Directory -Path $testResultsFolder -Force | Out-Null + + $config = New-PesterConfiguration + $config.Run.Path = './test/infrastructure/' + $config.Run.PassThru = $true + $config.TestResult.Enabled = $true + $config.TestResult.OutputFormat = 'NUnitXml' + $config.TestResult.OutputPath = "$testResultsFolder/InfrastructureTests.xml" + $config.Output.Verbosity = 'Detailed' + + $result = Invoke-Pester -Configuration $config + + if ($result.FailedCount -gt 0 -or $result.Result -eq 'Failed') { + throw "Infrastructure tests failed" + } + + - name: Publish Test Results + uses: "./.github/actions/test/process-pester-results" + if: always() + with: + name: "InfrastructureTests" + testResultsFolder: "${{ github.workspace }}/testResults" + ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. # analyze: # name: CodeQL Analysis @@ -180,6 +236,8 @@ jobs: - linux_test_unelevated_ci - linux_test_unelevated_others - linux_packaging + - merge_conflict_check + - infrastructure_tests # - analyze if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 8a80b79f1c0..2ee96079049 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -187,6 +187,14 @@ jobs: $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks shell: pwsh + + - name: Install Pester + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Test package contents if: success() run: |- diff --git a/.vsts-ci/templates/nanoserver.yml b/.vsts-ci/templates/nanoserver.yml deleted file mode 100644 index ae9f639b3b2..00000000000 --- a/.vsts-ci/templates/nanoserver.yml +++ /dev/null @@ -1,61 +0,0 @@ -parameters: - vmImage: 'windows-latest' - jobName: 'Nanoserver_Tests' - continueOnError: false - -jobs: - -- job: ${{ parameters.jobName }} - variables: - scriptName: ${{ parameters.scriptName }} - - pool: - vmImage: ${{ parameters.vmImage }} - - displayName: ${{ parameters.jobName }} - - steps: - - script: | - set - displayName: Capture Environment - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - - pwsh: | - Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 - displayName: 'Install Pester' - continueOnError: true - - - pwsh: | - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $options = (Get-PSOptions) - $path = split-path -path $options.Output - Write-Verbose "Path: '$path'" -Verbose - $rootPath = split-Path -path $path - Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force - Invoke-Pester -Path ./test/nanoserver -OutputFormat NUnitXml -OutputFile ./test-nanoserver.xml - displayName: Test - condition: succeeded() - - - task: PublishTestResults@2 - condition: succeededOrFailed() - displayName: Publish Nanoserver Test Results **\test*.xml - inputs: - testRunner: NUnit - testResultsFiles: '**\test*.xml' - testRunTitle: nanoserver - mergeTestResults: true - failTaskOnFailedTests: true diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 new file mode 100644 index 00000000000..f88d5787fc9 --- /dev/null +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -0,0 +1,240 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# NOTE: This test file tests the Test-MergeConflictMarker function which detects Git merge conflict markers. +# IMPORTANT: Do NOT use here-strings or literal conflict markers (e.g., "<<<<<<<", "=======", ">>>>>>>") +# in this file, as they will trigger conflict marker detection in CI pipelines. +# Instead, use string multiplication (e.g., '<' * 7) to dynamically generate these markers at runtime. + +Describe "Test-MergeConflictMarker" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + + # Create a temporary test workspace + $script:testWorkspace = Join-Path $TestDrive "workspace" + New-Item -ItemType Directory -Path $script:testWorkspace -Force | Out-Null + + # Create temporary output files + $script:testOutputPath = Join-Path $TestDrive "outputs.txt" + $script:testSummaryPath = Join-Path $TestDrive "summary.md" + } + + AfterEach { + # Clean up test files after each test + if (Test-Path $script:testWorkspace) { + Get-ChildItem $script:testWorkspace -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue + } + Remove-Item $script:testOutputPath -Force -ErrorAction SilentlyContinue + Remove-Item $script:testSummaryPath -Force -ErrorAction SilentlyContinue + } + + Context "When no files are provided" { + It "Should handle empty file array" { + # The function parameter has Mandatory validation which rejects empty arrays by design + # This test verifies that behavior + $emptyArray = @() + { Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw -ExpectedMessage "*empty array*" + } + } + + Context "When files have no conflicts" { + It "Should pass for clean files" { + $testFile = Join-Path $script:testWorkspace "clean.txt" + "This is a clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("clean.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Conflicts Found" + } + } + + Context "When files have conflict markers" { + It "Should detect <<<<<<< marker" { + $testFile = Join-Path $script:testWorkspace "conflict1.txt" + "Some content`n" + ('<' * 7) + " HEAD`nConflicting content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict1.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=1" + } + + It "Should detect ======= marker" { + $testFile = Join-Path $script:testWorkspace "conflict2.txt" + "Some content`n" + ('=' * 7) + "`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict2.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect >>>>>>> marker" { + $testFile = Join-Path $script:testWorkspace "conflict3.txt" + "Some content`n" + ('>' * 7) + " branch-name`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict3.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect multiple markers in one file" { + $testFile = Join-Path $script:testWorkspace "conflict4.txt" + $content = "Some content`n" + ('<' * 7) + " HEAD`nContent A`n" + ('=' * 7) + "`nContent B`n" + ('>' * 7) + " branch`nMore content" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict4.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "Conflicts Detected" + $summary | Should -Match "conflict4.txt" + } + + It "Should detect conflicts in multiple files" { + $testFile1 = Join-Path $script:testWorkspace "conflict5.txt" + ('<' * 7) + " HEAD" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "conflict6.txt" + ('=' * 7) | Out-File $testFile2 -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict5.txt", "conflict6.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=2" + } + } + + Context "When markers are not at line start" { + It "Should not detect markers in middle of line" { + $testFile = Join-Path $script:testWorkspace "notconflict.txt" + "This line has <<<<<<< in the middle" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("notconflict.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should not detect markers with wrong number of characters" { + $testFile = Join-Path $script:testWorkspace "wrongcount.txt" + ('<' * 6) + " Only 6`n" + ('<' * 8) + " 8 characters" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("wrongcount.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When handling special file scenarios" { + It "Should skip non-existent files" { + Test-MergeConflictMarker -File @("nonexistent.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + } + + It "Should handle absolute paths" { + $testFile = Join-Path $script:testWorkspace "absolute.txt" + "Clean content" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @($testFile) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should handle mixed relative and absolute paths" { + $testFile1 = Join-Path $script:testWorkspace "relative.txt" + "Clean" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "absolute.txt" + "Clean" | Out-File $testFile2 -Encoding utf8 + + Test-MergeConflictMarker -File @("relative.txt", $testFile2) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When summary and output generation" { + It "Should generate proper GitHub Actions outputs format" { + $testFile = Join-Path $script:testWorkspace "test.txt" + "Clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("test.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Where-Object {$_ -match "^files-checked=\d+$"} | Should -Not -BeNullOrEmpty + $outputs | Where-Object {$_ -match "^conflicts-found=\d+$"} | Should -Not -BeNullOrEmpty + } + + It "Should generate markdown summary with conflict details" { + $testFile = Join-Path $script:testWorkspace "marked.txt" + $content = "Line 1`n" + ('<' * 7) + " HEAD`nLine 3`n" + ('=' * 7) + "`nLine 5" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("marked.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "# Merge Conflict Marker Check Results" + $summary | Should -Match "marked.txt" + $summary | Should -Match "\| Line \| Marker \|" + } + } +} + +Describe "Install-CIPester" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + } + + Context "When checking function exists" { + It "Should export Install-CIPester function" { + $function = Get-Command Install-CIPester -ErrorAction SilentlyContinue + $function | Should -Not -BeNullOrEmpty + $function.ModuleName | Should -Be 'ci' + } + + It "Should have expected parameters" { + $function = Get-Command Install-CIPester + $function.Parameters.Keys | Should -Contain 'MinimumVersion' + $function.Parameters.Keys | Should -Contain 'MaximumVersion' + $function.Parameters.Keys | Should -Contain 'Force' + } + + It "Should accept version parameters" { + $function = Get-Command Install-CIPester + $function.Parameters['MinimumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['MaximumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['Force'].ParameterType.Name | Should -Be 'SwitchParameter' + } + } + + Context "When validating real execution" { + # These tests only run in CI where we can safely install/test Pester + + It "Should successfully run without errors when Pester exists" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -ErrorAction Stop } | Should -Not -Throw + } + + It "Should accept custom version parameters" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion '5.99.99' -ErrorAction Stop } | Should -Not -Throw + } + } +} + diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 478435e8543..bcc816cc918 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -228,6 +228,45 @@ function Invoke-CIxUnit } } +# Install Pester module if not already installed with a compatible version +function Install-CIPester +{ + [CmdletBinding()] + param( + [string]$MinimumVersion = '5.0.0', + [string]$MaximumVersion = '5.99.99', + [switch]$Force + ) + + Write-Verbose "Checking for Pester module (required: $MinimumVersion - $MaximumVersion)" -Verbose + + # Check if a compatible version of Pester is already installed + $installedPester = Get-Module -Name Pester -ListAvailable | + Where-Object { $_.Version -ge $MinimumVersion -and $_.Version -le $MaximumVersion } | + Sort-Object -Property Version -Descending | + Select-Object -First 1 + + if ($installedPester -and -not $Force) { + Write-Host "Pester version $($installedPester.Version) is already installed and meets requirements" -ForegroundColor Green + return + } + + if ($Force) { + Write-Host "Installing Pester module (forced)" -ForegroundColor Yellow + } else { + Write-Host "Installing Pester module" -ForegroundColor Yellow + } + + try { + Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion $MaximumVersion -ErrorAction Stop + Write-Host "Successfully installed Pester module" -ForegroundColor Green + } + catch { + Write-Error "Failed to install Pester module: $_" + throw + } +} + # Implement CI 'Test_script' function Invoke-CITest { @@ -621,7 +660,7 @@ function Invoke-CIFinish # Install the latest Pester and import it $maximumPesterVersion = '4.99' - Install-Module Pester -Force -SkipPublisherCheck -MaximumVersion $maximumPesterVersion + Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion $maximumPesterVersion -Force Import-Module Pester -Force -MaximumVersion $maximumPesterVersion $testResultPath = Join-Path -Path $env:TEMP -ChildPath "win-package-$channel-$runtime.xml" @@ -977,3 +1016,172 @@ function Invoke-InitializeContainerStage { Write-Host "##vso[build.addbuildtag]$($selectedImage.JobName)" } } + +Function Test-MergeConflictMarker +{ + <# + .SYNOPSIS + Checks files for Git merge conflict markers and outputs results for GitHub Actions. + .DESCRIPTION + Scans the specified files for Git merge conflict markers (<<<<<<<, =======, >>>>>>>) + and generates console output, GitHub Actions outputs, and job summary. + Designed for use in GitHub Actions workflows. + .PARAMETER File + Array of file paths (relative or absolute) to check for merge conflict markers. + .PARAMETER WorkspacePath + Base workspace path for resolving relative paths. Defaults to current directory. + .PARAMETER OutputPath + Path to write GitHub Actions outputs. Defaults to $env:GITHUB_OUTPUT. + .PARAMETER SummaryPath + Path to write GitHub Actions job summary. Defaults to $env:GITHUB_STEP_SUMMARY. + .EXAMPLE + Test-MergeConflictMarker -File @('file1.txt', 'file2.cs') -WorkspacePath $env:GITHUB_WORKSPACE + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string[]] $File, + + [Parameter()] + [string] $WorkspacePath = $PWD, + + [Parameter()] + [string] $OutputPath = $env:GITHUB_OUTPUT, + + [Parameter()] + [string] $SummaryPath = $env:GITHUB_STEP_SUMMARY + ) + + Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan + + Write-Host "Checking $($File.Count) changed files for merge conflict markers" -ForegroundColor Cyan + + # Convert relative paths to absolute paths for processing + $absolutePaths = $File | ForEach-Object { + if ([System.IO.Path]::IsPathRooted($_)) { + $_ + } else { + Join-Path $WorkspacePath $_ + } + } + + $filesWithConflicts = @() + $filesChecked = 0 + + foreach ($filePath in $absolutePaths) { + # Check if file exists (might be deleted) + if (-not (Test-Path $filePath)) { + Write-Verbose " Skipping deleted file: $filePath" + continue + } + + # Skip binary files and directories + if ((Get-Item $filePath) -is [System.IO.DirectoryInfo]) { + continue + } + + $filesChecked++ + + # Get relative path for display + $relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) { + $filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) + } else { + $filePath + } + + Write-Host " Checking: $relativePath" -ForegroundColor Gray + + # Search for conflict markers using Select-String + try { + # Git conflict markers are 7 characters followed by a space or end of line + # Regex pattern breakdown: + # ^ - Matches the start of a line + # (<{7}|={7}|>{7}) - Matches exactly 7 consecutive '<', '=', or '>' characters (Git conflict markers) + # (\s|$) - Ensures the marker is followed by whitespace or end of line + $pattern = '^(<{7}|={7}|>{7})(\s|$)' + $matchedLines = Select-String -Path $filePath -Pattern $pattern -AllMatches -ErrorAction Stop + + if ($matchedLines) { + # Collect marker details with line numbers (Select-String provides LineNumber automatically) + $markerDetails = @() + + foreach ($match in $matchedLines) { + $markerDetails += [PSCustomObject]@{ + Marker = $match.Matches[0].Groups[1].Value + Line = $match.LineNumber + } + } + + $filesWithConflicts += [PSCustomObject]@{ + File = $relativePath + MarkerDetails = $markerDetails + } + + Write-Host " ❌ CONFLICT MARKERS FOUND in $relativePath" -ForegroundColor Red + foreach ($detail in $markerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + } + } + } + catch { + # Skip files that can't be read (likely binary) + Write-Verbose " Skipping unreadable file: $relativePath" + } + } + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=$filesChecked" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=$($filesWithConflicts.Count)" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + Write-Host "`nSummary:" -ForegroundColor Cyan + Write-Host " Files checked: $filesChecked" -ForegroundColor Cyan + Write-Host " Files with conflicts: $($filesWithConflicts.Count)" -ForegroundColor Cyan + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** $filesChecked +- **Files with Conflicts:** $($filesWithConflicts.Count) + +"@ + + if ($filesWithConflicts.Count -gt 0) { + Write-Host "`n❌ Merge conflict markers detected in the following files:" -ForegroundColor Red + + $summaryContent += "`n## ❌ Conflicts Detected`n`n" + $summaryContent += "The following files contain merge conflict markers:`n`n" + + foreach ($fileInfo in $filesWithConflicts) { + Write-Host " - $($fileInfo.File)" -ForegroundColor Red + + $summaryContent += "### 📄 ``$($fileInfo.File)```n`n" + $summaryContent += "| Line | Marker |`n" + $summaryContent += "|------|--------|`n" + + foreach ($detail in $fileInfo.MarkerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + $summaryContent += "| $($detail.Line) | ``$($detail.Marker)`` |`n" + } + $summaryContent += "`n" + } + + $summaryContent += "`n**Action Required:** Please resolve these conflicts before merging.`n" + Write-Host "`nPlease resolve these conflicts before merging." -ForegroundColor Red + } else { + Write-Host "`n✅ No merge conflict markers found" -ForegroundColor Green + $summaryContent += "`n## ✅ No Conflicts Found`n`nAll checked files are free of merge conflict markers.`n" + } + + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + + # Exit with error if conflicts found + if ($filesWithConflicts.Count -gt 0) { + throw "Merge conflict markers detected in $($filesWithConflicts.Count) file(s)" + } +} From 8851ab8170a770d9dfeedf8bf08bd9a160f2207b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 31 Oct 2025 22:52:40 +0000 Subject: [PATCH 180/378] Fix merge conflict checker for empty file lists and filter *.cs files (#26365) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../merge-conflict-checker/README.md | 2 + .../merge-conflict-checker/action.yml | 3 +- test/infrastructure/ciModule.Tests.ps1 | 14 +++-- tools/ci.psm1 | 62 +++++++++++++++++-- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/.github/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md index aeae4a29b93..b53d6f99964 100644 --- a/.github/actions/infrastructure/merge-conflict-checker/README.md +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -56,8 +56,10 @@ jobs: - **File Handling**: - Checks only files that were added, modified, or renamed - Skips deleted files + - **Filters out `*.cs` files** (C# files are excluded from merge conflict checking) - Skips binary/unreadable files - Skips directories +- **Empty File List**: Gracefully handles cases where no files need checking (e.g., PRs that only delete files) ## Example Output diff --git a/.github/actions/infrastructure/merge-conflict-checker/action.yml b/.github/actions/infrastructure/merge-conflict-checker/action.yml index a86cfa5470a..41c7d2ad941 100644 --- a/.github/actions/infrastructure/merge-conflict-checker/action.yml +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -25,7 +25,8 @@ runs: run: | # Get changed files from environment variable (secure against injection) $changedFilesJson = $env:CHANGED_FILES_JSON - $changedFiles = $changedFilesJson | ConvertFrom-Json + # Ensure we always have an array (ConvertFrom-Json returns null for empty JSON arrays) + $changedFiles = @($changedFilesJson | ConvertFrom-Json) # Import ci.psm1 and run the check Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 index f88d5787fc9..b7320ff49b7 100644 --- a/test/infrastructure/ciModule.Tests.ps1 +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -30,11 +30,17 @@ Describe "Test-MergeConflictMarker" { } Context "When no files are provided" { - It "Should handle empty file array" { - # The function parameter has Mandatory validation which rejects empty arrays by design - # This test verifies that behavior + It "Should handle empty file array gracefully" { + # The function now accepts empty arrays to handle cases like delete-only PRs $emptyArray = @() - { Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw -ExpectedMessage "*empty array*" + Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Files to Check" } } diff --git a/tools/ci.psm1 b/tools/ci.psm1 index bcc816cc918..b9d150ceacd 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -1039,8 +1039,9 @@ Function Test-MergeConflictMarker #> [CmdletBinding()] param( - [Parameter(Mandatory)] - [string[]] $File, + [Parameter()] + [AllowEmptyCollection()] + [string[]] $File = @(), [Parameter()] [string] $WorkspacePath = $PWD, @@ -1054,10 +1055,63 @@ Function Test-MergeConflictMarker Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan - Write-Host "Checking $($File.Count) changed files for merge conflict markers" -ForegroundColor Cyan + # Helper function to write outputs when no files to check + function Write-NoFilesOutput { + param( + [string]$Message, + [string]$OutputPath, + [string]$SummaryPath + ) + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** 0 +- **Files with Conflicts:** 0 + +## ℹ️ No Files to Check + +$Message + +"@ + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + } + + # Handle empty file list (e.g., when PR only deletes files) + if ($File.Count -eq 0) { + Write-Host "No files to check (empty file list)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "No files were provided for checking (this can happen when a PR only deletes files)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + # Filter out *.cs files from merge conflict checking + $filesToCheck = @($File | Where-Object { $_ -notlike "*.cs" }) + $filteredCount = $File.Count - $filesToCheck.Count + + if ($filteredCount -gt 0) { + Write-Host "Filtered out $filteredCount *.cs file(s) from merge conflict checking" -ForegroundColor Yellow + } + + if ($filesToCheck.Count -eq 0) { + Write-Host "No files to check after filtering (all files were *.cs)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "All $filteredCount file(s) were filtered out (*.cs files are excluded from merge conflict checking)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + Write-Host "Checking $($filesToCheck.Count) changed files for merge conflict markers" -ForegroundColor Cyan # Convert relative paths to absolute paths for processing - $absolutePaths = $File | ForEach-Object { + $absolutePaths = $filesToCheck | ForEach-Object { if ([System.IO.Path]::IsPathRooted($_)) { $_ } else { From 8814b04bb441470dc189a7cc4582d3982508a6fb Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 31 Oct 2025 15:56:08 -0700 Subject: [PATCH 181/378] Delete this way of collecting feedback (#26364) --- .../IssueManagement.IssueFeedbackForm.yml | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 .github/policies/IssueManagement.IssueFeedbackForm.yml diff --git a/.github/policies/IssueManagement.IssueFeedbackForm.yml b/.github/policies/IssueManagement.IssueFeedbackForm.yml deleted file mode 100644 index f42be69ab1e..00000000000 --- a/.github/policies/IssueManagement.IssueFeedbackForm.yml +++ /dev/null @@ -1,22 +0,0 @@ -id: IssueManagement.IssueFeedbackForm -name: GitOps.PullRequestIssueManagement -description: Bot to request the feedback for how we are doing in the repo, replies on closed PRs and issues that are NOT labeled with no activity -owner: -resource: repository -disabled: false -where: -configuration: - resourceManagementConfiguration: - eventResponderTasks: - - if: - - not: - hasLabel: - label: Resolution-No Activity - - isAction: - action: Closed - then: - - addReply: - reply: " 📣 Hey @${issueAuthor}, how did we do? We would love to hear your feedback with the link below! 🗣️ \n\n🔗 https://aka.ms/PSRepoFeedback " - triggerOnOwnActions: true -onFailure: -onSuccess: From c8f26fec50411558e46b0b1ce66767218200378f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:25:07 -0800 Subject: [PATCH 182/378] Update outdated test package references (#26368) --- .../BenchmarkDotNet.Extensions.csproj | 4 ++-- test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 74a4cf9e089..d67f17c60f9 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 9883c8b2d63..3274f04acec 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - - + + From 1ba59744157269451183598dd5bfc8e7924094c4 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 4 Nov 2025 15:18:16 -0800 Subject: [PATCH 183/378] Add Attack Surface Analyzer Script (#26379) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .gitignore | 3 + tools/AttackSurfaceAnalyzer/README.md | 249 +++++++ .../Run-AttackSurfaceAnalyzer.ps1 | 590 ++++++++++++++++ .../Summarize-AsaResults.ps1 | 636 ++++++++++++++++++ tools/AttackSurfaceAnalyzer/docker/Dockerfile | 134 ++++ 5 files changed, 1612 insertions(+) create mode 100644 tools/AttackSurfaceAnalyzer/README.md create mode 100644 tools/AttackSurfaceAnalyzer/Run-AttackSurfaceAnalyzer.ps1 create mode 100644 tools/AttackSurfaceAnalyzer/Summarize-AsaResults.ps1 create mode 100644 tools/AttackSurfaceAnalyzer/docker/Dockerfile diff --git a/.gitignore b/.gitignore index ccadde27182..f115e61e22d 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,9 @@ TestsResults*.xml ParallelXUnitResults.xml xUnitResults.xml +# Attack Surface Analyzer results +asa-results/ + # Resharper settings PowerShell.sln.DotSettings.user *.msp diff --git a/tools/AttackSurfaceAnalyzer/README.md b/tools/AttackSurfaceAnalyzer/README.md new file mode 100644 index 00000000000..f57bb21f8c4 --- /dev/null +++ b/tools/AttackSurfaceAnalyzer/README.md @@ -0,0 +1,249 @@ +# Attack Surface Analyzer Testing + +This directory contains tools for running Attack Surface Analyzer (ASA) tests on PowerShell MSI installations using Docker. + +## Overview + +Attack Surface Analyzer is a Microsoft tool that helps analyze changes to a system's attack surface. These scripts allow you to run ASA tests locally in a clean Windows container to analyze what changes when PowerShell is installed. + +## Files + +- **Run-AttackSurfaceAnalyzer.ps1** - PowerShell script to run ASA tests with official MSIs +- **Summarize-AsaResults.ps1** - PowerShell script to analyze and summarize ASA results +- **docker/Dockerfile** - Multi-stage Dockerfile for building a container image with ASA pre-installed +- **README.md** - This documentation file + +## Docker Architecture + +The Docker implementation uses a multi-stage build to optimize the testing and result extraction process: + +### Multi-Stage Build Stages + +1. **asa-runner**: Main execution environment + - Base: `mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022` + - Contains Attack Surface Analyzer CLI tools + - Runs the complete test workflow + - Generates reports in both `C:\work` and `C:\reports` directories + +1. **asa-reports**: Minimal results layer + - Base: `mcr.microsoft.com/windows/nanoserver:ltsc2022` + - Contains only the test reports from the runner stage + - Enables clean extraction of results without container internals + +1. **final**: Default stage (inherits from asa-runner) + - Provides backward compatibility + - Used when no specific build target is specified + +### Benefits + +- **Clean Result Extraction**: Reports are isolated in a dedicated layer +- **Efficient Transfer**: Only test results are copied, not the entire container filesystem +- **Fallback Support**: Script includes fallback to volume-based extraction if needed +- **Minimal Footprint**: Final results layer contains only the necessary output files + +## Prerequisites + +- Windows 10/11 or Windows Server +- Docker Desktop with Windows containers enabled +- PowerShell 5.1 or later +- **An official signed PowerShell MSI file** from a released build + +### MSI Requirements + +**Important:** This tool now requires an official, digitally signed PowerShell MSI from Microsoft releases: + +- **Must be signed** by Microsoft Corporation +- **Must be from an official release** (downloaded from [PowerShell Releases](https://github.com/PowerShell/PowerShell/releases)) +- **Local builds are not supported** - unsigned or development MSIs will be rejected +- The script automatically verifies the digital signature before proceeding + +**Where to get official MSIs:** + +- Download from: https://github.com/PowerShell/PowerShell/releases +- Look for files like: `PowerShell-7.x.x-win-x64.msi` + +## Quick Start + +### Option 1: Using the PowerShell Script (Recommended) + +The script requires an official signed PowerShell MSI file: + +```powershell +# Run ASA test with official MSI (MsiPath is required) +.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath "C:\path\to\PowerShell-7.4.0-win-x64.msi" + +# Specify custom output directory for results +.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath ".\PowerShell-7.4.0-win-x64.msi" -OutputPath "C:\asa-results" + +# Keep the temporary work directory for debugging +.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath ".\PowerShell-7.4.0-win-x64.msi" -KeepWorkDirectory +``` + +The script will: + +1. **Verify MSI signature** - Ensures the MSI is officially signed by Microsoft Corporation +1. Create a temporary work directory +1. Build a custom Docker container from the static Dockerfile +1. Start the Windows container with Attack Surface Analyzer +1. Take a baseline snapshot +1. Install the PowerShell MSI +1. Take a post-installation snapshot +1. Export comparison results +1. Copy results back to your specified output directory + +**Security Note:** The script will reject any MSI that is not digitally signed by Microsoft Corporation to ensure analysis is performed only on official releases. + +### Option 2: Using the Dockerfile + +If you prefer to build and use the container image directly: + +```powershell +# Build the Docker image (Dockerfile is in docker subfolder with clean context) +docker build -f tools\AttackSurfaceAnalyzer\docker\Dockerfile -t powershell-asa-test tools\AttackSurfaceAnalyzer\docker\ + +# Run the container with your MSI (script is built into the container) +docker run --rm --isolation process ` + -v "C:\path\to\msi\directory:C:\work" ` + powershell-asa-test +``` + +## Output Files + +The test will generate output files in the `./asa-results/` directory (or your specified `-OutputPath`): + +- **`asa.sqlite`** - SQLite database with full analysis data (primary result file) +- **`install.log`** - MSI installation log file +- **`*_summary.json.txt`** - Summary of detected changes (if generated) +- **`*_results.json.txt`** - Detailed results in JSON format (if generated) +- **`*.sarif`** - SARIF format results (if generated, can be viewed in VS Code) + +## Analyzing Results + +### Using the Summary Script (Recommended) + +Use the included summary script to get a comprehensive analysis: + +```powershell +# Basic summary of ASA results +.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1 + +# Detailed analysis with rule breakdowns +.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1 -ShowDetails + +# Analyze results from a specific location +.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1 -Path "C:\custom\path\asa-results.json" -ShowDetails +``` + +The summary script provides: + +- **Overall statistics** - Total findings, analysis levels, category breakdowns +- **Rule analysis** - Which security rules were triggered and how often +- **File analysis** - Detailed breakdown of file-related security issues by rule type +- **Category cross-reference** - Shows which rules affect which categories + +### Using VS Code + +The SARIF files can be opened directly in VS Code with the SARIF Viewer extension to see a formatted view of the findings. + +### Using PowerShell + +```powershell +# Read the JSON results directly +$results = Get-Content "asa-results\asa-results.json" | ConvertFrom-Json +$results.Results.FILE_CREATED.Count # Number of files created + +# Query the SQLite database (requires SQLite tools) +# Example: List all file changes +# sqlite3 asa.sqlite "SELECT * FROM file_system WHERE change_type != 'NONE'" +``` + +## Troubleshooting + +### Docker Not Available + +The script automatically handles Docker Desktop installation and startup: + +**If Docker Desktop is installed but not running:** + +- The script will automatically start Docker Desktop for you +- It waits up to 60 seconds for Docker to become available +- You'll be prompted for confirmation (supports `-Confirm` and `-WhatIf`) + +**If Docker Desktop is not installed:** + +- The script will prompt you to install it automatically using winget +- After installation completes, start Docker Desktop and run the script again + +**Manual Installation:** + +1. Install Docker Desktop from https://www.docker.com/products/docker-desktop +1. Ensure Docker is running +1. Switch to Windows containers (right-click Docker tray icon → "Switch to Windows containers") + +### Container Fails to Start + +- Ensure you have enough disk space (containers can be large) +- Check that Windows containers are enabled in Docker settings +- Try pulling the base image manually: `docker pull mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022` + +### MSI Signature Verification Fails + +If you get signature verification errors: + +- **Ensure you're using an official MSI** from [PowerShell Releases](https://github.com/PowerShell/PowerShell/releases) +- **Do not use local builds** - only signed release MSIs are supported +- **Check certificate validity** - very old MSIs may have expired certificates +- **Verify file integrity** - redownload the MSI if it may be corrupted + +### No Results Generated + +- Check the install.log file for MSI installation errors +- Run with `-KeepWorkDirectory` to inspect the temporary work directory +- Verify the MSI file is valid and not corrupted + +## Advanced Usage + +### Parameters + +The `Run-AttackSurfaceAnalyzer.ps1` script supports these parameters: + +- **`-MsiPath`** (Required) - Path to the official signed PowerShell MSI file +- **`-OutputPath`** (Optional) - Directory for results (defaults to `./asa-results`) +- **`-ContainerImage`** (Optional) - Custom container base image +- **`-KeepWorkDirectory`** (Optional) - Keep temp directory for debugging + +Example with custom container image: + +```powershell +.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 ` + -MsiPath ".\PowerShell-7.4.0-win-x64.msi" ` + -ContainerImage "mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022" +``` + +### Debugging + +To debug issues, keep the work directory and examine the files: + +```powershell +.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -KeepWorkDirectory + +# The script will print the work directory path +# You can then examine: +# - run-asa.ps1 - The script that runs in the container +# - install.log - MSI installation log +# - Any other generated files +``` + +## Integration with CI/CD + +These tools were extracted from the GitHub Actions workflow to allow local testing. If you need to integrate ASA testing back into a CI/CD pipeline, you can: + +1. Use the PowerShell script directly in your pipeline +1. Build and push the Docker image to a registry +1. Use the Dockerfile as a base for custom testing scenarios + +## More Information + +- [Attack Surface Analyzer on GitHub](https://github.com/microsoft/AttackSurfaceAnalyzer) +- [Docker for Windows Documentation](https://docs.docker.com/desktop/windows/) +- [SARIF Documentation](https://sarifweb.azurewebsites.net/) diff --git a/tools/AttackSurfaceAnalyzer/Run-AttackSurfaceAnalyzer.ps1 b/tools/AttackSurfaceAnalyzer/Run-AttackSurfaceAnalyzer.ps1 new file mode 100644 index 00000000000..2f7e502bff6 --- /dev/null +++ b/tools/AttackSurfaceAnalyzer/Run-AttackSurfaceAnalyzer.ps1 @@ -0,0 +1,590 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Run Attack Surface Analyzer test locally using Docker to analyze PowerShell MSI installation. + +.DESCRIPTION + This script runs Attack Surface Analyzer in a clean Windows container to analyze + the attack surface changes when installing PowerShell MSI. It takes a baseline + snapshot, installs the MSI, takes a post-installation snapshot, and exports the + comparison results. + +.PARAMETER MsiPath + Path to the official signed PowerShell MSI file to test. This must be a released, + signed MSI from the official PowerShell releases. + +.PARAMETER OutputPath + Directory where results will be saved. Defaults to './asa-results' subdirectory. + +.PARAMETER ContainerImage + Docker container image to use. Defaults to mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022 + +.PARAMETER KeepWorkDirectory + If specified, keeps the temporary work directory after the test completes. + +.EXAMPLE + .\Run-AttackSurfaceAnalyzer.ps1 -MsiPath "C:\path\to\PowerShell-7.4.0-win-x64.msi" + +.EXAMPLE + .\Run-AttackSurfaceAnalyzer.ps1 -MsiPath ".\PowerShell-7.4.0-win-x64.msi" -OutputPath "C:\asa-results" + +.NOTES + Requires Docker Desktop with Windows containers enabled. + Requires an official signed PowerShell MSI file from a released build. + + Docker Desktop Handling: + - If Docker Desktop is installed but not running, the script will start it automatically + - If Docker Desktop is not installed, the script will prompt to install it using winget + - Waits up to 60 seconds for Docker to become available after starting + + MSI Requirements: + - The MSI must be digitally signed by Microsoft Corporation + - The MSI must be from an official PowerShell release + - Local builds or unsigned MSIs are not supported + + Supports -WhatIf and -Confirm for Docker installation and startup. +#> + +[CmdletBinding(SupportsShouldProcess)] +param( + [Parameter(Mandatory)] + [string]$MsiPath, + + [Parameter()] + [string]$OutputPath = (Join-Path $PWD "asa-results"), + + [Parameter()] + [string]$ContainerImage = "mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022", + + [Parameter()] + [switch]$KeepWorkDirectory +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +function Write-Log { + param([string]$Message, [string]$Level = "INFO") + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $color = switch ($Level) { + "ERROR" { "Red" } + "WARNING" { "Yellow" } + "SUCCESS" { "Green" } + default { "White" } + } + Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color +} + +function Test-MsiSignature { + param( + [Parameter(Mandatory)] + [string]$MsiPath + ) + + Write-Log "Verifying MSI signature..." -Level INFO + + try { + # Get the digital signature information + $signature = Get-AuthenticodeSignature -FilePath $MsiPath + + if ($signature.Status -ne 'Valid') { + Write-Log "MSI signature is not valid. Status: $($signature.Status)" -Level ERROR + return $false + } + + # Check if signed by Microsoft Corporation + $signerCertificate = $signature.SignerCertificate + if (-not $signerCertificate) { + Write-Log "No signer certificate found" -Level ERROR + return $false + } + + $subject = $signerCertificate.Subject + Write-Log "Certificate subject: $subject" -Level INFO + + # Check for Microsoft Corporation in the subject + if ($subject -notmatch "Microsoft Corporation" -and $subject -notmatch "CN=Microsoft Corporation") { + Write-Log "MSI is not signed by Microsoft Corporation" -Level ERROR + Write-Log "Expected: Microsoft Corporation" -Level ERROR + Write-Log "Found: $subject" -Level ERROR + return $false + } + + # Check certificate validity + $validFrom = $signerCertificate.NotBefore + $validTo = $signerCertificate.NotAfter + $now = Get-Date + + if ($now -lt $validFrom -or $now -gt $validTo) { + Write-Log "Certificate is not valid for current date" -Level ERROR + Write-Log "Valid from: $validFrom to: $validTo" -Level ERROR + return $false + } + + Write-Log "MSI signature verification passed" -Level SUCCESS + Write-Log "Signed by: $($signerCertificate.Subject)" -Level SUCCESS + Write-Log "Valid from: $validFrom to: $validTo" -Level SUCCESS + + return $true + } + catch { + Write-Log "Error verifying MSI signature: $_" -Level ERROR + return $false + } +} + +function Test-DockerAvailable { + try { + $null = docker version 2>&1 + return $true + } + catch { + return $false + } +} + +function Test-DockerDesktopInstalled { + # Check if Docker Desktop executable exists + $dockerDesktopPaths = @( + "${env:ProgramFiles}\Docker\Docker\Docker Desktop.exe", + "${env:ProgramFiles(x86)}\Docker\Docker\Docker Desktop.exe", + "${env:LOCALAPPDATA}\Programs\Docker\Docker Desktop.exe" + ) + + foreach ($path in $dockerDesktopPaths) { + if (Test-Path $path) { + return $path + } + } + return $null +} + +function Test-DockerDesktopRunning { + $process = Get-Process -Name "Docker Desktop" -ErrorAction SilentlyContinue + return $null -ne $process +} + +function Start-DockerDesktopApp { + [CmdletBinding(SupportsShouldProcess)] + param() + + $dockerDesktopPath = Test-DockerDesktopInstalled + + if (-not $dockerDesktopPath) { + Write-Log "Docker Desktop executable not found." -Level ERROR + return $false + } + + if (Test-DockerDesktopRunning) { + Write-Log "Docker Desktop is already running." -Level SUCCESS + return $true + } + + if ($PSCmdlet.ShouldProcess("Docker Desktop", "Start application")) { + Write-Log "Starting Docker Desktop..." -Level SUCCESS + Write-Log "This may take a minute for Docker to fully start..." + + try { + Start-Process -FilePath $dockerDesktopPath -WindowStyle Hidden + + # Wait for Docker to become available (up to 60 seconds) + $maxWaitSeconds = 60 + $waitedSeconds = 0 + + while ($waitedSeconds -lt $maxWaitSeconds) { + Start-Sleep -Seconds 5 + $waitedSeconds += 5 + Write-Log "Waiting for Docker to start... ($waitedSeconds/$maxWaitSeconds seconds)" + + if (Test-DockerAvailable) { + Write-Log "Docker Desktop started successfully!" -Level SUCCESS + return $true + } + } + + Write-Log "Docker Desktop was started but is not responding yet. Please wait a moment and try again." -Level WARNING + return $false + } + catch { + Write-Log "Error starting Docker Desktop: $_" -Level ERROR + return $false + } + } + else { + Write-Log "Starting Docker Desktop cancelled by user." -Level WARNING + return $false + } +} + +function Test-WingetAvailable { + try { + $null = Get-Command winget -ErrorAction Stop + return $true + } + catch { + return $false + } +} + +function Install-DockerDesktop { + [CmdletBinding(SupportsShouldProcess, ConfirmImpact="High")] + param() + + if (-not (Test-WingetAvailable)) { + Write-Log "winget is not available. Please install winget (App Installer from Microsoft Store) or install Docker Desktop manually from https://www.docker.com/products/docker-desktop" -Level ERROR + return $false + } + + if ($PSCmdlet.ShouldProcess("Docker Desktop", "Install using winget")) { + Write-Log "Installing Docker Desktop using winget..." -Level SUCCESS + Write-Log "This may take several minutes..." + + try { + winget install docker.dockerdesktop --accept-package-agreements --accept-source-agreements + + if ($LASTEXITCODE -eq 0) { + Write-Log "Docker Desktop installed successfully!" -Level SUCCESS + Write-Log "Please restart Docker Desktop and ensure Windows containers are enabled, then run this script again." -Level SUCCESS + return $true + } + else { + Write-Log "Docker Desktop installation failed with exit code: $LASTEXITCODE" -Level ERROR + return $false + } + } + catch { + Write-Log "Error installing Docker Desktop: $_" -Level ERROR + return $false + } + } + else { + Write-Log "Docker Desktop installation cancelled by user." -Level WARNING + return $false + } +} + +# Verify Docker is available +Write-Log "Checking Docker availability..." +if (-not (Test-DockerAvailable)) { + Write-Log "Docker is not responding." -Level WARNING + + # Check if Docker Desktop is installed but not running + if (Test-DockerDesktopInstalled) { + Write-Log "Docker Desktop is installed but not running." -Level WARNING + + if (Start-DockerDesktopApp) { + Write-Log "Docker Desktop is now running and ready." -Level SUCCESS + } + else { + Write-Log "Failed to start Docker Desktop or it's taking longer than expected." -Level ERROR + Write-Log "Please start Docker Desktop manually and ensure Windows containers are enabled, then run this script again." -Level ERROR + exit 1 + } + } + else { + # Docker Desktop is not installed + Write-Log "Docker Desktop is not installed." -Level WARNING + Write-Log "Docker Desktop is required to run Attack Surface Analyzer tests in containers." -Level WARNING + + if (Install-DockerDesktop) { + Write-Log "Docker Desktop has been installed. Please restart Docker Desktop and run this script again." -Level SUCCESS + exit 0 + } + else { + Write-Log "Please install Docker Desktop manually from https://www.docker.com/products/docker-desktop and ensure it's running with Windows containers enabled." -Level ERROR + exit 1 + } + } +} + +# Verify MSI exists and is properly signed +if (-not (Test-Path $MsiPath)) { + Write-Log "MSI file not found: $MsiPath" -Level ERROR + exit 1 +} + +$MsiPath = Resolve-Path $MsiPath +Write-Log "Using MSI: $MsiPath" + +# Verify MSI signature +if (-not (Test-MsiSignature -MsiPath $MsiPath)) { + Write-Log "MSI signature verification failed. Only official signed PowerShell MSIs are supported." -Level ERROR + Write-Log "Please download an official PowerShell MSI from: https://github.com/PowerShell/PowerShell/releases" -Level ERROR + exit 1 +} + +# Create output directory +$OutputPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputPath) +if (-not (Test-Path $OutputPath)) { + New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null + Write-Log "Created output directory: $OutputPath" +} + +# Create container work directory +$containerWorkDir = Join-Path $env:TEMP "asa-container-work-$(Get-Date -Format 'yyyyMMdd-HHmmss')" +New-Item -ItemType Directory -Force -Path $containerWorkDir | Out-Null +Write-Log "Created container work directory: $containerWorkDir" + +try { + # Use the static Dockerfile from the docker subfolder + $dockerContextPath = Join-Path $PSScriptRoot "docker" + + # Copy MSI to Docker build context + $msiFileName = Split-Path $MsiPath -Leaf + $destMsiPath = Join-Path $dockerContextPath $msiFileName + Write-Log "Copying MSI to Docker build context..." + Copy-Item $MsiPath -Destination $destMsiPath + $staticDockerfilePath = Join-Path $dockerContextPath "Dockerfile" + Write-Log "Using static Dockerfile: $staticDockerfilePath" + + if (-not (Test-Path $staticDockerfilePath)) { + Write-Log "Static Dockerfile not found at: $staticDockerfilePath" -Level ERROR + exit 1 + } + + Write-Log "Docker build context: $dockerContextPath" + + # Build custom container image from static Dockerfile + Write-Log "=========================================" -Level SUCCESS + Write-Log "Building custom Attack Surface Analyzer container..." -Level SUCCESS + Write-Log "=========================================" -Level SUCCESS + + Write-Log "=========================================" -Level SUCCESS + Write-Log "Building ASA test container..." -Level SUCCESS + Write-Log "=========================================" -Level SUCCESS + Write-Log "This may take several minutes..." + + # Build the asa-reports stage specifically + $reportsImageName = "powershell-asa-reports:latest" + docker build --target asa-reports -t $reportsImageName -f $staticDockerfilePath $dockerContextPath + + if ($LASTEXITCODE -ne 0) { + Write-Log "Docker build failed with exit code: $LASTEXITCODE" -Level ERROR + exit 1 + } + + Write-Log "Build completed successfully" -Level SUCCESS + + # Extract reports from the built image + Write-Log "=========================================" -Level SUCCESS + Write-Log "Extracting reports to: $OutputPath" -Level SUCCESS + Write-Log "=========================================" -Level SUCCESS + + $tempContainerName = "asa-reports-extract-$(Get-Date -Format 'yyyyMMdd-HHmmss')" + + try { + # Create a container from the reports image (but don't run it) + docker create --name $tempContainerName $reportsImageName + + if ($LASTEXITCODE -ne 0) { + Write-Log "Failed to create temporary container for extraction" -Level ERROR + exit 1 + } + + # Try to extract known report file patterns individually + Write-Log "Extracting report files..." -Level INFO + + # Extract standardized report files directly (no file listing needed) + # Extract files with standardized names (no wildcards needed) + Write-Log "Extracting standardized report files..." -Level INFO + $reportFilePatterns = @( + "asa.sqlite", + "asa-results.json", + "install.log" + ) + + $extractedAny = $false + + foreach ($filename in $reportFilePatterns) { + try { + Write-Log "Trying to extract file: $filename" -Level INFO + docker cp "${tempContainerName}:/$filename" $OutputPath 2>$null + + if ($LASTEXITCODE -eq 0) { + Write-Log "Successfully extracted: $filename" -Level SUCCESS + $extractedAny = $true + } else { + Write-Log "File not found: $filename" -Level INFO + } + } + catch { + Write-Log "Error extracting file $filename : $_" -Level WARNING + } + } + + # Alternative approach: extract the entire reports directory if individual files don't work + if (-not $extractedAny) { + Write-Log "Trying to extract entire directory..." -Level INFO + docker cp "${tempContainerName}:/" "$OutputPath/reports" 2>$null + + if ($LASTEXITCODE -eq 0) { + Write-Log "Successfully extracted reports directory" -Level SUCCESS + $extractedAny = $true + } + } + + if ($extractedAny) { + Write-Log "Report extraction completed successfully" -Level SUCCESS + } else { + Write-Log "No reports could be extracted - this may be normal if no issues were found" -Level WARNING + } + } + finally { + # Clean up the temporary container + docker rm $tempContainerName -f 2>$null + } + + # Check what files were extracted + Write-Host "" + Write-Log "=========================================" -Level SUCCESS + Write-Log "Checking extracted results..." -Level SUCCESS + Write-Log "=========================================" -Level SUCCESS + + $resultFiles = Get-ChildItem -Path $OutputPath -ErrorAction SilentlyContinue + $copiedCount = $resultFiles.Count + + if ($copiedCount -eq 0) { + Write-Log "Warning: No result files found in extracted output" -Level WARNING + } + else { + Write-Log "Successfully extracted $copiedCount file(s):" -Level SUCCESS + $resultFiles | ForEach-Object { + if ($_.PSIsContainer) { + Write-Log " - $($_.Name) (directory)" -Level SUCCESS + } else { + Write-Log " - $($_.Name) ($([math]::Round($_.Length/1KB, 2)) KB)" -Level SUCCESS + } + } + } + + Write-Host "" + Write-Log "=========================================" -Level SUCCESS + Write-Log "Attack Surface Analyzer test completed!" -Level SUCCESS + Write-Log "=========================================" -Level SUCCESS + Write-Log "Results saved to: $OutputPath" -Level SUCCESS + + # Check for ASA GUI availability and launch interactive analysis + $dbPath = Join-Path $OutputPath "asa.sqlite" + $jsonPath = Join-Path $OutputPath "asa-results.json" + + if (Test-Path $dbPath) { + # Check if ASA CLI is available + $asaAvailable = $false + try { + $asaVersion = asa --version 2>$null + if ($LASTEXITCODE -eq 0) { + $asaAvailable = $true + Write-Log "Attack Surface Analyzer CLI detected: $($asaVersion.Trim())" -Level INFO + } + } + catch { + # ASA not available via PATH + } + + # Try dotnet tool global path if ASA not found in PATH + if (-not $asaAvailable) { + $globalToolsPath = "$env:USERPROFILE\.dotnet\tools\asa.exe" + if (Test-Path $globalToolsPath) { + try { + $asaVersion = & $globalToolsPath --version 2>$null + if ($LASTEXITCODE -eq 0) { + $asaAvailable = $true + Write-Log "Attack Surface Analyzer found in global tools: $($asaVersion.Trim())" -Level INFO + # Use full path for subsequent commands + $asaCommand = $globalToolsPath + } + } + catch { + # Global tools ASA not working + } + } + } else { + $asaCommand = "asa" + } + + if ($asaAvailable) { + Write-Log "Launching Attack Surface Analyzer GUI for interactive analysis..." -Level SUCCESS + try { + # Launch ASA GUI with the database file + $asaProcess = Start-Process -FilePath $asaCommand -ArgumentList "gui", "--databasefilename", "`"$dbPath`"" -PassThru -NoNewWindow:$false + + if ($asaProcess) { + Write-Log "ASA GUI launched successfully (PID: $($asaProcess.Id))" -Level SUCCESS + Write-Log "Interactive analysis interface is now available" -Level INFO + } else { + Write-Log "Failed to launch ASA GUI" -Level WARNING + } + } + catch { + Write-Log "Error launching ASA GUI: $_" -Level WARNING + Write-Log "You can manually launch the GUI with: asa gui --databasefilename `"$dbPath`"" -Level INFO + } + } else { + Write-Log "Attack Surface Analyzer CLI not found" -Level INFO + Write-Log "Install ASA globally to enable GUI analysis: dotnet tool install -g Microsoft.CST.AttackSurfaceAnalyzer.CLI" -Level INFO + Write-Log "Then launch GUI manually with: asa gui --databasefilename `"$dbPath`"" -Level INFO + } + } else { + Write-Log "Database file not found - cannot launch ASA GUI" -Level WARNING + } + + # Also check for VS Code integration for JSON analysis + if (Test-Path $jsonPath) { + # Detect if running in VS Code + $isVSCode = $false + + if ($env:VSCODE_PID -or $env:TERM_PROGRAM -eq "vscode" -or $env:VSCODE_INJECTION -eq "1") { + $isVSCode = $true + } + + # Check if 'code' command is available + if (-not $isVSCode) { + try { + $null = & code --version 2>$null + if ($LASTEXITCODE -eq 0) { + $isVSCode = $true + } + } + catch { + # 'code' command not available + } + } + + if ($isVSCode) { + Write-Log "VS Code detected - opening JSON results for analysis..." -Level INFO + try { + & code $jsonPath + if ($LASTEXITCODE -eq 0) { + Write-Log "JSON results file opened in VS Code: $jsonPath" -Level SUCCESS + } else { + Write-Log "Failed to open JSON file in VS Code" -Level WARNING + } + } + catch { + Write-Log "Error opening JSON file in VS Code: $_" -Level WARNING + } + } else { + Write-Log "JSON analysis results available at: $jsonPath" -Level INFO + Write-Log "Open this file in VS Code or any JSON viewer for detailed analysis" -Level INFO + } + } +} +finally { + # Cleanup + if (-not $KeepWorkDirectory) { + Write-Log "Cleaning up temporary work directory..." + Remove-Item -Path $containerWorkDir -Recurse -Force -ErrorAction SilentlyContinue + Write-Log "Cleanup completed" + } + else { + Write-Log "Work directory preserved at: $containerWorkDir" -Level SUCCESS + } + + # Always cleanup MSI file from Docker build context + if ($destMsiPath -and (Test-Path $destMsiPath)) { + Write-Log "Cleaning up MSI file from Docker context..." + Remove-Item -Path $destMsiPath -Force -ErrorAction SilentlyContinue + } +} diff --git a/tools/AttackSurfaceAnalyzer/Summarize-AsaResults.ps1 b/tools/AttackSurfaceAnalyzer/Summarize-AsaResults.ps1 new file mode 100644 index 00000000000..00f27014037 --- /dev/null +++ b/tools/AttackSurfaceAnalyzer/Summarize-AsaResults.ps1 @@ -0,0 +1,636 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#Requires -Version 5.1 +<# +.SYNOPSIS + Summarizes Attack Surface Analyzer (ASA) results from a JSON file. + +.DESCRIPTION + This script analyzes ASA JSON results and provides a comprehensive summary of security findings, + including counts by category, analysis levels, and detailed breakdowns of security issues. + +.PARAMETER Path + Path to the ASA results JSON file. Defaults to 'asa-results\asa-results.json' in the current directory. + +.PARAMETER ShowDetails + Shows detailed information about each finding category. + +.PARAMETER IncludeInformationalEvent + Includes informational events in the analysis. By default, only WARNING and ERROR events are processed. + +.PARAMETER IncludeDebugEvent + Includes debug events in the analysis. By default, only WARNING and ERROR events are processed. + +.EXAMPLE + .\Summarize-AsaResults.ps1 + + Summarizes the ASA results with basic statistics, showing only WARNING and ERROR events. + +.EXAMPLE + .\Summarize-AsaResults.ps1 -ShowDetails + + Shows detailed breakdown of findings by category, filtering out informational and debug events. + +.EXAMPLE + .\Summarize-AsaResults.ps1 -IncludeInformationalEvent + + Includes informational events along with WARNING and ERROR events in the analysis..NOTES + Author: GitHub Copilot + Version: 1.0 + Created for PowerShell ASA Analysis +#> + +[CmdletBinding()] +param( + [Parameter()] + [string]$Path = "asa-results\asa-results.json", + + [Parameter()] + [switch]$ShowDetails, + + [Parameter()] + [switch]$IncludeInformationalEvent, + + [Parameter()] + [switch]$IncludeDebugEvent +) + +function Get-AsaSummary { + param( + [Parameter(Mandatory)] + $AsaData, + + [Parameter()] + [switch]$IncludeInformationalEvent, + + [Parameter()] + [switch]$IncludeDebugEvent + ) + + # Extract metadata + $metadata = $AsaData["Metadata"] + $results = $AsaData["Results"] + + # Initialize counters + $summary = @{ + Metadata = @{ + Version = $metadata["compare-version"] + OS = $metadata["compare-os"] + OSVersion = $metadata["compare-osversion"] + BaseRunId = "" + CompareRunId = "" + } + Categories = @{} + TotalFindings = 0 + AnalysisLevels = @{ + WARNING = 0 + ERROR = 0 + INFORMATION = 0 + DEBUG = 0 + } + RuleTypes = @{} + FileIssuesByRule = @{} + FileExtensionSummary = @{} + TimeSpan = $null + } + + # Process each category + foreach ($categoryName in $results.Keys) { + $categoryData = $results[$categoryName] + + $summary.Categories[$categoryName] = @{ + Count = 0 + Items = @() + } + + # Process items in category with filtering + foreach ($item in $categoryData) { + # Filter events based on analysis level + $analysisLevel = $item["Analysis"] + if ($analysisLevel) { + # Skip informational events unless explicitly included + if ($analysisLevel -eq "INFORMATION" -and -not $IncludeInformationalEvent) { + continue + } + # Skip debug events unless explicitly included + if ($analysisLevel -eq "DEBUG" -and -not $IncludeDebugEvent) { + continue + } + + $summary.AnalysisLevels[$analysisLevel]++ + } # If we reach here, the item passed the filter + $summary.Categories[$categoryName].Count++ + $summary.TotalFindings++ + + # Extract run IDs and calculate timespan + if ($item["BaseRunId"]) { + $summary.Metadata.BaseRunId = $item["BaseRunId"] + } + if ($item["CompareRunId"]) { + $summary.Metadata.CompareRunId = $item["CompareRunId"] + } + + # Process rules + foreach ($rule in $item["Rules"]) { + $ruleName = $rule["Name"] + if (-not $summary.RuleTypes.ContainsKey($ruleName)) { + $summary.RuleTypes[$ruleName] = @{ + Count = 0 + Description = $rule["Description"] + Flag = $rule["Flag"] + Platforms = $rule["Platforms"] + Categories = @{} + } + } + $summary.RuleTypes[$ruleName].Count++ + + # Track which categories this rule appears in + if (-not $summary.RuleTypes[$ruleName].Categories.ContainsKey($categoryName)) { + $summary.RuleTypes[$ruleName].Categories[$categoryName] = 0 + } + $summary.RuleTypes[$ruleName].Categories[$categoryName]++ + + # For file-related categories, track file extension if available + if ($categoryName -like "*FILE*" -and $item["Identity"]) { + $fileExtension = [System.IO.Path]::GetExtension($item["Identity"]).ToLower() + if (-not $fileExtension) { $fileExtension = "(no extension)" } + + # Track by rule and extension + if (-not $summary.FileIssuesByRule.ContainsKey($ruleName)) { + $summary.FileIssuesByRule[$ruleName] = @{} + } + if (-not $summary.FileIssuesByRule[$ruleName].ContainsKey($fileExtension)) { + $summary.FileIssuesByRule[$ruleName][$fileExtension] = 0 + } + $summary.FileIssuesByRule[$ruleName][$fileExtension]++ + + # Track overall file extension summary + if (-not $summary.FileExtensionSummary.ContainsKey($fileExtension)) { + $summary.FileExtensionSummary[$fileExtension] = @{ + Count = 0 + Rules = @{} + Categories = @{} + } + } + $summary.FileExtensionSummary[$fileExtension].Count++ + + # Track which rules affect this extension + if (-not $summary.FileExtensionSummary[$fileExtension].Rules.ContainsKey($ruleName)) { + $summary.FileExtensionSummary[$fileExtension].Rules[$ruleName] = 0 + } + $summary.FileExtensionSummary[$fileExtension].Rules[$ruleName]++ + + # Track which categories this extension appears in + if (-not $summary.FileExtensionSummary[$fileExtension].Categories.ContainsKey($categoryName)) { + $summary.FileExtensionSummary[$fileExtension].Categories[$categoryName] = 0 + } + $summary.FileExtensionSummary[$fileExtension].Categories[$categoryName]++ + } + } + + # Store item details for detailed view + $summary.Categories[$categoryName].Items += @{ + Identity = $item["Identity"] + Analysis = $item["Analysis"] + Rules = $item["Rules"] + Compare = $item["Compare"] + } + } + } + + # Calculate timespan if we have both run IDs + if ($summary.Metadata.BaseRunId -and $summary.Metadata.CompareRunId) { + try { + $baseTime = [DateTime]::Parse($summary.Metadata.BaseRunId) + $compareTime = [DateTime]::Parse($summary.Metadata.CompareRunId) + $summary.TimeSpan = $compareTime - $baseTime + } + catch { + $summary.TimeSpan = "Unable to calculate" + } + } + + return $summary +} + +function Write-ConsoleSummary { + param( + [Parameter(Mandatory)] + [hashtable]$Summary, + + [Parameter()] + [switch]$ShowDetails, + + [Parameter()] + [switch]$IncludeInformationalEvent, + + [Parameter()] + [switch]$IncludeDebugEvent + ) + + # Header + Write-Host ("=" * 80) -ForegroundColor Cyan + Write-Host "Attack Surface Analyzer Results Summary" -ForegroundColor Cyan + Write-Host ("=" * 80) -ForegroundColor Cyan + Write-Host "" + + # Metadata + Write-Host "Analysis Metadata:" -ForegroundColor Yellow + Write-Host " ASA Version: $($Summary.Metadata.Version)" -ForegroundColor White + Write-Host " Operating System: $($Summary.Metadata.OS) ($($Summary.Metadata.OSVersion))" -ForegroundColor White + if ($Summary.TimeSpan -and $Summary.TimeSpan -ne "Unable to calculate") { + Write-Host " Analysis Duration: $($Summary.TimeSpan.ToString())" -ForegroundColor White + } + Write-Host "" + + # Overall Statistics + Write-Host "Overall Statistics:" -ForegroundColor Yellow + Write-Host " Total Findings: $($Summary.TotalFindings)" -ForegroundColor White + + # Show filtering information + $filterInfo = @() + if (-not $IncludeInformationalEvent) { $filterInfo += "INFORMATION events excluded" } + if (-not $IncludeDebugEvent) { $filterInfo += "DEBUG events excluded" } + if ($filterInfo.Count -gt 0) { + Write-Host " Filtering: $($filterInfo -join ', ')" -ForegroundColor DarkYellow + } + + # Analysis Levels + Write-Host " Analysis Levels:" -ForegroundColor White + foreach ($level in $Summary.AnalysisLevels.Keys | Sort-Object) { + $count = $Summary.AnalysisLevels[$level] + $color = switch ($level) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'White' } + } + Write-Host " $level`: $count" -ForegroundColor $color + } + Write-Host "" + + # Category Breakdown + Write-Host "Findings by Category:" -ForegroundColor Yellow + $sortedCategories = $Summary.Categories.GetEnumerator() | Sort-Object { $_.Value.Count } -Descending + + foreach ($category in $sortedCategories) { + $categoryName = $category.Key + $count = $category.Value.Count + + if ($count -gt 0) { + Write-Host " $categoryName`: $count items" -ForegroundColor Cyan + } + else { + Write-Host " $categoryName`: $count items" -ForegroundColor DarkGray + } + } + Write-Host "" + + # Rule Types Summary + Write-Host "Top Security Rules Triggered:" -ForegroundColor Yellow + $topRules = $Summary.RuleTypes.GetEnumerator() | + Sort-Object { $_.Value.Count } -Descending | + Select-Object -First 10 + + foreach ($rule in $topRules) { + $ruleName = $rule.Key + $count = $rule.Value.Count + $flag = $rule.Value.Flag + + $color = switch ($flag) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'White' } + } + + Write-Host " [$flag] $ruleName`: $count occurrences" -ForegroundColor $color + if ($ShowDetails) { + Write-Host " Description: $($rule.Value.Description)" -ForegroundColor DarkGray + Write-Host " Platforms: $($rule.Value.Platforms -join ', ')" -ForegroundColor DarkGray + + # Show breakdown by category for this rule + if ($rule.Value.Categories.Count -gt 0) { + Write-Host " Categories:" -ForegroundColor DarkGray + foreach ($cat in $rule.Value.Categories.GetEnumerator() | Sort-Object { $_.Value } -Descending) { + Write-Host " $($cat.Key): $($cat.Value) occurrences" -ForegroundColor Gray + } + } + } + } + + # File Extension Summary + if ($Summary.FileExtensionSummary.Count -gt 0) { + Write-Host "" + Write-Host "File Extension Analysis:" -ForegroundColor Yellow + + $sortedExtensions = $Summary.FileExtensionSummary.GetEnumerator() | + Sort-Object { $_.Value.Count } -Descending | + Select-Object -First 15 + + foreach ($extEntry in $sortedExtensions) { + $extension = $extEntry.Key + $count = $extEntry.Value.Count + $displayExt = if ($extension -eq "(no extension)") { $extension } else { "*$extension" } + + Write-Host " $displayExt`: $count files" -ForegroundColor Cyan + + if ($ShowDetails) { + # Show top rules for this extension + $topRulesForExt = $extEntry.Value.Rules.GetEnumerator() | + Sort-Object { $_.Value } -Descending | + Select-Object -First 3 + + foreach ($ruleEntry in $topRulesForExt) { + $ruleName = $ruleEntry.Key + $ruleCount = $ruleEntry.Value + Write-Host " $ruleName`: $ruleCount files" -ForegroundColor Gray + } + } + } + } + + # Detailed Rule Analysis by Category + if ($ShowDetails) { + Write-Host "" + Write-Host "Detailed Rule Analysis by Category:" -ForegroundColor Yellow + + # Focus on file-related categories + $fileCategories = $Summary.Categories.GetEnumerator() | Where-Object { $_.Key -like "*FILE*" -and $_.Value.Count -gt 0 } + + foreach ($category in $fileCategories) { + $categoryName = $category.Key + Write-Host "" + Write-Host " $categoryName Rules Breakdown:" -ForegroundColor Cyan + + # Get rules that appear in this category + $categoryRules = $Summary.RuleTypes.GetEnumerator() | + Where-Object { $_.Value.Categories.ContainsKey($categoryName) } | + Sort-Object { $_.Value.Categories[$categoryName] } -Descending + + foreach ($ruleEntry in $categoryRules) { + $ruleName = $ruleEntry.Key + $count = $ruleEntry.Value.Categories[$categoryName] + $flag = $ruleEntry.Value.Flag + + $color = switch ($flag) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'White' } + } + + Write-Host " [$flag] $ruleName`: $count files" -ForegroundColor $color + } + } + + # Show file extension breakdown if available + if ($Summary.FileIssuesByRule.Count -gt 0) { + Write-Host "" + Write-Host "File Issues by Rule and Extension:" -ForegroundColor Yellow + + foreach ($ruleEntry in $Summary.FileIssuesByRule.GetEnumerator()) { + $ruleName = $ruleEntry.Key + Write-Host "" + Write-Host " $ruleName`:" -ForegroundColor Cyan + + $sortedExtensions = $ruleEntry.Value.GetEnumerator() | Sort-Object { $_.Value } -Descending + foreach ($extEntry in $sortedExtensions) { + $extension = $extEntry.Key + $count = $extEntry.Value + Write-Host " $extension`: $count files" -ForegroundColor White + } + } + } + } + + # Detailed Category Information + if ($ShowDetails) { + Write-Host "" + Write-Host "Detailed Category Breakdown:" -ForegroundColor Yellow + + foreach ($category in $sortedCategories | Where-Object { $_.Value.Count -gt 0 }) { + $categoryName = $category.Key + $items = $category.Value.Items + + Write-Host "" + Write-Host " $categoryName ($($items.Count) items):" -ForegroundColor Cyan + + # Group by analysis level + $groupedByAnalysis = $items | Group-Object Analysis + foreach ($group in $groupedByAnalysis) { + $level = $group.Name + $count = $group.Count + + $color = switch ($level) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'White' } + } + + Write-Host " $level`: $count items" -ForegroundColor $color + } + + # Show individual file details for file-related categories + if ($categoryName -like "*FILE*" -and $items.Count -gt 0) { + # Check if this category contains files with expired signatures + $expiredSigItems = $items | Where-Object { + $_.Rules -and ($_.Rules | Where-Object { $_.Name -eq 'Binaries with expired signatures' }) + } + + if ($expiredSigItems.Count -gt 0) { + Write-Host "" + Write-Host " Files with Expired Signatures (grouped by Issuer):" -ForegroundColor DarkCyan + + # Group by issuer only + $groupedByIssuer = @{} + foreach ($item in $expiredSigItems) { + if ($item.Compare -and $item.Compare.SignatureStatus -and $item.Compare.SignatureStatus.SigningCertificate) { + $cert = $item.Compare.SignatureStatus.SigningCertificate + $issuer = $cert.Issuer + $notAfter = $cert.NotAfter + $identity = $item.Identity + + if (-not $groupedByIssuer.ContainsKey($issuer)) { + $groupedByIssuer[$issuer] = @() + } + $groupedByIssuer[$issuer] += [PSCustomObject]@{ + Identity = $identity + NotAfter = $notAfter + } + } + } + + # Display grouped results + $sortedIssuers = $groupedByIssuer.GetEnumerator() | Sort-Object Name + + foreach ($issuerGroup in $sortedIssuers) { + $issuer = $issuerGroup.Name + $files = $issuerGroup.Value + $fileCount = $files.Count + + Write-Host "" + Write-Host " Issuer: $issuer" -ForegroundColor Yellow + Write-Host " Files ($fileCount):" -ForegroundColor White + + # Sort files by full file path + $sortedFiles = $files | Sort-Object Identity + + # Show all files + foreach ($file in $sortedFiles) { + # Get identity - handle both hashtable and PSCustomObject + $filePath = if ($file -is [hashtable]) { $file['Identity'] } else { $file.Identity } + + # Format date without time + $expirationDate = 'Unknown' + $notAfterValue = if ($file -is [hashtable]) { $file['NotAfter'] } else { $file.NotAfter } + if ($notAfterValue) { + try { + $expirationDate = ([DateTime]::Parse($notAfterValue)).ToString('yyyy-MM-dd') + } + catch { + $expirationDate = 'Unknown' + } + } + Write-Host " [Expired: $expirationDate] $filePath" -ForegroundColor Gray + } + } + + # Show other files (non-expired signature issues) + $otherFiles = $items | Where-Object { + -not ($_.Rules -and ($_.Rules | Where-Object { $_.Name -eq 'Binaries with expired signatures' })) + } + + if ($otherFiles.Count -gt 0) { + Write-Host "" + Write-Host " Other Files:" -ForegroundColor DarkCyan + + $displayLimit = [Math]::Min(20, $otherFiles.Count) + for ($i = 0; $i -lt $displayLimit; $i++) { + $item = $otherFiles[$i] + $identity = $item.Identity + $analysis = $item.Analysis + + $color = switch ($analysis) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'Gray' } + } + + if ($item.Rules -and $item.Rules.Count -gt 0) { + $ruleNames = $item.Rules | ForEach-Object { $_.Name } + Write-Host " [$analysis] $identity" -ForegroundColor $color + Write-Host " Rules: $($ruleNames -join ', ')" -ForegroundColor DarkGray + } + else { + Write-Host " [$analysis] $identity" -ForegroundColor $color + } + } + + if ($otherFiles.Count -gt $displayLimit) { + Write-Host " ... and $($otherFiles.Count - $displayLimit) more files" -ForegroundColor DarkGray + } + } + } + else { + # No expired signatures, show standard file listing + Write-Host "" + Write-Host " Files:" -ForegroundColor DarkCyan + + $displayLimit = [Math]::Min(50, $items.Count) + for ($i = 0; $i -lt $displayLimit; $i++) { + $item = $items[$i] + $identity = $item.Identity + $analysis = $item.Analysis + + $color = switch ($analysis) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'Gray' } + } + + # Show triggered rules for this file + if ($item.Rules -and $item.Rules.Count -gt 0) { + $ruleNames = $item.Rules | ForEach-Object { $_.Name } + Write-Host " [$analysis] $identity" -ForegroundColor $color + Write-Host " Rules: $($ruleNames -join ', ')" -ForegroundColor DarkGray + } + else { + Write-Host " [$analysis] $identity" -ForegroundColor $color + } + } + + if ($items.Count -gt $displayLimit) { + Write-Host " ... and $($items.Count - $displayLimit) more files" -ForegroundColor DarkGray + } + } + } + # Show details for non-file categories (users, groups, etc.) + elseif ($items.Count -gt 0) { + Write-Host "" + Write-Host " Items:" -ForegroundColor DarkCyan + + $displayLimit = [Math]::Min(20, $items.Count) + for ($i = 0; $i -lt $displayLimit; $i++) { + $item = $items[$i] + $identity = $item.Identity + $analysis = $item.Analysis + + $color = switch ($analysis) { + 'ERROR' { 'Red' } + 'WARNING' { 'Yellow' } + 'INFORMATION' { 'Green' } + 'DEBUG' { 'DarkGray' } + default { 'Gray' } + } + + Write-Host " [$analysis] $identity" -ForegroundColor $color + } + + if ($items.Count -gt $displayLimit) { + Write-Host " ... and $($items.Count - $displayLimit) more items" -ForegroundColor DarkGray + } + } + } + } + + Write-Host "" + Write-Host ("=" * 80) -ForegroundColor Cyan +} + +# Main execution +try { + # Validate input file + if (-not (Test-Path $Path)) { + Write-Error "ASA results file not found: $Path" + exit 1 + } + + Write-Verbose "Reading ASA results from: $Path" + + # Load and parse JSON + $jsonContent = Get-Content -Path $Path -Raw -Encoding UTF8 + $asaData = $jsonContent | ConvertFrom-Json -AsHashtable + + # Generate summary + Write-Verbose "Analyzing ASA results..." + $summary = Get-AsaSummary -AsaData $asaData -IncludeInformationalEvent:$IncludeInformationalEvent -IncludeDebugEvent:$IncludeDebugEvent + + # Output results to console + Write-ConsoleSummary -Summary $summary -ShowDetails:$ShowDetails -IncludeInformationalEvent:$IncludeInformationalEvent -IncludeDebugEvent:$IncludeDebugEvent +} +catch { + Write-Error "Error processing ASA results: $($_.Exception.Message)" + Write-Error $_.ScriptStackTrace + exit 1 +} diff --git a/tools/AttackSurfaceAnalyzer/docker/Dockerfile b/tools/AttackSurfaceAnalyzer/docker/Dockerfile new file mode 100644 index 00000000000..3e4aaa3b717 --- /dev/null +++ b/tools/AttackSurfaceAnalyzer/docker/Dockerfile @@ -0,0 +1,134 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Multi-stage Dockerfile for Attack Surface Analyzer Testing +# Stage 1: Build and run ASA tests +# Stage 2: Extract reports to scratch layer + +# Stage 1: Test execution environment +FROM mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022@sha256:28f3a59216a7f91dfc4730ea47e236e2ffbb519975725bf8231f57e69dab3ca8 AS asa-runner + +# Set shell to PowerShell for easier scripting +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +# Install Attack Surface Analyzer as a global .NET tool +RUN dotnet tool install -g Microsoft.CST.AttackSurfaceAnalyzer.CLI --version 2.3.328 + +# Add .NET tools directory to PATH +RUN $env:PATH += ';C:/Users/ContainerAdministrator/.dotnet/tools'; \ + [Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine) + +# Set working directory and create reports directory +WORKDIR C:/work +RUN New-Item -ItemType Directory -Path C:\reports -Force | Out-Null + +# Take baseline snapshot before installation +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Taking baseline snapshot..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + asa collect -f -r -u -l --directories 'C:\Program Files\PowerShell,C:\Program Files (x86)\PowerShell' --runid before; \ + if ($LASTEXITCODE -ne 0) { Write-Error "Failed to take baseline snapshot"; exit 1 } + +# Copy the PowerShell MSI file from build context +COPY *.msi ./powershell.msi + +# Install PowerShell MSI +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Installing PowerShell MSI..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + Write-Host "MSI file: C:\work\powershell.msi"; \ + $argumentList = '/i C:\work\powershell.msi /quiet /norestart /l*vx C:\work\install.log ADD_PATH=1'; \ + Write-Host "Running: msiexec $argumentList"; \ + $msiProcess = Start-Process msiexec.exe -ArgumentList $argumentList -Wait -NoNewWindow -PassThru; \ + if ($msiProcess.ExitCode -ne 0) { \ + Write-Host "MSI installation failed with exit code: $($msiProcess.ExitCode)"; \ + throw "MSI installation failed. Check install.log for details" \ + } + +# Take post-installation snapshot +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Taking post-installation snapshot..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + asa collect -f -r -u -l --directories 'C:\Program Files\PowerShell,C:\Program Files (x86)\PowerShell' --runid after; \ + if ($LASTEXITCODE -ne 0) { Write-Error "Failed to take post-installation snapshot"; exit 1 } + +# Export comparison results +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Exporting comparison results..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + asa export-collect --savetodatabase --resultlevels WARNING,ERROR,FATAL --firstrunid before --secondrunid after; \ + if ($LASTEXITCODE -ne 0) { Write-Warning "Failed to export results with exit code: $LASTEXITCODE" } + +# Export comparison results +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Exporting comparison results..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + asa export-collect --readfromsavedcomparisons; \ + if ($LASTEXITCODE -ne 0) { Write-Warning "Failed to export results with exit code: $LASTEXITCODE" } + + +# Copy and standardize JSON result files +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Processing JSON result files..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + $jsonFiles = Get-ChildItem -Path "*.json.txt" -ErrorAction SilentlyContinue; \ + if ($jsonFiles.Count -eq 0) { \ + Write-Warning 'No JSON.TXT files found - checking for .json files...'; \ + $jsonFiles = Get-ChildItem -Path "*.json" -ErrorAction SilentlyContinue \ + }; \ + if ($jsonFiles.Count -eq 0) { \ + throw 'No JSON files found - ASA may not have generated results' \ + } else { \ + $jsonFiles | ForEach-Object { \ + Write-Host "Found JSON file: $($_.Name)"; \ + if (-not (Test-Path $_.FullName)) { \ + throw "JSON file not accessible: $($_.FullName)" \ + }; \ + Write-Host "Copying to standard name: asa-results.json"; \ + Copy-Item -Path $_.FullName -Destination C:\work\asa-results.json -ErrorAction Stop; \ + Copy-Item -Path $_.FullName -Destination C:\reports\asa-results.json -ErrorAction Stop; \ + } \ + } + +# Copy SQLite database file if it exists +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Copying SQLite database..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + if (Test-Path "asa.sqlite") { \ + Write-Host "Copying: asa.sqlite"; \ + Copy-Item -Path "asa.sqlite" -Destination C:\reports\ -ErrorAction Stop \ + } else { \ + throw 'SQLite database (asa.sqlite) not found - this may indicate ASA export issues' \ + } + +# Copy installation log file +RUN Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Copying installation log..." -ForegroundColor Green; \ + Write-Host "========================================="; \ + if (-not (Test-Path "C:\work\install.log")) { \ + throw "Required installation log file not found: C:\work\install.log" \ + }; \ + Copy-Item -Path "C:\work\install.log" -Destination C:\reports\ -ErrorAction Stop; \ + Write-Host "Attack Surface Analyzer test completed!" -ForegroundColor Green + +# Default command shows completion message +CMD Write-Host "=========================================" -ForegroundColor Green; \ + Write-Host "Container ready. Reports available in C:\reports\" -ForegroundColor Cyan; \ + Write-Host "=========================================" + +# Stage 2: Reports-only layer using minimal Windows base +FROM mcr.microsoft.com/windows/nanoserver:ltsc2022@sha256:307874138e4dc064d0538b58c6f028419ab82fb15fcabaf6d5378ba32c235266 AS asa-reports + +# Set working directory to root +WORKDIR / + +# Copy only the report files from the runner stage to root level +COPY --from=asa-runner C:/reports/ ./ + +# Stage 3: Final stage (defaults to the runner for backward compatibility) +FROM asa-runner AS final + +# Label for documentation +LABEL description="Windows container for running Attack Surface Analyzer tests on PowerShell MSI installations" +LABEL version="1.0" +LABEL maintainer="PowerShell Team" From bf1c8ed827fff88647b33309d22fbb8abed48955 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 09:20:02 -0800 Subject: [PATCH 184/378] Add a backport prompt for copilot (#26383) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../backport-pr-to-release-branch.prompt.md | 536 ++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 .github/prompts/backport-pr-to-release-branch.prompt.md diff --git a/.github/prompts/backport-pr-to-release-branch.prompt.md b/.github/prompts/backport-pr-to-release-branch.prompt.md new file mode 100644 index 00000000000..8117bdc5183 --- /dev/null +++ b/.github/prompts/backport-pr-to-release-branch.prompt.md @@ -0,0 +1,536 @@ +--- +description: Guide for backporting changes to PowerShell release branches +--- + +# Backport a Change to a PowerShell Release Branch + +## 1 — Goal + +Create a backport PR that applies changes from a merged PR to a release branch (e.g., `release/v7.4`, `release/v7.5`). The backport must follow the repository's established format and include proper references to the original PR. + +## 2 — Prerequisites for the model + +- You have full repository access +- You can run git commands +- You can read PR information from the repository +- Ask clarifying questions if the target release branch or original PR number is unclear + +## 3 — Required user inputs + +If the user hasn't specified a PR number, help them find one: + +### Finding PRs that need backporting + +1. Ask the user which release version they want to backport to (e.g., `7.4`, `7.5`) +2. Search for PRs with the appropriate label using GitHub CLI: + +```powershell +$Owner = "PowerShell" +$Repo = "PowerShell" +$version = "7.4" # or user-specified version +$considerLabel = "Backport-$version.x-Consider" + +$prsJson = gh pr list --repo "$Owner/$Repo" --label $considerLabel --state merged --json number,title,url,labels,mergedAt --limit 100 2>&1 +$prs = $prsJson | ConvertFrom-Json +# Sort PRs from oldest merged to newest merged +$prs = $prs | Sort-Object mergedAt +``` + +3. Present the list of PRs to the user with: + - PR number + - PR title + - Merged date + - URL + +4. Ask the user: "Which PR would you like to backport?" (provide the PR number) + +### After selecting a PR + +Once the user selects a PR (or if they provided one initially), confirm: +- **Original PR number**: The PR number that was merged to the main branch (e.g., 26193) +- **Target release**: The release number (e.g., `7.4`, `7.5`, `7.5.1`) + +Example: "Backport PR 26193 to release/v7.4" + +## 4 — Implementation steps (must be completed in order) + +### Step 1: Verify the original PR exists and is merged + +1. Fetch the original PR information using the PR number +2. Confirm the PR state is `MERGED` +3. Extract the following information: + - Merge commit SHA + - Original PR title + - Original PR author + - Original CL label (if present, typically starts with `CL-`) + +If the PR is not merged, stop and inform the user. + +4. Check if backport already exists or has been attempted: + ```powershell + gh pr list --repo PowerShell/PowerShell --search "in:title [release/v7.4] " --state all + ``` + + If a backport PR already exists, inform the user and ask if they want to continue. + +5. Check backport labels to understand status: + - `Backport-7.4.x-Migrated`: Indicates previous backport attempt (may have failed or had issues) + - `Backport-7.4.x-Done`: Already backported successfully + - `Backport-7.4.x-Approved`: Ready for backporting + - `Backport-7.4.x-Consider`: Under consideration for backporting + + If status is "Done", inform the user that backport may already be complete. + +### Step 2: Create the backport branch + +1. Identify the correct remote to fetch from: + ```bash + git remote -v + ``` + + Look for the remote that points to `https://github.com/PowerShell/PowerShell` (typically named `upstream` or `origin`). Use this remote name in subsequent commands. + +2. Ensure you have the latest changes from the target release branch: + ```bash + git fetch + ``` + + Example: `git fetch upstream release/v7.4` + +3. Create a new branch from the target release branch: + ```bash + git checkout -b backport- / + ``` + + Example: `git checkout -b backport-26193 upstream/release/v7.4` + +### Step 3: Cherry-pick the merge commit + +1. Cherry-pick the merge commit from the original PR: + ```bash + git cherry-pick + ``` + +2. If conflicts occur: + - Inform the user about the conflicts + - List the conflicting files + - Fetch the original PR diff to understand the changes: + ```bash + gh pr diff --repo PowerShell/PowerShell | Out-File pr-diff.txt + ``` + - Review the diff to understand what the PR changed + - Figure out why there is a conflict and resolve it + - Create a summary of the conflict resolution: + * Which files had conflicts + * Nature of each conflict (parameter changes, code removal, etc.) + * How you resolved it + * Whether any manual adjustments were needed beyond accepting one side + - Ask the user to review your conflict resolution summary before continuing + - After conflicts are resolved, continue with: + ```bash + git add + git cherry-pick --continue + ``` + +### Step 4: Push the backport branch + +Push to your fork (typically the remote that you have write access to): + +```bash +git push backport- +``` + +Example: `git push origin backport-26193` + +Note: If you're pushing to the official PowerShell repository and have permissions, you may push to `upstream` or the appropriate remote. + +### Step 5: Create the backport PR + +Create a new PR with the following format: + +**Title:** +``` +[] +``` + +Example: `[release/v7.4] GitHub Workflow cleanup` + +**Body:** +``` +Backport of # to + + + +Triggered by @ on behalf of @ + +Original CL Label: + +/cc @PowerShell/powershell-maintainers + +## Impact + +Choose either tooling or Customer impact. +### Tooling Impact + +- [ ] Required tooling change +- [ ] Optional tooling change (include reasoning) + +### Customer Impact + +- [ ] Customer reported +- [ ] Found internally + +[Select one or both of the boxes. Describe how this issue impacts customers, citing the expected and actual behaviors and scope of the issue. If customer-reported, provide the issue number.] + +## Regression + +- [ ] Yes +- [ ] No + +[If yes, specify when the regression was introduced. Provide the PR or commit if known.] + +## Testing + +[How was the fix verified? How was the issue missed previously? What tests were added?] + +## Risk + +- [ ] High +- [ ] Medium +- [ ] Low + +[High/Medium/Low. Justify the indication by mentioning how risks were measured and addressed.] +``` + +**Base branch:** `` (e.g., `release/v7.4`) + +**Head branch:** `backport-` (e.g., `backport-26193`) + +#### Guidelines for Filling Out the PR Body + +**For Impact Section**: +- If the original PR changed build/tooling/packaging, select "Tooling Impact" +- If it fixes a user-facing bug or changes user-visible behavior, select "Customer Impact" +- Copy relevant context from the original PR description +- Be specific about what changed and why + +**For Regression Section**: +- Mark "Yes" only if the original PR fixed a regression +- Include when the regression was introduced if known + +**For Testing Section**: +- Reference the original PR's testing approach +- Note any additional backport-specific testing needed +- Mention if manual testing was done to verify the backport + +**For Risk Assessment**: +- **High**: Changes core functionality, packaging, build systems, or security-related code +- **Medium**: Changes non-critical features, adds new functionality, or modifies existing behavior +- **Low**: Documentation, test-only changes, minor refactoring, or fixes with narrow scope +- Justify your assessment based on the scope of changes and potential impact + +**If there were merge conflicts**: +Add a note in the PR description after the Risk section describing what conflicts occurred and how they were resolved. + +### Step 6: Clean up temporary files + +After successful PR creation, clean up any temporary files created during the process: + +```powershell +Remove-Item pr*.diff -ErrorAction SilentlyContinue +``` + +## 5 — Definition of Done (self-check list) + +- [ ] Original PR is verified as merged +- [ ] Checked for existing backport PRs +- [ ] Reviewed backport labels to understand status +- [ ] Backport branch created from correct release branch +- [ ] Merge commit cherry-picked successfully (or conflicts resolved) +- [ ] If conflicts occurred, provided resolution summary to user +- [ ] Branch pushed to origin +- [ ] PR created with correct title format: `[] ` +- [ ] Temporary files cleaned up (pr*.diff) +- [ ] PR body includes: + - [ ] Backport reference: `Backport of (PR-number) to ` + - [ ] Auto-generated comment with original PR number + - [ ] Triggered by and original author attribution + - [ ] Original CL label (if available) + - [ ] CC to PowerShell maintainers + - [ ] Impact section filled out + - [ ] Regression section filled out + - [ ] Testing section filled out + - [ ] Risk section filled out +- [ ] Base branch set to target release branch +- [ ] No unrelated changes included + +## 6 — Branch naming convention + +**Format:** `backport-` + +Examples: +- `backport-26193` +- `backport-26334` + +Note: Automated bot uses format `backport/release/v/-`, but manual backports use the simpler `backport-` format. + +## 7 — Example backport PR + +Reference PR 26334 as the canonical example of a correct backport: + +**Original PR**: PR 26193 "GitHub Workflow cleanup" + +**Backport PR**: PR 26334 "[release/v7.4] GitHub Workflow cleanup" +- **Title**: `[release/v7.4] GitHub Workflow cleanup` +- **Body**: Started with backport reference to original PR and release branch +- **Branch**: `backport/release/v7.4/26193-4aff02475` (bot-created) +- **Base**: `release/v7.4` +- **Includes**: Auto-generated metadata, impact assessment, regression info, testing details, and risk level + +## 8 — Backport label system (for context) + +Backport labels follow pattern: `Backport-.x-` + +**Triage states:** +- `Consider` - Under review for backporting +- `Approved` - Approved and ready to be backported +- `Done` - Backport completed + +**Examples:** `Backport-7.4.x-Approved`, `Backport-7.5.x-Consider`, `Backport-7.3.x-Done` + +Note: The PowerShell repository has an automated bot (pwshBot) that creates backport PRs automatically when a merged PR has a backport approval label. Manual backports follow the same format. + +## Manual Backport Using PowerShell Tools + +For situations where automated backports fail or manual intervention is needed, use the `Invoke-PRBackport` function from `tools/releaseTools.psm1`. + +### Prerequisites + +1. **GitHub CLI**: Install from https://cli.github.com/ + - Required version: 2.17 or later + - Authenticate with `gh auth login` + +2. **Upstream Remote**: Configure a Git remote named `upstream` pointing to `PowerShell/PowerShell`: + ```powershell + git remote add upstream https://github.com/PowerShell/PowerShell.git + ``` + +### Using Invoke-PRBackport + +```powershell +# Import the release tools module +Import-Module ./tools/releaseTools.psm1 + +# Backport a single PR +Invoke-PRBackport -PrNumber 26193 -Target release/v7.4.1 + +# Backport with custom branch postfix +Invoke-PRBackport -PrNumber 26193 -Target release/v7.4.1 -BranchPostFix "retry" + +# Overwrite existing local branch if it exists +Invoke-PRBackport -PrNumber 26193 -Target release/v7.4.1 -Overwrite +``` + +### Parameters + +- **PrNumber** (Required): The PR number to backport +- **Target** (Required): Target release branch (must match pattern `release/v\d+\.\d+(\.\d+)?`) +- **Overwrite**: Switch to overwrite local branch if it already exists +- **BranchPostFix**: Add a postfix to the branch name (e.g., for retry attempts) +- **UpstreamRemote**: Name of the upstream remote (default: `upstream`) + +### How It Works + +1. Verifies the PR is merged +2. Fetches the target release branch from upstream +3. Creates a new branch: `backport-[-]` +4. Cherry-picks the merge commit +5. If conflicts occur, prompts you to resolve them +6. Creates the backport PR using GitHub CLI + +## Handling Merge Conflicts + +When cherry-picking fails due to conflicts: + +1. The script will pause and prompt you to fix conflicts +2. Resolve conflicts in your editor: + ```powershell + # Check which files have conflicts + git status + + # Edit files to resolve conflicts + # After resolving, stage the changes + git add + + # Continue the cherry-pick + git cherry-pick --continue + ``` +3. Type 'Yes' when prompted to continue the script +4. The script will create the PR + +### Understanding Conflict Patterns + +When resolving conflicts during backports, follow this approach: + +1. **Analyze the diff first**: Before resolving conflicts, fetch and review the original PR's diff to understand what changed: + ```powershell + gh pr diff --repo PowerShell/PowerShell | Out-File pr-diff.txt + ``` + +2. **Identify conflict types**: + - **Parameter additions**: New parameters added to functions (e.g., ValidateSet values) + - **Code removal**: Features removed in main but still exist in release branch + - **Code additions**: New code blocks that don't exist in release branch + - **Refactoring conflicts**: Code structure changes between branches + +3. **Resolution priorities**: + - Preserve the intent of the backported change + - Keep release branch-specific code that doesn't conflict with the fix + - When in doubt, favor the incoming change from the backport + - Document significant manual changes in the PR description + +4. **Verification**: + - After resolving conflicts, verify the file compiles/runs + - Check that the resolved code matches the original PR's intent + - Look for orphaned code that references removed functions + +5. **Create a conflict resolution summary**: + - List which files had conflicts + - Briefly explain the nature of each conflict + - Describe how you resolved it + - Ask user to review the resolution before continuing + +### Context-Aware Conflict Resolution + +**Key Principle**: The release branch may have different code than main. Your goal is to apply the *change* from the PR, not necessarily make the code identical to main. + +**Common Scenarios**: +1. **Function parameters differ**: If the release branch has fewer parameters than main, and the backport adds functionality unrelated to new parameters, keep the release branch parameters unless the new parameters are part of the fix +2. **Dependencies removed in main**: If main removed a dependency but the release branch still has it, and the backport is unrelated to that dependency, keep the release branch code +3. **New features in main**: If main has new features not in the release, focus on backporting only the specific fix, not the new features + +## Bulk Backporting Approved PRs + +To backport all PRs labeled as approved for a specific version: + +```powershell +Import-Module ./tools/releaseTools.psm1 + +# Backport all approved PRs for version 7.2.12 +Invoke-PRBackportApproved -Version 7.2.12 +``` + +This function: +1. Queries all merged PRs with the `Backport-.x-Approved` label +2. Attempts to backport each PR in order of merge date +3. Creates individual backport PRs for each + +## Viewing Backport Reports + +Get a list of PRs that need backporting: + +```powershell +Import-Module ./tools/releaseTools.psm1 + +# List all approved backports for 7.4 +Get-PRBackportReport -Version 7.4 -TriageState Approved + +# Open all approved backports in browser +Get-PRBackportReport -Version 7.4 -TriageState Approved -Web + +# Check which backports are done +Get-PRBackportReport -Version 7.4 -TriageState Done +``` + +## Branch Naming Conventions + +### Automated Bot Branches +Format: `backport/release/v/-` + +Example: `backport/release/v7.4/26193-4aff02475` + +### Manual Backport Branches +Format: `backport-[-]` + +Examples: +- `backport-26193` +- `backport-26193-retry` + +## PR Title and Description Format + +### Title +Format: `[release/v] ` + +Example: `[release/v7.4] GitHub Workflow cleanup` + +### Description +The backport PR description includes: +- Reference to original PR number +- Target release branch +- Auto-generated comment with original PR metadata +- Maintainer information +- Original CL label +- CC to PowerShell maintainers team + +Example description structure: +```text +Backport of (original-pr-number) to release/v + + + +Triggered by @ on behalf of @ + +Original CL Label: + +/cc @PowerShell/powershell-maintainers +``` + +## Best Practices + +1. **Verify PR is merged**: Only backport merged PRs +2. **Test backports**: Ensure backported changes work in the target release context +3. **Check for conflicts early**: Large PRs are more likely to have conflicts +4. **Use appropriate labels**: Apply correct version and triage state labels +5. **Document special cases**: If manual changes were needed, note them in the PR description +6. **Follow up on CI failures**: Backports should pass all CI checks before merging + +## Troubleshooting + +### "PR is not merged" Error +**Cause**: Attempting to backport a PR that hasn't been merged yet +**Solution**: Wait for the PR to be merged to the main branch first + +### "Please create an upstream remote" Error +**Cause**: No upstream remote configured +**Solution**: +```powershell +git remote add upstream https://github.com/PowerShell/PowerShell.git +git fetch upstream +``` + +### "GitHub CLI is not installed" Error +**Cause**: gh CLI not found in PATH +**Solution**: Install from https://cli.github.com/ and restart terminal + +### Cherry-pick Conflicts +**Cause**: Changes conflict with the target branch +**Solution**: Manually resolve conflicts, stage files, and continue cherry-pick + +### "Commit does not exist" Error +**Cause**: Local Git doesn't have the commit +**Solution**: +```powershell +git fetch upstream +``` + +## Related Resources + +- **Release Process**: See `docs/maintainers/releasing.md` +- **Release Tools**: See `tools/releaseTools.psm1` +- **Issue Management**: See `docs/maintainers/issue-management.md` From 69770b29b00d70b371a5f86b7a839d5f1afff7f1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:32:30 +0000 Subject: [PATCH 185/378] Remove obsolete test/docker/networktest directory (#26388) --- .../networktest/DockerRemoting.Tests.ps1 | 89 ------------------- test/docker/networktest/Dockerfile | 24 ----- 2 files changed, 113 deletions(-) delete mode 100644 test/docker/networktest/DockerRemoting.Tests.ps1 delete mode 100644 test/docker/networktest/Dockerfile diff --git a/test/docker/networktest/DockerRemoting.Tests.ps1 b/test/docker/networktest/DockerRemoting.Tests.ps1 deleted file mode 100644 index 5f5a13c5b4c..00000000000 --- a/test/docker/networktest/DockerRemoting.Tests.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -$imageName = "remotetestimage" -Describe "Basic remoting test with docker" -tags @("Scenario","Slow"){ - BeforeAll { - $Timeout = 600 # 10 minutes to run these tests - $dockerimage = docker images --format "{{ .Repository }}" $imageName - if ( $dockerimage -ne $imageName ) { - $pending = $true - Write-Warning "Docker image '$imageName' not found, not running tests" - return - } - else { - $pending = $false - } - - # give the containers something to do, otherwise they will exit and be removed - Write-Verbose -Verbose "setting up docker container PowerShell server" - $server = docker run -d $imageName powershell -c Start-Sleep -Seconds $timeout - Write-Verbose -Verbose "setting up docker container PowerShell client" - $client = docker run -d $imageName powershell -c Start-Sleep -Seconds $timeout - - # get fullpath to installed core powershell - Write-Verbose -Verbose "Getting path to PowerShell" - $powershellcorepath = docker exec $server powershell -c "(get-childitem 'c:\program files\powershell\*\pwsh.exe').fullname" - if ( ! $powershellcorepath ) - { - $pending = $true - Write-Warning "Cannot find powershell executable, not running tests" - return - } - $powershellcoreversion = ($powershellcorepath -split "[\\/]")[-2] - # we will need the configuration of the core powershell endpoint - $powershellcoreConfiguration = "powershell.${powershellcoreversion}" - - # capture the hostnames of the containers which will be used by the tests - Write-Verbose -Verbose "getting server hostname" - $serverhostname = docker exec $server hostname - Write-Verbose -Verbose "getting client hostname" - $clienthostname = docker exec $client hostname - - # capture the versions of full and core PowerShell - Write-Verbose -Verbose "getting powershell full version" - $fullVersion = docker exec $client powershell -c "`$PSVersionTable.psversion.tostring()" - if ( ! $fullVersion ) - { - $pending = $true - Write-Warning "Cannot determine PowerShell full version, not running tests" - return - } - - Write-Verbose -Verbose "getting powershell version" - $coreVersion = docker exec $client "$powershellcorepath" -c "`$PSVersionTable.psversion.tostring()" - if ( ! $coreVersion ) - { - $pending = $true - Write-Warning "Cannot determine PowerShell version, not running tests" - return - } - } - - AfterAll { - # to debug, comment out the following - if ( $pending -eq $false ) { - docker rm -f $server - docker rm -f $client - } - } - - It "Full powershell can get correct remote powershell version" -Pending:$pending { - $result = docker exec $client powershell -c "`$ss = [security.securestring]::new(); '11aa!!AA'.ToCharArray() | ForEach-Object { `$ss.appendchar(`$_)}; `$c = [pscredential]::new('testuser',`$ss); `$ses=new-pssession $serverhostname -configurationname $powershellcoreConfiguration -auth basic -credential `$c; invoke-command -session `$ses { `$PSVersionTable.psversion.tostring() }" - $result | Should -Be $coreVersion - } - - It "Full powershell can get correct remote powershell full version" -Pending:$pending { - $result = docker exec $client powershell -c "`$ss = [security.securestring]::new(); '11aa!!AA'.ToCharArray() | ForEach-Object { `$ss.appendchar(`$_)}; `$c = [pscredential]::new('testuser',`$ss); `$ses=new-pssession $serverhostname -auth basic -credential `$c; invoke-command -session `$ses { `$PSVersionTable.psversion.tostring() }" - $result | Should -Be $fullVersion - } - - It "Core powershell can get correct remote powershell version" -Pending:$pending { - $result = docker exec $client "$powershellcorepath" -c "`$ss = [security.securestring]::new(); '11aa!!AA'.ToCharArray() | ForEach-Object { `$ss.appendchar(`$_)}; `$c = [pscredential]::new('testuser',`$ss); `$ses=new-pssession $serverhostname -configurationname $powershellcoreConfiguration -auth basic -credential `$c; invoke-command -session `$ses { `$PSVersionTable.psversion.tostring() }" - $result | Should -Be $coreVersion - } - - It "Core powershell can get correct remote powershell full version" -Pending:$pending { - $result = docker exec $client "$powershellcorepath" -c "`$ss = [security.securestring]::new(); '11aa!!AA'.ToCharArray() | ForEach-Object { `$ss.appendchar(`$_)}; `$c = [pscredential]::new('testuser',`$ss); `$ses=new-pssession $serverhostname -auth basic -credential `$c; invoke-command -session `$ses { `$PSVersionTable.psversion.tostring() }" - $result | Should -Be $fullVersion - } -} diff --git a/test/docker/networktest/Dockerfile b/test/docker/networktest/Dockerfile deleted file mode 100644 index d558b139246..00000000000 --- a/test/docker/networktest/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# escape=` -FROM mcr.microsoft.com/windows/servercore:ltsc2022@sha256:5d09ffa90d91a46e2fe7652b0a37cbf5217f34a819c3d71cbe635dae8226061b - -SHELL ["pwsh.exe","-command"] - -# the source msi should change on a daily basis -# the destination should not change -ADD PSCore.msi /PSCore.msi - -# the msipath (PSCore.msi) below will need to change based on the daily package -# set up for basic auth -# install-powershellremoting will restart winrm service -RUN new-LocalUser -Name testuser -password (ConvertTo-SecureString 11aa!!AA -asplaintext -force); ` - add-localgroupmember -group administrators -member testuser; ` - set-item wsman:/localhost/service/auth/basic $true; ` - set-item WSMan:/localhost/client/trustedhosts "*" -force; ` - set-item wsman:/localhost/service/AllowUnencrypted $true; ` - set-item WSMan:/localhost/client/AllowUnencrypted $true; ` - Start-Process -FilePath msiexec.exe -ArgumentList '-qn', ` - '-i c:\PSCore.msi','-log c:\PSCore-install.log','-norestart' -wait ; ` - $psexec = get-item -path ${ENV:ProgramFiles}/powershell/*/pwsh.exe; ` - $corehome = $psexec.directory.fullname; ` - & $psexec Install-PowerShellRemoting.ps1; ` - remove-item -force c:\PSCore.msi From ac55117f073108dbfbbd4c5023396ab1bbb99b32 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 5 Nov 2025 11:23:17 -0800 Subject: [PATCH 186/378] Update backport prompt (#26392) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../backport-pr-to-release-branch.prompt.md | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/prompts/backport-pr-to-release-branch.prompt.md b/.github/prompts/backport-pr-to-release-branch.prompt.md index 8117bdc5183..32bff10bd5e 100644 --- a/.github/prompts/backport-pr-to-release-branch.prompt.md +++ b/.github/prompts/backport-pr-to-release-branch.prompt.md @@ -231,13 +231,42 @@ Choose either tooling or Customer impact. - **Medium**: Changes non-critical features, adds new functionality, or modifies existing behavior - **Low**: Documentation, test-only changes, minor refactoring, or fixes with narrow scope - Justify your assessment based on the scope of changes and potential impact +- **For CI/CD changes**: When backporting CI/CD infrastructure changes (workflows, build scripts, packaging), note in your justification that not taking these changes may create technical debt and make it difficult to apply future CI/CD changes that build on top of them. This doesn't change the risk level itself, but provides important context for why the change should be taken despite potentially higher risk **If there were merge conflicts**: Add a note in the PR description after the Risk section describing what conflicts occurred and how they were resolved. -### Step 6: Clean up temporary files +### Step 6: Add the CL label to the backport PR -After successful PR creation, clean up any temporary files created during the process: +After creating the backport PR, add the same changelog label (CL-*) from the original PR to the backport PR: + +```bash +gh pr edit --repo PowerShell/PowerShell --add-label "" +``` + +Example: `gh pr edit 26389 --repo PowerShell/PowerShell --add-label "CL-BuildPackaging"` + +This ensures the backport is properly categorized in the changelog for the release branch. + +### Step 7: Update the original PR's backport labels + +After successfully creating the backport PR, update the original PR to reflect that it has been backported: + +```bash +gh pr edit --repo PowerShell/PowerShell --add-label "Backport-.x-Migrated" --remove-label "Backport-.x-Consider" +``` + +Example: `gh pr edit 26193 --repo PowerShell/PowerShell --add-label "Backport-7.5.x-Migrated" --remove-label "Backport-7.5.x-Consider"` + +Notes: +- If the original PR had `Backport-.x-Approved` instead of `Consider`, remove that label +- This step helps track which PRs have been successfully backported +- The `Migrated` label indicates the backport PR has been created (not necessarily merged) +- The `Done` label should only be added once the backport PR is merged + +### Step 8: Clean up temporary files + +After successful PR creation and labeling, clean up any temporary files created during the process: ```powershell Remove-Item pr*.diff -ErrorAction SilentlyContinue @@ -253,6 +282,8 @@ Remove-Item pr*.diff -ErrorAction SilentlyContinue - [ ] If conflicts occurred, provided resolution summary to user - [ ] Branch pushed to origin - [ ] PR created with correct title format: `[] ` +- [ ] CL label added to backport PR (matching original PR's CL label) +- [ ] Original PR labels updated (added Migrated, removed Consider/Approved) - [ ] Temporary files cleaned up (pr*.diff) - [ ] PR body includes: - [ ] Backport reference: `Backport of (PR-number) to ` @@ -269,13 +300,13 @@ Remove-Item pr*.diff -ErrorAction SilentlyContinue ## 6 — Branch naming convention -**Format:** `backport-` +**Format:** `backport/release//pr/` Examples: -- `backport-26193` -- `backport-26334` +- `backport/release/v7.5/pr/26193` +- `backport/release/v7.4.1/pr/26334` -Note: Automated bot uses format `backport/release/v/-`, but manual backports use the simpler `backport-` format. +Note: Automated bot uses format `backport/release/v/-`, but manual backports should use the format `backport/release//pr/` as shown above. ## 7 — Example backport PR From 000c116e5164365e14539ae6f5785011ffd7d098 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 5 Nov 2025 19:10:55 -0500 Subject: [PATCH 187/378] Add Fuzz Tests (#26384) Co-authored-by: anamnavi --- .../AssemblyInfo.cs | 1 + .../common/RemoteSessionHyperVSocket.cs | 35 +++++++-- test/fuzzing/FuzzingApp/Program.cs | 45 +++++++++++ test/fuzzing/FuzzingApp/Target.cs | 19 +++++ .../FuzzingApp/powershell-fuzz-tests.csproj | 29 +++++++ test/fuzzing/inputs/maxinput | 1 + test/fuzzing/inputs/mininput | 1 + test/fuzzing/runFuzzer.ps1 | 75 +++++++++++++++++++ 8 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 test/fuzzing/FuzzingApp/Program.cs create mode 100644 test/fuzzing/FuzzingApp/Target.cs create mode 100644 test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj create mode 100644 test/fuzzing/inputs/maxinput create mode 100644 test/fuzzing/inputs/mininput create mode 100644 test/fuzzing/runFuzzer.ps1 diff --git a/src/System.Management.Automation/AssemblyInfo.cs b/src/System.Management.Automation/AssemblyInfo.cs index 559d809fe72..e265bb453c8 100644 --- a/src/System.Management.Automation/AssemblyInfo.cs +++ b/src/System.Management.Automation/AssemblyInfo.cs @@ -7,6 +7,7 @@ [assembly: InternalsVisibleTo("powershell-tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo("powershell-perf,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] +[assembly: InternalsVisibleTo("powershell-fuzz-tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo(@"Microsoft.PowerShell.Commands.Utility" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo(@"Microsoft.PowerShell.Commands.Management" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index cd18dc511b1..8d53adf0ca8 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -434,7 +434,10 @@ internal static void ValidateToken(Socket socket, string token, DateTimeOffset t // Final check if we got the token before the timeout cancellationToken.ThrowIfCancellationRequested(); - if (string.IsNullOrEmpty(responseString) || !responseString.StartsWith("TOKEN ", StringComparison.Ordinal)) + ReadOnlySpan responseBytes = Encoding.UTF8.GetBytes(responseString); + string responseToken = RemoteSessionHyperVSocketClient.ExtractToken(responseBytes); + + if (responseToken == null) { socket.Send("FAIL"u8); // If the response is not in the expected format, we throw an exception. @@ -444,9 +447,6 @@ internal static void ValidateToken(Socket socket, string token, DateTimeOffset t PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Client", "Token Response")); } - // Extract the token from the response. - string responseToken = responseString.Substring(6).Trim(); - if (!string.Equals(responseToken, token, StringComparison.Ordinal)) { socket.Send("FAIL"u8); @@ -1059,14 +1059,18 @@ public static (bool success, string authenticationToken) ExchangeCredentialsAndC // allowing a significant larger size, allows the broker to make almost arbitrary changes, // without breaking the client. string token = ReceiveResponse(HyperVSocket, 1024); // either "PASS" or "FAIL" - if (token == null || !token.StartsWith("TOKEN ", StringComparison.Ordinal)) + + ReadOnlySpan tokenResponseBytes = Encoding.UTF8.GetBytes(token); + string extractedToken = ExtractToken(tokenResponseBytes); + + if (extractedToken == null) { s_tracer.WriteLine("ExchangeCredentialsAndConfiguration: Server did not respond with a valid token. Response: {0}", token); throw new PSDirectException( PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HyperVInvalidResponse, "Broker", "Token " + token)); } - token = token.Substring(6); // remove "TOKEN " prefix + token = extractedToken; HyperVSocket.Send("PASS"u8); // acknowledge the token return (true, token); @@ -1122,6 +1126,25 @@ internal static string ReceiveResponse(Socket socket, int bufferSize) } } + internal static string ExtractToken(ReadOnlySpan tokenResponse) + { + string token = Encoding.UTF8.GetString(tokenResponse); + + if (token == null || !token.StartsWith("TOKEN ", StringComparison.Ordinal)) + { + return null; // caller method will write trace (and determine when to expose token info as appropriate) + } + + token = token.Substring(6).Trim(); // remove "TOKEN " prefix + + if (token.Length == 0) + { + return null; + } + + return token; + } + /// /// Sends user data (domain, username, etc.) over the HyperVSocket using Unicode encoding. /// diff --git a/test/fuzzing/FuzzingApp/Program.cs b/test/fuzzing/FuzzingApp/Program.cs new file mode 100644 index 00000000000..77dee97165c --- /dev/null +++ b/test/fuzzing/FuzzingApp/Program.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Text; +using SharpFuzz; +using System.Management.Automation.Remoting; + +namespace FuzzTests +{ + public static class Program + { + public static void Main(string[] args) + { + FuzzTargetMethod(args); + } + + public static void FuzzTargetMethod(string[] args) + { + if (args == null) + { + Console.WriteLine("args was null"); + args = Array.Empty(); + } + + try + { + Fuzzer.LibFuzzer.Run(Target.ExtractToken); + } + catch (System.ArgumentNullException nex) + { + Console.WriteLine($"ArgumentNullException in main: {nex.Message}"); + Console.WriteLine($"Stack Trace: {nex.StackTrace}"); + Environment.Exit(1); + } + catch (Exception ex) + { + Console.WriteLine($"Exception in main: {ex.Message}"); + Console.WriteLine($"Exception type: {ex.GetType()}"); + Console.WriteLine($"Stack Trace: {ex.StackTrace}"); + Environment.Exit(1); + } + } + } +} diff --git a/test/fuzzing/FuzzingApp/Target.cs b/test/fuzzing/FuzzingApp/Target.cs new file mode 100644 index 00000000000..033f6517620 --- /dev/null +++ b/test/fuzzing/FuzzingApp/Target.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Text; +using SharpFuzz; +using System.Management.Automation.Remoting; + +namespace FuzzTests +{ + public static class Target + { + public static void ExtractToken(ReadOnlySpan tokenResponse) + { + RemoteSessionHyperVSocketClient.ExtractToken(tokenResponse); + } + } +} + diff --git a/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj b/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj new file mode 100644 index 00000000000..fc6549122f5 --- /dev/null +++ b/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj @@ -0,0 +1,29 @@ + + + + PowerShell Fuzzing + powershell-fuzz-tests + + + + Exe + net10.0 + enable + enable + + + + true + ../../../src/signing/visualstudiopublic.snk + true + + + + + + + + + + + diff --git a/test/fuzzing/inputs/maxinput b/test/fuzzing/inputs/maxinput new file mode 100644 index 00000000000..6773a896b3c --- /dev/null +++ b/test/fuzzing/inputs/maxinput @@ -0,0 +1 @@ +TOKEN abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/= \ No newline at end of file diff --git a/test/fuzzing/inputs/mininput b/test/fuzzing/inputs/mininput new file mode 100644 index 00000000000..c9b91c737c2 --- /dev/null +++ b/test/fuzzing/inputs/mininput @@ -0,0 +1 @@ +TOKEN TQ \ No newline at end of file diff --git a/test/fuzzing/runFuzzer.ps1 b/test/fuzzing/runFuzzer.ps1 new file mode 100644 index 00000000000..94000b59bbb --- /dev/null +++ b/test/fuzzing/runFuzzer.ps1 @@ -0,0 +1,75 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +param ( + [string]$libFuzzer = ".\libfuzzer-dotnet-windows.exe", + [string]$project = ".\FuzzingApp\powershell-fuzz-tests.csproj", + [Parameter(Mandatory=$true)] + [string]$corpus, + [string]$command = "sharpfuzz.exe" +) + +Set-StrictMode -Version Latest + +$outputDir = "out" + +if (Test-Path $outputDir) { + Remove-Item -Recurse -Force $outputDir +} + +Write-Host "dotnet publish $project -c release -o $outputDir" +dotnet publish $project -c release -o $outputDir +Write-Host "build completed" + +$projectName = (Get-Item $project).BaseName +$projectDll = "$projectName.dll" +$project = Join-Path $outputDir $projectDll + +$exclusions = @( + "dnlib.dll", + "SharpFuzz.dll", + "SharpFuzz.Common.dll" +) + +$exclusions += $projectDll + +Write-Host "instrumenting: $project" +& $command $project Target +Write-Host "done instrumenting $project" + +$fuzzingTargets = Get-ChildItem $outputDir -Filter *.dll ` +| Where-Object { $_.Name -notin $exclusions } ` +| Where-Object { $_.Name -notlike "System.*.dll" } +| Where-Object { $_.Name -notlike "Newtonsoft.*.dll" } +| Where-Object { $_.Name -notlike "Microsoft.*.dll" } + +foreach ($fuzzingTarget in $fuzzingTargets) { + Write-Output "Instrumenting $fuzzingTarget" + & $command $fuzzingTarget.FullName + + if ($LastExitCode -ne 0) { + Write-Error "An error occurred while instrumenting $fuzzingTarget" + exit 1 + } +} + +$smaDllPath = Join-Path $outputDir "System.Management.Automation.dll" + +Write-Host "instrumenting: $smaDllPath" +& $command $smaDllPath Remoting +Write-Host "done instrumenting: $smaDllPath" + +$fuzzingTargets += $projectDll +$fuzzingTargets += $smaDllPath + +if (($fuzzingTargets | Measure-Object).Count -eq 0) { + Write-Error "No fuzzing targets found" + exit 1 +} + +$outputPath = Join-Path $outputDir "output.txt" + +Write-Host "launching fuzzer on $project" +Write-Host "$libFuzzer --target_path=dotnet --target_arg=$project $corpus" +& $libFuzzer --target_path=dotnet --target_arg=$project $corpus -max_len=1024 2>&1 ` +| Tee-Object -FilePath $outputPath From 3953976592f94c72e6ab85c957c6458674429483 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 6 Nov 2025 16:36:54 -0800 Subject: [PATCH 188/378] Fix the fuzzy test (#26402) --- test/fuzzing/FuzzingApp/Program.cs | 6 +- test/fuzzing/FuzzingApp/Target.cs | 3 - .../FuzzingApp/powershell-fuzz-tests.csproj | 8 +- test/fuzzing/runFuzzer.ps1 | 80 ++++++++----------- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/test/fuzzing/FuzzingApp/Program.cs b/test/fuzzing/FuzzingApp/Program.cs index 77dee97165c..4e309ffc468 100644 --- a/test/fuzzing/FuzzingApp/Program.cs +++ b/test/fuzzing/FuzzingApp/Program.cs @@ -2,9 +2,7 @@ // Licensed under the MIT License. using System; -using System.Text; using SharpFuzz; -using System.Management.Automation.Remoting; namespace FuzzTests { @@ -27,7 +25,7 @@ public static void FuzzTargetMethod(string[] args) { Fuzzer.LibFuzzer.Run(Target.ExtractToken); } - catch (System.ArgumentNullException nex) + catch (ArgumentNullException nex) { Console.WriteLine($"ArgumentNullException in main: {nex.Message}"); Console.WriteLine($"Stack Trace: {nex.StackTrace}"); @@ -41,5 +39,5 @@ public static void FuzzTargetMethod(string[] args) Environment.Exit(1); } } - } + } } diff --git a/test/fuzzing/FuzzingApp/Target.cs b/test/fuzzing/FuzzingApp/Target.cs index 033f6517620..d82e17e8702 100644 --- a/test/fuzzing/FuzzingApp/Target.cs +++ b/test/fuzzing/FuzzingApp/Target.cs @@ -2,8 +2,6 @@ // Licensed under the MIT License. using System; -using System.Text; -using SharpFuzz; using System.Management.Automation.Remoting; namespace FuzzTests @@ -16,4 +14,3 @@ public static void ExtractToken(ReadOnlySpan tokenResponse) } } } - diff --git a/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj b/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj index fc6549122f5..7ee82c34cae 100644 --- a/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj +++ b/test/fuzzing/FuzzingApp/powershell-fuzz-tests.csproj @@ -1,15 +1,11 @@  + + PowerShell Fuzzing powershell-fuzz-tests - - - Exe - net10.0 - enable - enable diff --git a/test/fuzzing/runFuzzer.ps1 b/test/fuzzing/runFuzzer.ps1 index 94000b59bbb..5cb63393c4c 100644 --- a/test/fuzzing/runFuzzer.ps1 +++ b/test/fuzzing/runFuzzer.ps1 @@ -1,75 +1,65 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +<# +1. libfuzzer-dotnet-windows.exe can be installed from https://github.com/Metalnem/libfuzzer-dotnet/releases + +2. sharpfuzz can be installed with dotnet-tool: + > dotnet tool install --global SharpFuzz.CommandLine --version 2.2.0 + +Usage: sharpfuzz [path-to-assembly] [prefix ...] + +path-to-assembly: + The path to an assembly .dll file to instrument. + +prefix: + The class or the namespace to instrument. + If not present, all types in the assembly will be instrumented. + At least one prefix is required when instrumenting System.Private.CoreLib. + +Examples: + sharpfuzz Newtonsoft.Json.dll + sharpfuzz System.Private.CoreLib.dll System.Number + sharpfuzz System.Private.CoreLib.dll System.DateTimeFormat System.DateTimeParse +#> + param ( - [string]$libFuzzer = ".\libfuzzer-dotnet-windows.exe", - [string]$project = ".\FuzzingApp\powershell-fuzz-tests.csproj", - [Parameter(Mandatory=$true)] - [string]$corpus, + [string]$libFuzzer = "$PSScriptRoot\libfuzzer-dotnet-windows.exe", + [string]$project = "$PSScriptRoot\FuzzingApp\powershell-fuzz-tests.csproj", + [string]$corpus = "$PSScriptRoot\inputs", [string]$command = "sharpfuzz.exe" ) Set-StrictMode -Version Latest -$outputDir = "out" +$outputDir = "$PSScriptRoot\out" if (Test-Path $outputDir) { Remove-Item -Recurse -Force $outputDir } -Write-Host "dotnet publish $project -c release -o $outputDir" -dotnet publish $project -c release -o $outputDir +Write-Host "dotnet publish $project -c Debug -o $outputDir" +dotnet publish $project -c Debug -o $outputDir Write-Host "build completed" $projectName = (Get-Item $project).BaseName $projectDll = "$projectName.dll" $project = Join-Path $outputDir $projectDll +$smaDllPath = Join-Path $outputDir "System.Management.Automation.dll" -$exclusions = @( - "dnlib.dll", - "SharpFuzz.dll", - "SharpFuzz.Common.dll" -) - -$exclusions += $projectDll - +## Instrument the specific class within the test assembly. Write-Host "instrumenting: $project" -& $command $project Target +## !NOTE! If you instrument the class that defines "Main", it will fail. +& $command $project "FuzzTests.Target" Write-Host "done instrumenting $project" -$fuzzingTargets = Get-ChildItem $outputDir -Filter *.dll ` -| Where-Object { $_.Name -notin $exclusions } ` -| Where-Object { $_.Name -notlike "System.*.dll" } -| Where-Object { $_.Name -notlike "Newtonsoft.*.dll" } -| Where-Object { $_.Name -notlike "Microsoft.*.dll" } - -foreach ($fuzzingTarget in $fuzzingTargets) { - Write-Output "Instrumenting $fuzzingTarget" - & $command $fuzzingTarget.FullName - - if ($LastExitCode -ne 0) { - Write-Error "An error occurred while instrumenting $fuzzingTarget" - exit 1 - } -} - -$smaDllPath = Join-Path $outputDir "System.Management.Automation.dll" - +## Instrument any other assemblies that need to be tested. Write-Host "instrumenting: $smaDllPath" -& $command $smaDllPath Remoting +& $command $smaDllPath "System.Management.Automation.Remoting.RemoteSessionHyperVSocketClient" Write-Host "done instrumenting: $smaDllPath" -$fuzzingTargets += $projectDll -$fuzzingTargets += $smaDllPath - -if (($fuzzingTargets | Measure-Object).Count -eq 0) { - Write-Error "No fuzzing targets found" - exit 1 -} - $outputPath = Join-Path $outputDir "output.txt" Write-Host "launching fuzzer on $project" Write-Host "$libFuzzer --target_path=dotnet --target_arg=$project $corpus" -& $libFuzzer --target_path=dotnet --target_arg=$project $corpus -max_len=1024 2>&1 ` -| Tee-Object -FilePath $outputPath +& $libFuzzer --target_path=dotnet --target_arg=$project $corpus -max_len=1024 2>&1 | Tee-Object -FilePath $outputPath From e7bf5621bf8c3dfe7c4bdc69f83178077ec7bd5d Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 7 Nov 2025 11:53:43 -0800 Subject: [PATCH 189/378] Improve ADO package build and validation across platforms (#26398) --- .github/workflows/macos-ci.yml | 2 +- .pipelines/templates/mac-package-build.yml | 26 ++++-- build.psm1 | 11 ++- .../macos/package-validation.tests.ps1 | 81 ++++++++++++------- tools/packaging/packaging.psm1 | 70 ++++++++-------- 5 files changed, 116 insertions(+), 74 deletions(-) rename tools/packaging/releaseTests/macOSPackage.tests.ps1 => test/packaging/macos/package-validation.tests.ps1 (85%) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 2ee96079049..bdb7c128d12 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -205,7 +205,7 @@ jobs: } Import-Module Pester $pesterConfig = New-PesterConfiguration - $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.Path = './test/packaging/macos/package-validation.tests.ps1' $pesterConfig.Run.PassThru = $true $pesterConfig.Output.Verbosity = 'Detailed' $pesterConfig.TestResult.Enabled = $true diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 669ab3c8437..d429be91284 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -116,13 +116,25 @@ jobs: Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $pkgNameFilter = "powershell-*$macosRuntime.pkg" - $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$pkgPath" + Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File + + foreach($p in $pkgPath) { + $file = $p.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } Start-PSPackage -Type tar -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $tarPkgNameFilter = "powershell-*$macosRuntime.tar.gz" - $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$tarPkgPath" + Write-Verbose -Verbose "Looking for tar packages with filter: $tarPkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File + + foreach($t in $tarPkgPath) { + $file = $t.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } displayName: 'Package ${{ parameters.buildArchitecture}}' env: @@ -195,14 +207,14 @@ jobs: - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File - + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" - + if (-not (Test-Path $_)) { throw "Package not found: $_" } - + if (-not (Test-Path $(ob_outputDirectory))) { $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory } diff --git a/build.psm1 b/build.psm1 index c56303524be..dd2cf0f351e 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2399,7 +2399,7 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } - + # For Debian-based systems and Mariner, ensure dpkg-deb is available if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for dpkg-deb..." @@ -2407,9 +2407,14 @@ function Start-PSBootstrap { Write-Warning "dpkg-deb not found. Installing dpkg package..." if ($environment.IsMariner) { # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -verbose "BEGIN: /etc/os-release content:" + Get-Content /etc/os-release | Write-Verbose -verbose + Write-Verbose -verbose "END: /etc/os-release content" + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y azurelinux-repos-extended")) -IgnoreExitcode - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y dpkg")) -IgnoreExitcode + + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager azurelinux-repos-extended")) -IgnoreExitcode -Verbose + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager dpkg")) -IgnoreExitcode -Verbose } else { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode } diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 similarity index 85% rename from tools/packaging/releaseTests/macOSPackage.tests.ps1 rename to test/packaging/macos/package-validation.tests.ps1 index c1de1091562..02b09fbb078 100644 --- a/tools/packaging/releaseTests/macOSPackage.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -1,51 +1,54 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + Describe "Verify macOS Package" { BeforeAll { Write-Verbose "In Describe BeforeAll" -Verbose Import-Module $PSScriptRoot/../../../build.psm1 - + # Find the macOS package $packagePath = $env:PACKAGE_FOLDER if (-not $packagePath) { $packagePath = Get-Location } - + Write-Verbose "Looking for package in: $packagePath" -Verbose $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 - + if (-not $package) { Write-Warning "No .pkg file found in $packagePath" } else { Write-Verbose "Found package: $($package.FullName)" -Verbose } - + # Set up test directories $script:package = $package $script:expandDir = $null $script:payloadDir = $null $script:extractedFiles = @() - + if ($package) { # Use TestDrive for temporary directories - pkgutil will create the expand directory $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" - + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose # pkgutil will create the directory itself, so don't pre-create it Start-NativeExecution { pkgutil --expand $package.FullName $script:expandDir } - + # Extract the payload to verify files $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" - + # Create payload directory since cpio needs it if (-not (Test-Path $script:payloadDir)) { $null = New-Item -ItemType Directory -Path $script:payloadDir -Force } - + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 if ($componentPkg) { Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose @@ -57,40 +60,60 @@ Describe "Verify macOS Package" { Pop-Location } } - + # Get all extracted files for verification $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose } } - + AfterAll { # TestDrive automatically cleans up, but we can ensure cleanup happens # No manual cleanup needed as TestDrive handles it } - + Context "Package existence and structure" { It "Package file should exist" { $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" $script:package.Extension | Should -Be ".pkg" } - + + It "Package name should follow correct naming convention" { + $script:package | Should -Not -BeNullOrEmpty + + # Regex pattern for valid macOS PKG package names. + # Valid examples: + # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) + # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) + # - powershell-preview-7.6.0-preview.6-osx-x64.pkg + # - powershell-lts-7.4.13-osx-arm64.pkg + $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' + + $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" + } + + It "Package name should NOT use x86_64 with underscores" { + $script:package | Should -Not -BeNullOrEmpty + + $script:package.Name | Should -Not -Match 'x86_64' -Because "Package should use 'x64' not 'x86_64' (with underscores) for compatibility" + } + It "Package should expand successfully" { $script:expandDir | Should -Exist Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty } - + It "Package should have a component package" { $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" } - + It "Payload should extract successfully" { $script:payloadDir | Should -Exist $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" } } - + Context "Required files in package" { BeforeAll { $expectedFilePatterns = @{ @@ -99,7 +122,7 @@ Describe "Verify macOS Package" { "Man page" = "usr/local/share/man/man1/pwsh*.gz" "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" } - + $testCases = @() foreach ($key in $expectedFilePatterns.Keys) { $testCases += @{ @@ -107,23 +130,23 @@ Describe "Verify macOS Package" { Pattern = $expectedFilePatterns[$key] } } - + $script:testCases = $testCases } - + It "Should contain " -TestCases $script:testCases { param($Description, $Pattern) - + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" } } - + Context "PowerShell binary verification" { It "PowerShell executable should be executable" { $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } $pwshBinary | Should -Not -BeNullOrEmpty - + # Check if file has executable permissions (on Unix-like systems) if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode @@ -132,27 +155,27 @@ Describe "Verify macOS Package" { } } } - + Context "Launcher application" { It "Launcher app should have proper bundle structure" { $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } $plistFile | Should -Not -BeNullOrEmpty - + # Verify the bundle has required components $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent $macOSDir = Join-Path $appPath "Contents/MacOS" $resourcesDir = Join-Path $appPath "Contents/Resources" - + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" } - + It "Launcher script should exist and be executable" { - $launcherScript = $script:extractedFiles | Where-Object { - $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" } $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" - + if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index ccdc4e1cf08..e229aa493ae 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1239,15 +1239,15 @@ function New-UnixPackage { # Use rpmbuild directly for RPM packages if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { Write-Log "Creating RPM package with rpmbuild..." - + # Create rpmbuild directory structure $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" $specsDir = Join-Path $rpmBuildRoot "SPECS" $rpmsDir = Join-Path $rpmBuildRoot "RPMS" - + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null - + # Generate RPM spec file $specContent = New-RpmSpec ` -Name $Name ` @@ -1264,11 +1264,11 @@ function New-UnixPackage { -LinkInfo $Links ` -Distribution $DebDistro ` -HostArchitecture $HostArchitecture - + $specFile = Join-Path $specsDir "$Name.spec" $specContent | Out-File -FilePath $specFile -Encoding ascii Write-Verbose "Generated spec file: $specFile" -Verbose - + # Log the spec file content if ($env:GITHUB_ACTIONS -eq 'true') { Write-Host "::group::RPM Spec File Content" @@ -1277,7 +1277,7 @@ function New-UnixPackage { } else { Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose } - + # Build RPM package try { # Use bash to properly handle rpmbuild arguments @@ -1290,16 +1290,16 @@ function New-UnixPackage { Write-Verbose "Running: $buildCmd" -Verbose $Output = bash -c $buildCmd 2>&1 $exitCode = $LASTEXITCODE - + if ($exitCode -ne 0) { throw "rpmbuild failed with exit code $exitCode" } - + # Find the generated RPM - $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | - Sort-Object -Property LastWriteTime -Descending | + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 - + if ($rpmFile) { # Copy RPM to current location Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force @@ -1337,7 +1337,7 @@ function New-UnixPackage { -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` -HostArchitecture $HostArchitecture ` -CurrentLocation $CurrentLocation - + $Output = @("Created package {:path=>""$($result.PackageName)""}") } catch { @@ -1348,7 +1348,7 @@ function New-UnixPackage { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { Write-Log "Creating macOS package with native tools..." - + $macPkgArgs = @{ Name = $Name Version = $packageVersion @@ -1363,7 +1363,7 @@ function New-UnixPackage { HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation } - + try { $packageFile = New-MacOSPackage @macPkgArgs $Output = @("Created package {:path=>""$($packageFile.Name)""}") @@ -1386,7 +1386,7 @@ function New-UnixPackage { Clear-MacOSLauncher } } - + # Clean up rpmbuild directory if it was created if ($Type -eq 'rpm') { $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" @@ -1395,7 +1395,7 @@ function New-UnixPackage { Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue } } - + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1489,13 +1489,13 @@ function New-MacOsDistributionPackage $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" if (Test-Path $backgroundFile) { Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } - + # Copy the component package to temp directory $componentFileName = Split-Path -Leaf -Path $ComponentPackage $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName @@ -1511,7 +1511,7 @@ function New-MacOsDistributionPackage # Minimum OS version $minOSVersion = "11.0" # macOS Big Sur minimum - + # format distribution template with: # 0 - title # 1 - version @@ -1522,8 +1522,10 @@ function New-MacOsDistributionPackage $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force # Build final package path - $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" - + # Rename x86_64 to x64 for compatibility + $packageArchName = if ($HostArchitecture -eq "x86_64") { "x64" } else { $HostArchitecture } + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$packageArchName.pkg" + # Remove existing package if it exists if (Test-Path $finalPackagePath) { Write-Warning "Removing existing package: $finalPackagePath" @@ -1542,7 +1544,7 @@ function New-MacOsDistributionPackage --resources $resourcesDir ` $finalPackagePath } - + if (Test-Path $finalPackagePath) { Write-Log "Successfully created macOS package: $finalPackagePath" } @@ -1612,7 +1614,7 @@ function New-RpmSpec # RPM doesn't allow hyphens in version, so convert them to underscores # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 $rpmVersion = $Version -replace '-', '_' - + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") # Don't use RPM macros - build the full release string in PowerShell $rpmRelease = "$Iteration.$Distribution" @@ -1638,7 +1640,7 @@ AutoReq: no } else { # For cross-architecture builds, don't specify BuildArch in spec # The --target option will handle the architecture - + # Disable automatic binary stripping for cross-arch builds # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: # "Unable to recognise the format of the input file" @@ -1646,7 +1648,7 @@ AutoReq: no # __strip: This macro controls the command used for stripping binaries during the build process. # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. $specContent += "%define __strip /bin/true`n" - + # Disable debug package generation to prevent strip-related errors # Debug packages require binary stripping which fails for cross-arch builds # See: https://rpm-packaging-guide.github.io/#debugging @@ -1903,11 +1905,11 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) # Copy DEBIAN directory and data files to build root $buildDir = Join-Path $debBuildRoot "build" New-Item -ItemType Directory -Path $buildDir -Force | Out-Null - + Write-Verbose "debianDir: $debianDir" -Verbose Write-Verbose "dataDir: $dataDir" -Verbose Write-Verbose "buildDir: $buildDir" -Verbose - + # Use cp to preserve symlinks Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } Start-NativeExecution { cp -a $dataDir/* $buildDir } @@ -2017,14 +2019,14 @@ function New-MacOSPackage $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null $finalLinkPath = Join-Path $pkgRoot $link.Destination - + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose - + # Remove if exists if (Test-Path $finalLinkPath) { Remove-Item $finalLinkPath -Force } - + # Get the target of the original symlink and recreate it in the package root if (Test-Path $link.Source) { $linkTarget = (Get-Item $link.Source).Target @@ -2050,10 +2052,10 @@ function New-MacOSPackage # Build the component package using pkgbuild $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') - + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." - + Start-NativeExecution -VerboseOutputOnError { pkgbuild --root $pkgRoot ` --identifier $pkgIdentifier ` @@ -2062,7 +2064,7 @@ function New-MacOSPackage --install-location "/" ` $componentPkgPath } - + Write-Verbose "Component package created: $componentPkgPath" -Verbose } @@ -2075,7 +2077,7 @@ function New-MacOSPackage -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` -IsPreview:($Name -like '*-preview') - + return $distributionPackage } finally { From 3596ffa9090f2f3dd2f1bdba2fa98172ad7cbcd3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 10 Nov 2025 11:05:12 -0800 Subject: [PATCH 190/378] Optimize/split windows package signing (#26403) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../chatmodes/cherry-pick-commits.chatmode.md | 78 ++++++ .../build-configuration-guide.instructions.md | 3 +- ...ode-review-branch-strategy.instructions.md | 230 ++++++++++++++++++ ...anch-restore-phase-pattern.instructions.md | 83 +++++++ ...anch-signing-configuration.instructions.md | 195 +++++++++++++++ .pipelines/MSIXBundle-vPack-Official.yml | 1 - ...werShell-Coordinated_Packages-Official.yml | 1 - .pipelines/PowerShell-Packages-Official.yml | 62 +++-- .pipelines/PowerShell-vPack-Official.yml | 1 - .pipelines/templates/SetVersionVariables.yml | 59 ++--- .pipelines/templates/checkAzureContainer.yml | 3 +- .pipelines/templates/cloneToOfficialPath.yml | 18 +- .pipelines/templates/compliance/apiscan.yml | 3 +- .pipelines/templates/install-dotnet.yml | 7 +- .pipelines/templates/linux-package-build.yml | 3 +- .pipelines/templates/mac-package-build.yml | 3 +- .pipelines/templates/nupkg.yml | 3 +- .pipelines/templates/package-create-msix.yml | 6 +- .../windows/package.yml} | 149 +++--------- .../templates/packaging/windows/sign.yml | 216 ++++++++++++++++ .../templates/release-MakeBlobPublic.yml | 6 +- .../templates/release-checkout-pwsh-repo.yml | 13 - .../templates/release-download-packages.yml | 122 ---------- .pipelines/templates/release-install-pwsh.yml | 34 --- .pipelines/templates/set-reporoot.yml | 35 +++ .pipelines/templates/shouldSign.yml | 7 +- .pipelines/templates/uploadToAzure.yml | 3 +- 27 files changed, 969 insertions(+), 375 deletions(-) create mode 100644 .github/chatmodes/cherry-pick-commits.chatmode.md create mode 100644 .github/instructions/code-review-branch-strategy.instructions.md create mode 100644 .github/instructions/onebranch-restore-phase-pattern.instructions.md create mode 100644 .github/instructions/onebranch-signing-configuration.instructions.md rename .pipelines/templates/{windows-package-build.yml => packaging/windows/package.yml} (56%) create mode 100644 .pipelines/templates/packaging/windows/sign.yml delete mode 100644 .pipelines/templates/release-checkout-pwsh-repo.yml delete mode 100644 .pipelines/templates/release-download-packages.yml delete mode 100644 .pipelines/templates/release-install-pwsh.yml create mode 100644 .pipelines/templates/set-reporoot.yml diff --git a/.github/chatmodes/cherry-pick-commits.chatmode.md b/.github/chatmodes/cherry-pick-commits.chatmode.md new file mode 100644 index 00000000000..826ab11d56c --- /dev/null +++ b/.github/chatmodes/cherry-pick-commits.chatmode.md @@ -0,0 +1,78 @@ +# Cherry-Pick Commits Between Branches + +Cherry-pick recent commits from a source branch to a target branch without switching branches. + +## Instructions for Copilot + +1. **Confirm branches with the user** + - Ask the user to confirm the source and target branches + - If different branches are needed, update the configuration + +2. **Identify unique commits** + - Run: `git log .. --oneline --reverse` + - **IMPORTANT**: The commit count may be misleading if branches diverged from different base commits + - Compare the LAST few commits from each branch to identify actual missing commits: + - `git log --oneline -10` + - `git log --oneline -10` + - Look for commits with the same message but different SHAs (rebased commits) + - Show the user ONLY the truly missing commits (usually just the most recent ones) + +3. **Confirm with user before proceeding** + - If the commit count seems unusually high (e.g., 400+), STOP and verify semantically + - Ask: "I found X commits to cherry-pick. Shall I proceed?" + - If there are many commits, warn that this may take time + +4. **Execute the cherry-pick** + - Ensure the target branch is checked out first + - Run: `git cherry-pick ` for single commits + - Or: `git cherry-pick ` for multiple commits + - Apply commits in chronological order (oldest first) + +5. **Handle any issues** + - If conflicts occur, pause and ask user for guidance + - If empty commits occur, automatically skip with `git cherry-pick --skip` + +6. **Verify and report results** + - Run: `git log - --oneline` + - Show the user the newly applied commits + - Confirm the branch is now ahead by X commits + +## Key Git Commands + +```bash +# Find unique commits (may show full divergence if branches were rebased) +git log .. --oneline --reverse + +# Compare recent commits on each branch (more reliable for rebased branches) +git log --oneline -10 +git log --oneline -10 + +# Cherry-pick specific commits (when target is checked out) +git cherry-pick +git cherry-pick + +# Skip empty commits +git cherry-pick --skip + +# Verify result +git log - --oneline +``` + +## Common Scenarios + +- **Empty commits**: Automatically skip with `git cherry-pick --skip` +- **Conflicts**: Stop, show files with conflicts, ask user to resolve +- **Many commits**: Warn user and confirm before proceeding +- **Already applied**: These will result in empty commits that should be skipped +- **Diverged branches**: If branches diverged (rebased), `git log` may show the entire history difference + - The actual missing commits are usually only the most recent ones + - Compare commit messages from recent history on both branches + - Cherry-pick only commits that are semantically missing + +## Workflow Style + +Use an interactive, step-by-step approach: +- Show output from each command +- Ask for confirmation before major actions +- Provide clear status updates +- Handle errors gracefully with user guidance diff --git a/.github/instructions/build-configuration-guide.instructions.md b/.github/instructions/build-configuration-guide.instructions.md index 56844777d95..d0384f4f307 100644 --- a/.github/instructions/build-configuration-guide.instructions.md +++ b/.github/instructions/build-configuration-guide.instructions.md @@ -4,6 +4,7 @@ applyTo: - "tools/ci.psm1" - ".github/**/*.yml" - ".github/**/*.yaml" + - ".pipelines/**/*.yml" --- # Build Configuration Guide @@ -121,7 +122,7 @@ The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source - **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) - Required for: CI/CD environments, public builds, packaging - Does not require authentication - + - **Private**: Uses internal PowerShell team feeds - Required for: Internal development with preview packages - Requires authentication credentials diff --git a/.github/instructions/code-review-branch-strategy.instructions.md b/.github/instructions/code-review-branch-strategy.instructions.md new file mode 100644 index 00000000000..191a677b912 --- /dev/null +++ b/.github/instructions/code-review-branch-strategy.instructions.md @@ -0,0 +1,230 @@ +--- +applyTo: "**/*" +--- + +# Code Review Branch Strategy Guide + +This guide helps GitHub Copilot provide appropriate feedback when reviewing code changes, particularly distinguishing between issues that should be fixed in the current branch versus the default branch. + +## Purpose + +When reviewing pull requests, especially those targeting release branches, it's important to identify whether an issue should be fixed in: +- **The current PR/branch** - Release-specific fixes or backports +- **The default branch first** - General bugs that exist in the main codebase + +## Branch Types and Fix Strategy + +### Release Branches (e.g., `release/v7.5`, `release/v7.4`) + +**Purpose:** Contain release-specific changes and critical backports + +**Should contain:** +- Release-specific configuration changes +- Critical bug fixes that are backported from the default branch +- Release packaging/versioning adjustments + +**Should NOT contain:** +- New general bug fixes that haven't been fixed in the default branch +- Refactoring or improvements that apply to the main codebase +- Workarounds for issues that exist in the default branch + +### Default/Main Branch (e.g., `master`, `main`) + +**Purpose:** Primary development branch for all ongoing work + +**Should contain:** +- All general bug fixes +- New features and improvements +- Refactoring and code quality improvements +- Fixes that will later be backported to release branches + +## Identifying Issues That Belong in the Default Branch + +When reviewing a PR targeting a release branch, look for these indicators that suggest the fix should be in the default branch first: + +### 1. The Root Cause Exists in Default Branch + +If the underlying issue exists in the default branch's code, it should be fixed there first. + +**Example:** +```yaml +# PR changes this in release/v7.5: +- $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json ++ $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json +``` + +**Analysis:** If `$repoRoot` is undefined because the template doesn't include its dependencies in BOTH the release branch AND the default branch, the fix should address the root cause in the default branch first. + +### 2. The Fix is a Workaround Rather Than a Proper Solution + +If the change introduces a workaround (hardcoded paths, special cases) rather than fixing the underlying design issue, it likely belongs in the default branch as a proper fix. + +**Example:** +- Using hardcoded paths instead of fixing variable initialization +- Adding special cases instead of fixing the logic +- Duplicating code instead of fixing shared dependencies + +### 3. The Issue Affects General Functionality + +If the issue affects general functionality not specific to a release, it should be fixed in the default branch. + +**Example:** +- Template dependencies that affect all pipelines +- Shared utility functions +- Common configuration issues + +## Providing Code Review Feedback + +### For Issues in the Current Branch + +When an issue is specific to the current branch or is a legitimate fix for the branch being targeted, **use the default code review feedback format** without any special branch-strategy commentary. + +### For Issues That Belong in the Default Branch + +1. **Provide the code review feedback** +2. **Explain why it should be fixed in the default branch** +3. **Provide an issue template** in markdown format + +**Example:** + +```markdown +The `channelSelection.yml` template relies on `$repoRoot` being set by `SetVersionVariables.yml`, but doesn't declare this dependency. This issue exists in both the release branch and the default branch. + +**This should be fixed in the default branch first**, then backported if needed. The proper fix is to ensure template dependencies are correctly declared, rather than using hardcoded paths as a workaround. + +--- + +**Suggested Issue for Default Branch:** + +### Issue Title +`channelSelection.yml` template missing dependency on `SetVersionVariables.yml` + +### Description +The `channelSelection.yml` template uses the `$repoRoot` variable but doesn't ensure it's set beforehand by including `SetVersionVariables.yml`. + +**Current State:** +- `channelSelection.yml` expects `$repoRoot` to be available +- Not all pipelines that use `channelSelection.yml` include `SetVersionVariables.yml` first +- This creates an implicit dependency that's not enforced + +**Expected State:** +Either: +1. `channelSelection.yml` should include `SetVersionVariables.yml` as a dependency, OR +2. `channelSelection.yml` should be refactored to not depend on `$repoRoot`, OR +3. Pipelines using `channelSelection.yml` should explicitly include `SetVersionVariables.yml` first + +**Files Affected:** +- `.pipelines/templates/channelSelection.yml` +- `.pipelines/templates/package-create-msix.yml` +- `.pipelines/templates/release-SetTagAndChangelog.yml` + +**Priority:** Medium +**Labels:** `Issue-Bug`, `Area-Build`, `Area-Pipeline` +``` + +## Issue Template Format + +When creating an issue template for the default branch, use this structure: + +```markdown +### Issue Title +[Clear, concise description of the problem] + +### Description +[Detailed explanation of the issue] + +**Current State:** +- [What's happening now] +- [Why it's problematic] + +**Expected State:** +- [What should happen] +- [Proposed solution(s)] + +**Files Affected:** +- [List of files] + +**Priority:** [Low/Medium/High/Critical] +**Labels:** [Suggested labels like `Issue-Bug`, `Area-*`] + +**Additional Context:** +[Any additional information, links to related issues, etc.] +``` + +## Common Scenarios + +### Scenario 1: Template Dependency Issues + +**Indicators:** +- Missing template includes +- Undefined variables from other templates +- Assumptions about pipeline execution order + +**Action:** Suggest fixing template dependencies in the default branch. + +### Scenario 2: Hardcoded Values + +**Indicators:** +- Hardcoded paths replacing variables +- Environment-specific values in shared code +- Magic strings or numbers + +**Action:** Suggest proper variable/parameter usage in the default branch. + +### Scenario 3: Logic Errors + +**Indicators:** +- Incorrect conditional logic +- Missing error handling +- Race conditions + +**Action:** Suggest fixing the logic in the default branch unless it's release-specific. + +### Scenario 4: Legitimate Release Branch Fixes + +**Indicators:** +- Version-specific configuration +- Release packaging changes +- Backport of already-fixed default branch issue + +**Action:** Provide normal code review feedback for the current PR. + +## Best Practices + +1. **Always check if the issue exists in the default branch** before suggesting a release-branch-only fix +2. **Prefer fixing root causes over workarounds** +3. **Provide clear rationale** for why a fix belongs in the default branch +4. **Include actionable issue templates** so users can easily create issues +5. **Be helpful, not blocking** - provide the feedback even if you can't enforce where it's fixed + +## Examples of Good vs. Bad Approaches + +### ❌ Bad: Workaround in Release Branch Only + +```yaml +# In release/v7.5 only +- pwsh: | + $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw +``` + +**Why bad:** Hardcodes path to work around missing `$repoRoot`, doesn't fix the default branch. + +### ✅ Good: Fix in Default Branch, Then Backport + +```yaml +# In default branch first +- template: SetVersionVariables.yml@self # Ensures $repoRoot is set +- template: channelSelection.yml@self # Now can use $repoRoot +``` + +**Why good:** Fixes the root cause by ensuring dependencies are declared, then backport to release if needed. + +## When in Doubt + +If you're unsure whether an issue should be fixed in the current branch or the default branch, ask yourself: + +1. Does this issue exist in the default branch? +2. Is this a workaround or a proper fix? +3. Will other branches/releases benefit from this fix? + +If the answer to any of these is "yes," suggest fixing it in the default branch first. diff --git a/.github/instructions/onebranch-restore-phase-pattern.instructions.md b/.github/instructions/onebranch-restore-phase-pattern.instructions.md new file mode 100644 index 00000000000..0945bb47c0b --- /dev/null +++ b/.github/instructions/onebranch-restore-phase-pattern.instructions.md @@ -0,0 +1,83 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Restore Phase Pattern + +## Overview +When steps need to run in the OneBranch restore phase (before the main build phase), the `ob_restore_phase` environment variable must be set in the `env:` block of **each individual step**. + +## Pattern + +### ✅ Correct (Working Pattern) +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # or false if you don't want restore phase + +steps: +- powershell: | + # script content + displayName: 'Step Name' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} +``` + +The key is to: +1. Define `ob_restore_phase` as a **boolean** parameter +2. Set `ob_restore_phase: ${{ parameters.ob_restore_phase }}` directly in each step's `env:` block +3. Pass `true` to run in restore phase, `false` to run in normal build phase + +### ❌ Incorrect (Does Not Work) +```yaml +steps: +- powershell: | + # script content + displayName: 'Step Name' + ${{ if eq(parameters.useRestorePhase, 'yes') }}: + env: + ob_restore_phase: true +``` + +Using conditionals at the same indentation level as `env:` causes only the first step to execute in restore phase. + +## Parameters + +Templates using this pattern should accept an `ob_restore_phase` boolean parameter: + +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # Set to true to run in restore phase by default +``` + +## Reference Examples + +Working examples of this pattern can be found in: +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Demonstrates the correct pattern +- `.pipelines/templates/SetVersionVariables.yml` - Updated to use this pattern + +## Why This Matters + +The restore phase in OneBranch pipelines runs before signing and other build operations. Steps that need to: +- Set environment variables for the entire build +- Configure authentication +- Prepare the repository structure + +Must run in the restore phase to be available when subsequent stages execute. + +## Common Use Cases + +- Setting `REPOROOT` variable +- Configuring NuGet feeds with authentication +- Setting version variables +- Repository preparation and validation + +## Troubleshooting + +If only the first step in your template is running in restore phase: +1. Check that `env:` block exists for **each step** +2. Verify the conditional `${{ if ... }}:` is **inside** the `env:` block +3. Confirm indentation is correct (conditional is indented under `env:`) diff --git a/.github/instructions/onebranch-signing-configuration.instructions.md b/.github/instructions/onebranch-signing-configuration.instructions.md new file mode 100644 index 00000000000..747fcaffdd6 --- /dev/null +++ b/.github/instructions/onebranch-signing-configuration.instructions.md @@ -0,0 +1,195 @@ +--- +applyTo: + - ".pipelines/**/*.yml" + - ".pipelines/**/*.yaml" +--- + +# OneBranch Signing Configuration + +This guide explains how to configure OneBranch signing variables in Azure Pipeline jobs, particularly when signing is not required. + +## Purpose + +OneBranch pipelines include signing infrastructure by default. For build-only jobs where signing happens in a separate stage, you should disable signing setup to improve performance and avoid unnecessary overhead. + +## Disable Signing for Build-Only Jobs + +When a job does not perform signing (e.g., it only builds artifacts that will be signed in a later stage), disable both signing setup and code sign validation: + +```yaml +variables: + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage +``` + +### Why Disable These Variables? + +**`ob_signing_setup_enabled: false`** +- Prevents OneBranch from setting up the signing infrastructure +- Reduces job startup time +- Avoids unnecessary credential validation +- Only disable when the job will NOT sign any artifacts + +**`ob_sdl_codeSignValidation_enabled: false`** +- Skips validation that checks if files are properly signed +- Appropriate for build stages where artifacts are unsigned +- Must be enabled in signing/release stages to validate signatures + +## Common Patterns + +### Build-Only Job (No Signing) + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + - pwsh: | + # Build unsigned artifacts + Start-PSBuild +``` + +### Signing Job + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true + - name: ob_sdl_codeSignValidation_enabled + value: true + steps: + - checkout: self + env: + ob_restore_phase: true # Steps before first signing operation + - pwsh: | + # Prepare artifacts for signing + env: + ob_restore_phase: true # Steps before first signing operation + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + # Signing step runs in build phase (no ob_restore_phase) + - pwsh: | + # Post-signing validation + # Post-signing steps run in build phase (no ob_restore_phase) +``` + +## Restore Phase Usage with Signing + +**The restore phase (`ob_restore_phase: true`) should only be used in jobs that perform signing operations.** It separates preparation steps from the actual signing and build steps. + +### When to Use Restore Phase + +Use `ob_restore_phase: true` **only** in jobs where `ob_signing_setup_enabled: true`: + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true # Signing enabled + steps: + # Steps BEFORE first signing operation: use restore phase + - checkout: self + env: + ob_restore_phase: true + - template: prepare-for-signing.yml + parameters: + ob_restore_phase: true + + # SIGNING STEP: runs in build phase (no ob_restore_phase) + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + + # Steps AFTER signing: run in build phase (no ob_restore_phase) + - pwsh: | + # Validation or packaging +``` + +### When NOT to Use Restore Phase + +**Do not use restore phase in build-only jobs** where `ob_signing_setup_enabled: false`: + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false # No signing + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + # NO ob_restore_phase - not needed without signing + - pwsh: | + Start-PSBuild +``` + +**Why?** The restore phase is part of OneBranch's signing infrastructure. Using it without signing enabled adds unnecessary overhead without benefit. + +## Related Variables + +Other OneBranch signing-related variables: + +- `ob_sdl_binskim_enabled`: Controls BinSkim security analysis (can be false in build-only, true in signing stages) + +## Best Practices + +1. **Separate build and signing stages**: Build artifacts in one job, sign in another +2. **Disable signing in build stages**: Improves performance and clarifies intent +3. **Only use restore phase with signing**: The restore phase should only be used in jobs where signing is enabled (`ob_signing_setup_enabled: true`) +4. **Restore phase before first signing step**: All steps before the first signing operation should use `ob_restore_phase: true` +5. **Always validate after signing**: Enable validation in signing stages to catch issues +6. **Document the reason**: Add comments explaining why signing is disabled or why restore phase is used + +## Example: Split Build and Sign Pipeline + +```yaml +stages: + - stage: Build + jobs: + - job: build_windows + variables: + - name: ob_signing_setup_enabled + value: false # Build-only, no signing + - name: ob_sdl_codeSignValidation_enabled + value: false # Artifacts are unsigned + steps: + - template: templates/build-unsigned.yml + + - stage: Sign + dependsOn: Build + jobs: + - job: sign_windows + variables: + - name: ob_signing_setup_enabled + value: true # Enable signing infrastructure + - name: ob_sdl_codeSignValidation_enabled + value: true # Validate signatures + steps: + - template: templates/sign-artifacts.yml +``` + +## Troubleshooting + +**Job fails with signing-related errors but signing is disabled:** +- Verify `ob_signing_setup_enabled: false` is set in variables +- Check that no template is overriding the setting +- Ensure `ob_sdl_codeSignValidation_enabled: false` is also set + +**Signed artifacts fail validation:** +- Confirm `ob_sdl_codeSignValidation_enabled: true` in signing job +- Verify signing actually occurred +- Check certificate configuration + +## Reference + +- PowerShell signing templates: `.pipelines/templates/packaging/windows/sign.yml` diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 8e175c5a6bb..997b7c458be 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -99,7 +99,6 @@ extends: - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - UseJson: no - pwsh: | Write-Verbose -Verbose 'PowerShell Version: $(version)' diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index e70b65a9a64..f36eeadf298 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -178,7 +178,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - stage: macos displayName: macOS - build and sign diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 9c2dee1c571..8e06be1cc64 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -127,11 +127,13 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep + displayName: 'Prep BuildInfo+Az' jobs: - template: /.pipelines/templates/checkAzureContainer.yml@self - stage: mac_package - dependsOn: [prep] + displayName: 'macOS Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/mac-package-build.yml@self parameters: @@ -141,35 +143,65 @@ extends: parameters: buildArchitecture: arm64 - - stage: windows_package - dependsOn: [prep] + - stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] jobs: - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: arm64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x86 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependent - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependentWinDesktop - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + + - stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self parameters: runtime: minsize - stage: linux_package - dependsOn: [prep] + displayName: 'Linux Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -251,17 +283,19 @@ extends: jobName: minSize - stage: nupkg - dependsOn: [prep] + displayName: 'NuGet Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/nupkg.yml@self - stage: msixbundle - displayName: 'Create MSIX Bundle' - dependsOn: [windows_package] + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self - stage: upload - dependsOn: [mac_package, windows_package, linux_package, nupkg, msixbundle] + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 7ba92f4eda9..096dfb574a4 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -159,7 +159,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - pwsh: | $version = '$(Version)' diff --git a/.pipelines/templates/SetVersionVariables.yml b/.pipelines/templates/SetVersionVariables.yml index 9f692373f6c..30ed1704022 100644 --- a/.pipelines/templates/SetVersionVariables.yml +++ b/.pipelines/templates/SetVersionVariables.yml @@ -1,49 +1,18 @@ parameters: - ReleaseTagVar: v6.2.0 - ReleaseTagVarName: ReleaseTagVar - CreateJson: 'no' - UseJson: 'yes' +- name: ReleaseTagVar + default: v6.2.0 +- name: ReleaseTagVarName + default: ReleaseTagVar +- name: CreateJson + default: 'no' +- name: ob_restore_phase + type: boolean + default: true steps: -- ${{ if eq(parameters['UseJson'],'yes') }}: - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'drop_prep_SetVars' - itemPattern: '*.json' - downloadPath: '$(System.ArtifactsDirectory)' - displayName: Download Build Info Json - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - -- powershell: | - $path = "./build.psm1" - if($env:REPOROOT){ - Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose - exit 0 - } - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detected at: ." -Verbose - $repoRoot = '.' - } - else{ - $path = "./PowerShell/build.psm1" - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detect at: ./PowerShell" -Verbose - $repoRoot = './PowerShell' - } - } - if($repoRoot) { - $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } else { - Write-Verbose -Verbose "repo not found" - } - displayName: 'Set repo Root' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue +- template: set-reporoot.yml@self + parameters: + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | $createJson = ("${{ parameters.CreateJson }}" -ne "no") @@ -69,11 +38,11 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | Get-ChildItem -Path Env: | Out-String -Width 150 displayName: Capture environment condition: succeededOrFailed() env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml index a6a86214d07..3e383d2c572 100644 --- a/.pipelines/templates/checkAzureContainer.yml +++ b/.pipelines/templates/checkAzureContainer.yml @@ -3,6 +3,8 @@ jobs: variables: - group: Azure Blob variable group - group: AzureBlobServiceConnection + - name: ob_artifactBaseName + value: BuildInfoJson - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - name: ob_sdl_sbom_enabled @@ -29,7 +31,6 @@ jobs: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - template: /.pipelines/templates/cloneToOfficialPath.yml@self diff --git a/.pipelines/templates/cloneToOfficialPath.yml b/.pipelines/templates/cloneToOfficialPath.yml index 844d8b8028d..b060c713683 100644 --- a/.pipelines/templates/cloneToOfficialPath.yml +++ b/.pipelines/templates/cloneToOfficialPath.yml @@ -1,5 +1,9 @@ parameters: - nativePathRoot: '' +- name: nativePathRoot + default: '' +- name: ob_restore_phase + type: boolean + default: true steps: - powershell: | @@ -12,8 +16,16 @@ steps: else { Write-Verbose -Verbose -Message "No cleanup required." } - git clone --quiet $env:REPOROOT $nativePath + # REPOROOT must be set by the pipeline - this is where the repository was checked out + $sourceDir = $env:REPOROOT + if (-not $sourceDir) { throw "REPOROOT environment variable is not set. This step depends on REPOROOT being configured in the pipeline." } + + $buildModulePath = Join-Path $sourceDir "build.psm1" + if (-not (Test-Path $buildModulePath)) { throw "build.psm1 not found at: $buildModulePath. REPOROOT must point to the PowerShell repository root." } + + Write-Verbose -Verbose -Message "Cloning from: $sourceDir to $nativePath" + git clone --quiet $sourceDir $nativePath displayName: Clone PowerShell Repo to /PowerShell errorActionPreference: silentlycontinue env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 817d5ab777f..5809af8e28c 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -50,8 +50,7 @@ jobs: - template: ../SetVersionVariables.yml parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: ../insert-nuget-config-azfeed.yml parameters: diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml index c2a2cfebeca..464e13d1047 100644 --- a/.pipelines/templates/install-dotnet.yml +++ b/.pipelines/templates/install-dotnet.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - pwsh: | if (-not (Test-Path '$(RepoRoot)')) { @@ -15,5 +20,5 @@ steps: displayName: 'Install dotnet SDK' workingDirectory: $(RepoRoot) env: - ob_restore_phase: true + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 68fa46690c2..b1c170eaed5 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -54,8 +54,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index d429be91284..1abb1722398 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -52,8 +52,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 4756c99a9d3..3a2aa4f3172 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -41,8 +41,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index f45f3718b04..ed0217b2940 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -26,7 +26,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_arm64 + artifact: drop_windows_package_arm64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -35,7 +35,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x64 + artifact: drop_windows_package_x64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -44,7 +44,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x86 + artifact: drop_windows_package_x86 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/packaging/windows/package.yml similarity index 56% rename from .pipelines/templates/windows-package-build.yml rename to .pipelines/templates/packaging/windows/package.yml index bc23bfc659e..9a8be4b18fe 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -2,8 +2,8 @@ parameters: runtime: x64 jobs: -- job: package_win_${{ parameters.runtime }} - displayName: Package Windows ${{ parameters.runtime }} +- job: build_win_${{ parameters.runtime }} + displayName: Build Windows Packages ${{ parameters.runtime }} condition: succeeded() pool: type: windows @@ -11,6 +11,12 @@ jobs: variables: - name: runCodesignValidationInjection value: false + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage, signing happens in separate stage + - name: ob_artifactBaseName + value: drop_windows_package_${{ parameters.runtime }} - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel @@ -22,7 +28,7 @@ jobs: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled - value: true + value: false # Disable for build-only, enable in signing stage - name: ob_sdl_tsa_configFile value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_sdl_credscan_suppressionsFile @@ -34,40 +40,35 @@ jobs: steps: - checkout: self clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - pwsh: | Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture environment - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - template: SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no + ob_restore_phase: false - - template: shouldSign.yml + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false - - template: cloneToOfficialPath.yml + - template: /.pipelines/templates/cloneToOfficialPath.yml@self parameters: nativePathRoot: '$(Agent.TempDirectory)' + ob_restore_phase: false - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts condition: ${{ ne(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_x64_${{ parameters.runtime }} displayName: Download minsize signed artifacts condition: ${{ eq(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - pwsh: | Write-Verbose -Verbose "signed artifacts" @@ -75,18 +76,10 @@ jobs: displayName: 'Capture Downloaded Artifacts' # Diagnostics is not critical it passes every time it runs continueOnError: true - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - template: /.pipelines/templates/install-dotnet.yml@self - - - pwsh: | - $msixUrl = '$(makeappUrl)' - Invoke-RestMethod -Uri $msixUrl -OutFile '$(Pipeline.Workspace)\makeappx.zip' - Expand-Archive '$(Pipeline.Workspace)\makeappx.zip' -destination '\' -Force - displayName: Install packaging tools - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + parameters: + ob_restore_phase: false - pwsh: | $runtime = '$(Runtime)' @@ -168,94 +161,19 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS - displayName: 'Package ${{ parameters.buildArchitecture}}' + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - - task: onebranch.pipeline.signing@1 - displayName: Sign MSI packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.msi' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $version = '$(Version)' - - $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiLocation: $msiLocation" - - Set-Location $repoRoot - - $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation - Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" - Write-Host "##vso[task.setvariable variable=exePath]$exePath" - Write-Verbose -Verbose "exePath: $exePath" - - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: 'Make exe and expand package' - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe engine - inputs: - command: 'sign' - signing_profile: $(msft_3rd_party_cert_id) - files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $exePath = '$(exePath)' - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: Compress signed exe package - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.exe' - search_root: '$(Pipeline.Workspace)' + # Copy unsigned packages to output directory - pwsh: | $runtime = '$(Runtime)' Write-Verbose -Verbose "runtime = '$(Runtime)'" $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix', 'exe') } - 'x86' { @('msi', 'zip', 'msix', 'exe') } - 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'x64' { @('msi', 'zip', 'msix') } + 'x86' { @('msi', 'zip', 'msix') } + 'arm64' { @('msi', 'zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -268,34 +186,25 @@ jobs: if ($packageTypes -contains 'msi') { $msiPkgNameFilter = "powershell-*.msi" $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" - Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - - if ($packageTypes -contains 'exe') { - $msiPkgNameFilter = "powershell-*.exe" - $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" + Write-Verbose -Verbose "unsigned msiPkgPath: $msiPkgPath" Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { $zipPkgNameFilter = "powershell-*.zip" $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "zipPkgPath: $zipPkgPath" + Write-Verbose -Verbose "unsigned zipPkgPath: $zipPkgPath" Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'msix') { $msixPkgNameFilter = "powershell-*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msixPkgPath: $msixPkgPath" + Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } - displayName: Copy to output directory + displayName: Copy unsigned packages to output directory - pwsh: | Get-ChildItem -Path $(ob_outputDirectory) -Recurse - displayName: 'List artifacts' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + displayName: 'List unsigned artifacts' diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml new file mode 100644 index 00000000000..4a095ba7694 --- /dev/null +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -0,0 +1,216 @@ +parameters: + runtime: x64 + +jobs: +- job: sign_win_${{ parameters.runtime }} + displayName: Sign Windows Packages ${{ parameters.runtime }} + condition: succeeded() + pool: + type: windows + + variables: + - name: runCodesignValidationInjection + value: false + - name: ob_artifactBaseName + value: drop_windows_package_package_win_${{ parameters.runtime }} + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: Runtime + value: ${{ parameters.runtime }} + - group: msixTools + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + # Download unsigned packages from the build stage + - download: current + artifact: drop_windows_package_${{ parameters.runtime }} + displayName: Download unsigned packages + env: + ob_restore_phase: true + + - pwsh: | + Write-Verbose -Verbose "Downloaded unsigned artifacts:" + Get-ChildItem "$(Pipeline.Workspace)\drop_windows_package_${{ parameters.runtime }}" -Recurse + displayName: 'Capture Downloaded Unsigned Artifacts' + continueOnError: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/install-dotnet.yml@self + + # Import build.psm1 and bootstrap packaging dependencies (WiX Toolset) + - pwsh: | + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + Write-Verbose -Verbose "Modules imported successfully" + + # Install WiX Toolset for EXE package creation + $isArm64 = '$(Runtime)' -eq 'arm64' + $env:RUNTIME = '$(Runtime)' + Start-PSBootstrap -Scenario Package + displayName: 'Import modules and install WiX Toolset' + env: + ob_restore_phase: true + + # Sign MSI packages + - task: onebranch.pipeline.signing@1 + displayName: Sign MSI packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.msi' + search_root: '$(Pipeline.Workspace)' + + # Create EXE package from signed MSI (for x64, x86, arm64 only) + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $version = '$(Version)' + + $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "msiLocation: $msiLocation" + + Set-Location $repoRoot + + $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation + Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" + Write-Host "##vso[task.setvariable variable=exePath]$exePath" + Write-Verbose -Verbose "exePath: $exePath" + + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: 'Make exe and expand package' + + # Sign EXE engine + - task: onebranch.pipeline.signing@1 + displayName: Sign exe engine + inputs: + command: 'sign' + signing_profile: $(msft_3rd_party_cert_id) + files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Compress signed EXE engine back into package + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $exePath = '$(exePath)' + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose + Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: Compress signed exe package + + # Sign final EXE packages + - task: onebranch.pipeline.signing@1 + displayName: Sign exe packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Copy all signed packages to output directory + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $packageTypes = switch ($runtime) { + 'x64' { @('msi', 'zip', 'msix', 'exe') } + 'x86' { @('msi', 'zip', 'msix', 'exe') } + 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'fxdependent' { 'fxdependent' } + 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } + 'minsize' { 'min-size' } + } + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + if ($packageTypes -contains 'msi') { + $msiPkgNameFilter = "powershell-*.msi" + $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msiPkgPath: $msiPkgPath" + Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'exe') { + $exePkgNameFilter = "powershell-*.exe" + $exePkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $exePkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed exePkgPath: $exePkgPath" + Copy-Item -Path $exePkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { + $zipPkgNameFilter = "powershell-*.zip" + $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed zipPkgPath: $zipPkgPath" + Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'msix') { + $msixPkgNameFilter = "powershell-*.msix" + $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" + Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + displayName: Copy signed packages to output directory + + - pwsh: | + Get-ChildItem -Path $(ob_outputDirectory) -Recurse + displayName: 'List signed artifacts' + env: + ob_restore_phase: true diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index c8f12938d25..758298202a1 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -45,8 +45,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: @@ -132,8 +131,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose diff --git a/.pipelines/templates/release-checkout-pwsh-repo.yml b/.pipelines/templates/release-checkout-pwsh-repo.yml deleted file mode 100644 index 9a7486887a6..00000000000 --- a/.pipelines/templates/release-checkout-pwsh-repo.yml +++ /dev/null @@ -1,13 +0,0 @@ -steps: - - pwsh: | - Write-Verbose -Verbose "Deploy Box Product Pathway Does Not Support the `"checkout`" task" - if ($ENV:BUILD_REASON -eq 'PullRequest') { - throw 'We dont support PRs' - } - - Write-Verbose -Verbose $ENV:BUILD_SOURCEBRANCH - $branchName = $ENV:BUILD_SOURCEBRANCH -replace '^refs/heads/' - Write-Verbose -Verbose "Branch Name: $branchName" - git clone --depth 1 --branch $branchName https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/PowerShell '$(Pipeline.Workspace)/PowerShell' - cd $(Pipeline.Workspace)/PowerShell - displayName: Checkout Powershell Repository diff --git a/.pipelines/templates/release-download-packages.yml b/.pipelines/templates/release-download-packages.yml deleted file mode 100644 index 27a3098d1e1..00000000000 --- a/.pipelines/templates/release-download-packages.yml +++ /dev/null @@ -1,122 +0,0 @@ -jobs: -- job: upload_packages - displayName: Upload packages - condition: succeeded() - pool: - type: windows - variables: - - template: ./variable/release-shared.yml@self - parameters: - REPOROOT: $(Build.SourcesDirectory) - SBOM: true - - steps: - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture environment variables - - - download: PSPackagesOfficial - artifact: drop_linux_package_deb - displayName: Download linux deb packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_fxdependent - displayName: Download linux fx packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_arm64 - displayName: Download linux mariner packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_x64 - displayName: Download linux mariner x64 packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_minSize - displayName: Download linux min packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_rpm - displayName: Download linux rpm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar - displayName: Download linux tar packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine - displayName: Download linux tar alpine packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine_fxd - displayName: Download linux tar alpine fxd packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm - displayName: Download linux tar arm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm64 - displayName: Download linux tar arm 64 packages - - - download: PSPackagesOfficial - artifact: drop_nupkg_build_nupkg - displayName: Download nupkg packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_arm64 - displayName: Download windows arm64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependent - displayName: Download windows fxdependent packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependentWinDesktop - displayName: Download windows fxdependentWinDesktop packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_minsize - displayName: Download windows minsize packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x64 - displayName: Download windows x64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x86 - displayName: Download windows x86 packages - - - download: PSPackagesOfficial - artifact: macos-pkgs - displayName: Download macos tar packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_arm64 - displayName: Download macos arm packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_x64 - displayName: Download macos x64 packages - - - pwsh: | - Get-ChildItem '$(Pipeline.Workspace)/PSPackagesOfficial' -Recurse | Select-Object -ExpandProperty FullName - displayName: 'Capture downloads' - - - pwsh: | - $PackagesPath = '$(Pipeline.Workspace)/PSPackagesOfficial' - Write-Verbose -Verbose "Copying Github Release files in $PackagesPath to use in Release Pipeline" - - Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" - New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -notin '.msix', '.nupkg' } | - Where-Object { $_.Extension -in '.gz', '.pkg', '.msi', '.zip', '.deb', '.rpm', '.zip' } | - Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose - - Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" - New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -eq '.nupkg' } | - Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose - displayName: Copy downloads to Artifacts diff --git a/.pipelines/templates/release-install-pwsh.yml b/.pipelines/templates/release-install-pwsh.yml deleted file mode 100644 index 9d7080a7e78..00000000000 --- a/.pipelines/templates/release-install-pwsh.yml +++ /dev/null @@ -1,34 +0,0 @@ -steps: - - task: PowerShell@2 - inputs: - targetType: inline - script: | - $localInstallerPath = Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages" -Filter '*win-x64.msi' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $localInstallerPath) { - Write-Verbose -Verbose "Installer found at $localInstallerPath" - } else { - throw "Installer not found" - } - Write-Verbose -Verbose "Installing PowerShell via msiexec" - Start-Process -FilePath msiexec -ArgumentList "/package $localInstallerPath /quiet REGISTER_MANIFEST=1" -Wait -NoNewWindow - $pwshPath = Get-ChildItem -Directory -Path 'C:\Program Files\PowerShell\7*' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $pwshPath) { - Write-Verbose -Verbose "PowerShell installed at $pwshPath" - Write-Verbose -Verbose "Adding pwsh to env:PATH" - Write-Host "##vso[task.prependpath]$pwshPath" - } else { - throw "PowerShell not installed" - } - displayName: Install pwsh 7 - - - task: PowerShell@2 - inputs: - targetType: inline - pwsh: true - script: | - Write-Verbose -Verbose "Pwsh 7 Installed" - Write-Verbose -Verbose "env:Path: " - $env:PATH -split ';' | ForEach-Object { - Write-Verbose -Verbose $_ - } - displayName: Check pwsh 7 installation diff --git a/.pipelines/templates/set-reporoot.yml b/.pipelines/templates/set-reporoot.yml new file mode 100644 index 00000000000..af7983afaa1 --- /dev/null +++ b/.pipelines/templates/set-reporoot.yml @@ -0,0 +1,35 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + +steps: +- pwsh: | + $path = "./build.psm1" + if($env:REPOROOT){ + Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose + exit 0 + } + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ." -Verbose + $repoRoot = '.' + } + else{ + $path = "./PowerShell/build.psm1" + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ./PowerShell" -Verbose + $repoRoot = './PowerShell' + } + } + if($repoRoot) { + $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + } else { + Write-Verbose -Verbose "repo not found" + } + displayName: 'Set repo Root' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 4bac9e1a3ae..551297f3aaa 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - powershell: | $shouldSign = $true @@ -22,4 +27,4 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set SHOULD_SIGN Variable' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index b330a2eef10..20842de81cc 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -36,8 +36,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: /.pipelines/templates/release-SetReleaseTagandContainerName.yml@self From 1934b837a654ae5063190699d1953f3177713c67 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 10 Nov 2025 13:51:02 -0800 Subject: [PATCH 191/378] Move package validation to package pipeline (#26414) --- .pipelines/PowerShell-Packages-Official.yml | 6 ++++++ .pipelines/PowerShell-Release-Official.yml | 9 +-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 8e06be1cc64..afd82af4462 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -299,3 +299,9 @@ extends: dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self + + - stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index ca6b79335dd..868d61ebfd0 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -216,12 +216,6 @@ extends: arm64: 'yes' enableCredScan: false - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self - - stage: ManualValidation dependsOn: [] displayName: Manual Validation @@ -272,7 +266,6 @@ extends: dependsOn: - ManualValidation - ReleaseAutomation - - validatePackages - fxdpackages - gbltool - validateSdk @@ -365,7 +358,7 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: + dependsOn: - setReleaseTagAndChangelog - PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store From 8b7e493dd9e2e6d020509ec20c14cd3ba7208e14 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 10 Nov 2025 14:03:27 -0800 Subject: [PATCH 192/378] Add rebuild branch support with conditional MSIX signing (#26415) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../ServiceGroupRoot/Shell/Run/Run.ps1 | 6 ++- ...werShell-Coordinated_Packages-Official.yml | 13 ++++- .pipelines/PowerShell-Packages-Official.yml | 2 + .pipelines/templates/channelSelection.yml | 26 ++++++++-- .pipelines/templates/linux-package-build.yml | 18 ++++++- .pipelines/templates/mac-package-build.yml | 18 ++++++- .pipelines/templates/package-create-msix.yml | 48 ++++++++++++++----- .../templates/packaging/windows/package.yml | 18 ++++++- .pipelines/templates/rebuild-branch-check.yml | 17 +++++++ 9 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 .pipelines/templates/rebuild-branch-check.yml diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index 25a5686b33e..23f91c1bff2 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -354,6 +354,9 @@ try { $skipPublish = $metadataContent.SkipPublish $lts = $metadataContent.LTS + # Check if this is a rebuild version (e.g., 7.4.13-rebuild.5) + $isRebuild = $releaseVersion -match '-rebuild\.' + if ($releaseVersion.Contains('-')) { $channel = 'preview' $packageNames = @('powershell-preview') @@ -363,7 +366,8 @@ try { $packageNames = @('powershell') } - if ($lts) { + # Only add LTS package if not a rebuild branch + if ($lts -and -not $isRebuild) { $packageNames += @('powershell-lts') } diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index f36eeadf298..e4de1fe5c21 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -296,9 +296,20 @@ extends: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self - powershell: | $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" Get-Content "$(Build.StagingDirectory)\release.json" diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index afd82af4462..18ef7b2d14c 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -293,6 +293,8 @@ extends: dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} - stage: upload displayName: 'Upload' diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 3d1f445c559..9dd0f3fb216 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,13 +2,31 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + $releaseTag = '$(OutputReleaseTag.releaseTag)' + + # Rebuild branches should be treated as preview builds + # NOTE: The following regex is duplicated from rebuild-branch-check.yml. + # This duplication is necessary because channelSelection.yml does not call rebuild-branch-check.yml, + # and is used in contexts where that check may not have run. + # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + $LTS = $metadata.LTSRelease.Latest $Stable = $metadata.StableRelease.Latest - $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' + $isPreview = $releaseTag -match '-' - $IsLTS = [bool]$LTS - $IsStable = [bool]$Stable - $IsPreview = [bool]$isPreview + # If this is a rebuild branch, force preview mode and ignore LTS metadata + if ($isRebuildBranch) { + $IsLTS = $false + $IsStable = $false + $IsPreview = $true + Write-Verbose -Message "Rebuild branch detected, forcing Preview channel" -Verbose + } + else { + $IsLTS = [bool]$LTS + $IsStable = [bool]$Stable + $IsPreview = [bool]$isPreview + } $channelVars = @{ IsLTS = $IsLTS diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index b1c170eaed5..bcf332b3778 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -62,6 +62,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: ${{ parameters.unsignedDrop }} displayName: 'Download unsigned artifacts' @@ -139,7 +141,21 @@ jobs: } $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 1abb1722398..4e7040d4acc 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -60,6 +60,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: macosBinResults-${{ parameters.buildArchitecture }} @@ -103,7 +105,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index ed0217b2940..2b32aa4d0bb 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -1,3 +1,8 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + jobs: - job: CreateMSIXBundle displayName: Create .msixbundle file @@ -49,7 +54,7 @@ jobs: **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows x86 packages - + # Finds the makeappx tool on the machine with image: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - pwsh: | $cmd = Get-Command makeappx.exe -ErrorAction Ignore @@ -99,12 +104,13 @@ jobs: - task: onebranch.pipeline.signing@1 displayName: Sign MsixBundle + condition: eq('${{ parameters.OfficialBuild }}', 'true') inputs: command: 'sign' signing_profile: $(MSIXProfile) files_to_sign: '**/*.msixbundle' search_root: '$(BundleDir)' - + - pwsh: | $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" @@ -126,12 +132,12 @@ jobs: Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - + - template: channelSelection.yml@self - pwsh: | $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" @@ -161,11 +167,11 @@ jobs: $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } - else { + else { Write-Error "No valid channel detected" exit 1 } - + $config = $channelConfigs[$currentChannel] Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" @@ -181,7 +187,7 @@ jobs: # Create namespace manager for XML with default namespace $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) if ($appStoreNameElement) { $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) @@ -220,12 +226,30 @@ jobs: Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" # These variables are used in the next tasks to determine which ServiceEndpoint to use - Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" name: UpdateConfigs displayName: Update PDPs and SBConfig.json + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Preview)' condition: eq('$(PREVIEW)', 'true') @@ -260,14 +284,14 @@ jobs: $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { Write-Verbose -Verbose "Uploading StoreBroker Package files:" Write-Verbose -Verbose "JSON File: $jsonFile" Write-Verbose -Verbose "ZIP File: $zipFile" Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } + } else { Write-Error "Required files not found in $submissionPackageDir" diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 9a8be4b18fe..83cdf730b53 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -60,6 +60,8 @@ jobs: nativePathRoot: '$(Agent.TempDirectory)' ob_restore_phase: false + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts @@ -127,7 +129,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/rebuild-branch-check.yml b/.pipelines/templates/rebuild-branch-check.yml new file mode 100644 index 00000000000..a4b546a0dc6 --- /dev/null +++ b/.pipelines/templates/rebuild-branch-check.yml @@ -0,0 +1,17 @@ +# This template checks if the current branch is a rebuild branch +# and sets an output variable IsRebuildBranch that can be used by other templates +steps: +- pwsh: | + # Check if this is a rebuild branch (e.g., rebuild/v7.4.13-rebuild.5) + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + + $value = if ($isRebuildBranch) { 'true' } else { 'false' } + Write-Verbose -Message "IsRebuildBranch: $value" -Verbose + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected: $(Build.SourceBranch)" -Verbose + } + + Write-Host "##vso[task.setvariable variable=IsRebuildBranch;isOutput=true]$value" + name: RebuildBranchCheck + displayName: Check if Rebuild Branch From 21e5cf3f3f40ae373c4f3b91772d0669e32dde30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:22:18 -0800 Subject: [PATCH 193/378] Bump actions/dependency-review-action from 4.8.1 to 4.8.2 (#26421) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c3cc0624c45..dadc6fd4370 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1 + uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 From e069c1d198e01f8982e6263b1128b40538cceb37 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 11 Nov 2025 14:25:51 -0800 Subject: [PATCH 194/378] Update the WCF packages to the latest version that is compatible with v4.10.3 (#26406) --- .../Microsoft.PowerShell.SDK.csproj | 17 +- .../System.Management.Automation.csproj | 7 - tools/packaging/boms/windows.json | 350 +++++++++++++----- tools/packaging/packaging.psm1 | 32 +- 4 files changed, 299 insertions(+), 107 deletions(-) diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 31c48def673..57994fb98f7 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -23,19 +23,10 @@ - - - - - - - - - + + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index f3d73f72dd4..114a4c09aaf 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -34,17 +34,10 @@ - - - - - - - diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index d8857c71786..2999db1a180 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -89,11 +89,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "cs/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "cs/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -159,6 +154,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "cs\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "D3DCompiler_47_cor3.dll", "FileType": "NonProduct", @@ -201,11 +216,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "de/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "de/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -271,6 +281,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "de\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "DirectWriteForwarder.dll", "FileType": "NonProduct", @@ -316,11 +346,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "es/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "es/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -386,6 +411,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "es\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "fr/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -421,11 +466,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "fr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "fr/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -491,6 +531,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "fr\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "getfilesiginforedist.dll", "FileType": "NonProduct", @@ -551,11 +611,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "it/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "it/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -621,6 +676,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "it\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "ja/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -656,11 +731,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ja/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ja/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -726,6 +796,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ja\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Json.More.dll", "FileType": "NonProduct", @@ -776,11 +866,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ko/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ko/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -846,6 +931,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ko\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Markdig.Signed.dll", "FileType": "NonProduct", @@ -1111,11 +1216,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "Modules/ThreadJob/*.psd1", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", "FileType": "NonProduct", @@ -1156,16 +1256,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "Modules\\ThreadJob\\.signature.p7s", - "FileType": "NonProduct", - "Architecture": null - }, - { - "Pattern": "Modules\\ThreadJob\\ThreadJob.psm1", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "mscordaccore_*.dll", "FileType": "NonProduct", @@ -1246,11 +1336,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "pl/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "pl/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -1316,6 +1401,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "pl\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "powershell.config.json", "FileType": "NonProduct", @@ -1466,11 +1571,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "pt-BR/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "pt-BR/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -1536,6 +1636,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "pt-BR\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "pwrshplugin.dll", "FileType": "NonProduct", @@ -2431,11 +2551,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ru/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ru/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -2501,6 +2616,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ru\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Schemas/PSMaml/base.xsd", "FileType": "NonProduct", @@ -3316,11 +3451,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "System.Private.ServiceModel.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "System.Private.Uri.dll", "FileType": "NonProduct", @@ -3606,6 +3736,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "System.ServiceModel.NetFramingBase.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "System.ServiceModel.NetTcp.dll", "FileType": "NonProduct", @@ -3901,11 +4036,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "tr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "tr/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -3971,6 +4101,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "tr\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "UIAutomationClient.dll", "FileType": "NonProduct", @@ -4046,11 +4196,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "zh-Hans/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "zh-Hans/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -4116,6 +4261,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "zh-Hans\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -4151,11 +4316,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "zh-Hant/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "zh-Hant/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -4221,6 +4381,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "zh-Hant\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "_manifest/spdx_2.2/manifest.spdx.json", "FileType": "Product", diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index e229aa493ae..6966ececaa4 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -284,6 +284,18 @@ function Start-PSPackage { $createdSpdxPathSha = New-Item -Path $manifestSpdxPathSha -Force Write-Verbose -Verbose "Created manifest.spdx.json.sha256 file: $createdSpdxPathSha" } + + $bsiJsonPath = (Join-Path -Path $Source "_manifest\spdx_2.2\bsi.json") + if (-not (Test-Path -Path $bsiJsonPath)) { + $createdBsiJsonPath = New-Item -Path $bsiJsonPath -Force + Write-Verbose -Verbose "Created bsi.json file: $createdBsiJsonPath" + } + + $manifestCatPath = (Join-Path -Path $Source "_manifest\spdx_2.2\manifest.cat") + if (-not (Test-Path -Path $manifestCatPath)) { + $createdCatPath = New-Item -Path $manifestCatPath -Force + Write-Verbose -Verbose "Created manifest.cat file: $createdCatPath" + } } # If building a symbols package, we add a zip of the parent to publish @@ -5521,8 +5533,24 @@ function Send-AzdoFile { Copy-Item -Path $Path -Destination $logFile } - Write-Host "##vso[artifact.upload containerfolder=$newName;artifactname=$newName]$logFile" - Write-Verbose "Log file captured as $newName" -Verbose + Write-Verbose "Capture the log file as '$newName'" -Verbose + if($env:TF_BUILD) { + ## In Azure DevOps + Write-Host "##vso[artifact.upload containerfolder=$newName;artifactname=$newName]$logFile" + } elseif ($env:GITHUB_WORKFLOW -and $env:SYSTEM_ARTIFACTSDIRECTORY) { + ## In GitHub Actions + $destinationPath = $env:SYSTEM_ARTIFACTSDIRECTORY + Write-Verbose "Upload '$logFile' to '$destinationPath' in GitHub Action" -Verbose + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $logFile -Destination $destinationPath -Force -Verbose + } else { + Write-Warning "This environment is neither Azure Devops nor GitHub Actions. Cannot capture the log file in this environment." + } } # Class used for serializing and deserialing a BOM into Json From 2330c80875b1c5db7ebbd283bc52e6fd7d724c1f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 11 Nov 2025 14:26:46 -0800 Subject: [PATCH 195/378] Update `PSResourceGet` package version to `1.2.0-preview4` (#26404) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 6cec561a07a..d2a49e26d2a 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From d412f040b839c10d04b8b3b015eec0d06f12a904 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 12 Nov 2025 08:59:57 -0800 Subject: [PATCH 196/378] Fix template path for rebuild branch check in package.yml (#26425) --- .pipelines/templates/packaging/windows/package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 83cdf730b53..03673d61c7b 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -60,7 +60,7 @@ jobs: nativePathRoot: '$(Agent.TempDirectory)' ob_restore_phase: false - - template: rebuild-branch-check.yml@self + - template: /.pipelines/templates/rebuild-branch-check.yml@self - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release From 1fd3ea835d51f51f7f0b060b34f575bad16f99e0 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 12 Nov 2025 09:35:41 -0800 Subject: [PATCH 197/378] Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26427) --- ...onebranch-condition-syntax.instructions.md | 223 ++++++++++++++++++ .pipelines/templates/package-create-msix.yml | 4 +- 2 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 .github/instructions/onebranch-condition-syntax.instructions.md diff --git a/.github/instructions/onebranch-condition-syntax.instructions.md b/.github/instructions/onebranch-condition-syntax.instructions.md new file mode 100644 index 00000000000..19bf331d9c3 --- /dev/null +++ b/.github/instructions/onebranch-condition-syntax.instructions.md @@ -0,0 +1,223 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Pipeline Condition Syntax + +## Overview +Azure Pipelines (OneBranch) uses specific syntax for referencing variables and parameters in condition expressions. Using the wrong syntax will cause conditions to fail silently or behave unexpectedly. + +## Variable Reference Patterns + +### In Condition Expressions + +**✅ Correct Pattern:** +```yaml +condition: eq(variables['VariableName'], 'value') +condition: or(eq(variables['VAR1'], 'true'), eq(variables['VAR2'], 'true')) +condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +**❌ Incorrect Patterns:** +```yaml +# Don't use $(VAR) string expansion in conditions +condition: eq('$(VariableName)', 'value') + +# Don't use direct variable references +condition: eq($VariableName, 'value') +``` + +### In Script Content (pwsh, bash, etc.) + +**✅ Correct Pattern:** +```yaml +- pwsh: | + $value = '$(VariableName)' + Write-Host "Value: $(VariableName)" +``` + +### In Input Fields + +**✅ Correct Pattern:** +```yaml +inputs: + serviceEndpoint: '$(ServiceEndpoint)' + sbConfigPath: '$(SBConfigPath)' +``` + +## Parameter References + +### Template Parameters (Compile-Time) + +**✅ Correct Pattern:** +```yaml +parameters: + - name: OfficialBuild + type: boolean + default: false + +steps: + - task: SomeTask@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') +``` + +Note: Parameters use `${{ parameters.Name }}` because they're evaluated at template compile-time. + +### Runtime Variables (Execution-Time) + +**✅ Correct Pattern:** +```yaml +steps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=MyVar]somevalue" + displayName: Set Variable + + - task: SomeTask@1 + condition: eq(variables['MyVar'], 'somevalue') +``` + +## Common Scenarios + +### Scenario 1: Check if Variable Equals Value + +```yaml +- task: DoSomething@1 + condition: eq(variables['PREVIEW'], 'true') +``` + +### Scenario 2: Multiple Variable Conditions (OR) + +```yaml +- task: DoSomething@1 + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) +``` + +### Scenario 3: Multiple Variable Conditions (AND) + +```yaml +- task: DoSomething@1 + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +### Scenario 4: Complex Conditions + +```yaml +- task: DoSomething@1 + condition: and( + succeededOrFailed(), + ne(variables['UseAzDevOpsFeed'], ''), + eq(variables['Build.SourceBranch'], 'refs/heads/master') + ) +``` + +### Scenario 5: Built-in Variables + +```yaml +- task: CodeQL3000Init@0 + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + +- step: finalize + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') +``` + +### Scenario 6: Parameter vs Variable + +```yaml +parameters: + - name: OfficialBuild + type: boolean + +steps: + # Parameter condition (compile-time) + - task: SignFiles@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') + + # Variable condition (runtime) + - task: PublishArtifact@1 + condition: eq(variables['PUBLISH_ENABLED'], 'true') +``` + +## Why This Matters + +**String Expansion `$(VAR)` in Conditions:** +- When you use `'$(VAR)'` in a condition, Azure Pipelines attempts to expand it as a string +- If the variable is undefined or empty, it becomes an empty string `''` +- The condition `eq('', 'true')` will always be false +- This makes debugging difficult because there's no error message + +**Variables Array Syntax `variables['VAR']`:** +- This is the proper way to reference runtime variables in conditions +- Azure Pipelines correctly evaluates the variable's value +- Undefined variables are handled properly by the condition evaluator +- This is the standard pattern used throughout Azure Pipelines + +## Reference Examples + +Working examples can be found in: +- `.pipelines/templates/linux.yml` - Build.SourceBranch conditions +- `.pipelines/templates/windows-hosted-build.yml` - Architecture conditions +- `.pipelines/templates/compliance/apiscan.yml` - CODEQL_ENABLED conditions +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Complex AND/OR conditions + +## Quick Reference Table + +| Context | Syntax | Example | +|---------|--------|---------| +| Condition expression | `variables['Name']` | `condition: eq(variables['PREVIEW'], 'true')` | +| Script content | `$(Name)` | `pwsh: Write-Host "$(PREVIEW)"` | +| Task input | `$(Name)` | `inputs: path: '$(Build.SourcesDirectory)'` | +| Template parameter | `${{ parameters.Name }}` | `condition: eq('${{ parameters.Official }}', 'true')` | + +## Troubleshooting + +### Condition Always False +If your condition is always evaluating to false: +1. Check if you're using `'$(VAR)'` instead of `variables['VAR']` +2. Verify the variable is actually set (add a debug step to print the variable) +3. Check the variable value is exactly what you expect (case-sensitive) + +### Variable Not Found +If you get errors about variables not being found: +1. Ensure the variable is set before the condition is evaluated +2. Check that the variable name is spelled correctly +3. Verify the variable is in scope (job vs. stage vs. pipeline level) + +## Best Practices + +1. **Always use `variables['Name']` in conditions** - This is the correct Azure Pipelines pattern +2. **Use `$(Name)` for string expansion** in scripts and inputs +3. **Use `${{ parameters.Name }}` for template parameters** (compile-time) +4. **Add debug steps** to verify variable values when troubleshooting conditions +5. **Follow existing patterns** in the repository - grep for `condition:` to see examples + +## Common Mistakes + +❌ **Mistake 1: String expansion in condition** +```yaml +condition: eq('$(PREVIEW)', 'true') # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq(variables['PREVIEW'], 'true') # CORRECT +``` + +❌ **Mistake 2: Missing quotes around parameter** +```yaml +condition: eq(${{ parameters.Official }}, true) # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq('${{ parameters.Official }}', 'true') # CORRECT +``` + +❌ **Mistake 3: Mixing syntax** +```yaml +condition: or(eq('$(STABLE)', 'true'), eq(variables['LTS'], 'true')) # INCONSISTENT +``` + +✅ **Fix:** +```yaml +condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) # CORRECT +``` diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 2b32aa4d0bb..255915ab02c 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -252,7 +252,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Preview)' - condition: eq('$(PREVIEW)', 'true') + condition: eq(variables['PREVIEW'], 'true') inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' @@ -264,7 +264,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' From 4aa65a77be93911072e015f2a52656786c8f54bf Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 12 Nov 2025 09:36:50 -0800 Subject: [PATCH 198/378] Update the macos package name for preview releases to match the previous pattern (#26429) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../templates/release-validate-packagenames.yml | 2 +- test/packaging/macos/package-validation.tests.ps1 | 11 ++++++----- tools/packaging/packaging.psm1 | 9 +++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index c717b50f289..6344418cd8f 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -82,7 +82,7 @@ jobs: - pwsh: | $message = @() Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.pkg | ForEach-Object { - if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx(\.10\.12)?\-(x64|arm64)\.pkg') + if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance diff --git a/test/packaging/macos/package-validation.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 index 02b09fbb078..945ffea6f7a 100644 --- a/test/packaging/macos/package-validation.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -82,12 +82,13 @@ Describe "Verify macOS Package" { $script:package | Should -Not -BeNullOrEmpty # Regex pattern for valid macOS PKG package names. + # This pattern matches the validation used in release-validate-packagenames.yml # Valid examples: - # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) - # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) - # - powershell-preview-7.6.0-preview.6-osx-x64.pkg - # - powershell-lts-7.4.13-osx-arm64.pkg - $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' + # - powershell-7.4.13-osx-x64.pkg (Stable release) + # - powershell-7.6.0-preview.6-osx-x64.pkg (Preview version string) + # - powershell-7.4.13-rebuild.5-osx-arm64.pkg (Rebuild version) + # - powershell-lts-7.4.13-osx-arm64.pkg (LTS package) + $pkgPackageNamePattern = '^powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg$' $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 6966ececaa4..baeb12e360a 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1159,15 +1159,12 @@ function New-UnixPackage { } # Determine if the version is a preview version - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - - # Preview versions have preview in the name + # Only LTS packages get a prefix in the name + # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) + # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) $Name = if($LTS) { "powershell-lts" } - elseif ($IsPreview) { - "powershell-preview" - } else { "powershell" } From 5715d33398d97bed2ccf9e6526faea3db1626b88 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 13 Nov 2025 09:56:09 -0800 Subject: [PATCH 199/378] DSC v3 resource for Powershell Profile (#26157) --- .github/actions/test/nix/action.yml | 42 ++++ .github/actions/test/windows/action.yml | 20 ++ dsc/pwsh.profile.dsc.resource.json | 126 +++++++++++ dsc/pwsh.profile.resource.ps1 | 179 +++++++++++++++ experimental-feature-linux.json | 1 + experimental-feature-windows.json | 1 + .../ExperimentalFeature.cs | 5 + src/powershell-unix/powershell-unix.csproj | 4 + .../powershell-win-core.csproj | 4 + .../dsc/dsc.profileresource.Tests.ps1 | 204 ++++++++++++++++++ .../dsc/psprofile_alluser_allhost.dsc.yaml | 9 + .../psprofile_allusers_currenthost.dsc.yaml | 9 + .../psprofile_currentuser_allhosts.dsc.yaml | 9 + ...psprofile_currentuser_currenthost.dsc.yaml | 9 + ..._currentuser_currenthost_emptycontent.yaml | 9 + test/powershell/dsc/psprofile_export.dsc.yaml | 5 + tools/packaging/boms/linux.json | 10 + tools/packaging/boms/mac.json | 10 + tools/packaging/boms/windows.json | 10 + 19 files changed, 666 insertions(+) create mode 100644 dsc/pwsh.profile.dsc.resource.json create mode 100644 dsc/pwsh.profile.resource.ps1 create mode 100644 test/powershell/dsc/dsc.profileresource.Tests.ps1 create mode 100644 test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml create mode 100644 test/powershell/dsc/psprofile_export.dsc.yaml diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index ef943bfce78..b8c1778974c 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -43,6 +43,48 @@ runs: with: global-json-file: ./global.json + - name: Set Package Name by Platform + id: set_package_name + shell: pwsh + run: |- + Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 + $platform = $env:RUNNER_OS + Write-Host "Runner platform: $platform" + if ($platform -eq 'Linux') { + $packageName = 'DSC-*-x86_64-linux.tar.gz' + } elseif ($platform -eq 'macOS') { + $packageName = 'DSC-*-x86_64-apple-darwin.tar.gz' + } else { + throw "Unsupported platform: $platform" + } + + Set-GWVariable -Name "DSC_PACKAGE_NAME" -Value $packageName + + - name: Get Latest DSC Package Version + shell: pwsh + run: |- + Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 + $latestVersion = $latestRelease.tag_name.TrimStart("v") + Write-Host "Latest DSC Version: $latestVersion" + + $packageName = "$env:DSC_PACKAGE_NAME" + + Write-Host "Package Name: $packageName" + + $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "*$packageName*" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url + Write-Host "Download URL: $downloadUrl" + + $tempPath = Get-GWTempPath + + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose + New-Item -ItemType Directory -Path "$tempPath/DSC" -Force -Verbose + tar xvf "$tempPath/DSC.tar.gz" -C "$tempPath/DSC" + $dscRoot = "$tempPath/DSC" + Write-Host "DSC Root: $dscRoot" + Set-GWVariable -Name "DSC_ROOT" -Value $dscRoot + - name: Bootstrap shell: pwsh run: |- diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 3b3ce0cafe8..923e9606e59 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -43,6 +43,26 @@ runs: with: global-json-file: .\global.json + - name: Get Latest DSC Package Version + shell: pwsh + run: |- + Import-Module .\.github\workflows\GHWorkflowHelper\GHWorkflowHelper.psm1 + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 + $latestVersion = $latestRelease.tag_name.TrimStart("v") + Write-Host "Latest DSC Version: $latestVersion" + + $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "DSC-*-x86_64-pc-windows-msvc.zip" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url + Write-Host "Download URL: $downloadUrl" + $tempPath = Get-GWTempPath + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" + + $null = New-Item -ItemType Directory -Path "$tempPath\DSC" -Force + Expand-Archive -Path "$tempPath\DSC.zip" -DestinationPath "$tempPath\DSC" -Force + $dscRoot = "$tempPath\DSC" + Write-Host "DSC Root: $dscRoot" + Set-GWVariable -Name "DSC_ROOT" -Value $dscRoot + - name: Bootstrap shell: powershell run: |- diff --git a/dsc/pwsh.profile.dsc.resource.json b/dsc/pwsh.profile.dsc.resource.json new file mode 100644 index 00000000000..cd18e94eec6 --- /dev/null +++ b/dsc/pwsh.profile.dsc.resource.json @@ -0,0 +1,126 @@ +{ + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "description": "Manage PowerShell profiles.", + "tags": [ + "Linux", + "Windows", + "macOS", + "PowerShell" + ], + "type": "Microsoft.PowerShell/Profile", + "version": "0.1.0", + "get": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "get" + ], + "input": "stdin" + }, + "set": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "set" + ], + "input": "stdin" + }, + "export": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "export" + ], + "input": "stdin" + }, + "exitCodes": { + "0": "Success", + "1": "Error", + "2": "Input not supported for export operation" + }, + "schema": { + "embedded": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Profile", + "description": "Manage PowerShell profiles.", + "type": "object", + "unevaluatedProperties": false, + "required": [ + "profileType" + ], + "properties": { + "profileType": { + "type": "string", + "title": "Profile Type", + "description": "Defines which profile to manage. Valid values are: 'AllUsersCurrentHost', 'AllUsersAllHosts', 'CurrentUserAllHosts', and 'CurrentUserCurrentHost'.", + "enum": [ + "AllUsersCurrentHost", + "AllUsersAllHosts", + "CurrentUserAllHosts", + "CurrentUserCurrentHost" + ] + }, + "profilePath": { + "title": "Profile Path", + "description": "The full path to the profile file.", + "type": "string", + "readOnly": true + }, + "content": { + "title": "Content", + "description": "Defines the content of the profile. If you don't specify this property, the resource doesn't manage the file contents. If you specify this property as an empty string, the resource removes all content from the file. If you specify this property as a non-empty string, the resource sets the file contents to the specified string. The resources retains newlines from this property without any modification.", + "type": "string" + }, + "_exist": { + "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json" + }, + "_name": { + "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json" + } + }, + "$defs": { + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json", + "title": "Instance should exist", + "description": "Indicates whether the DSC resource instance should exist.", + "type": "boolean", + "default": true, + "enum": [ + false, + true + ] + }, + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json", + "title": "Exported instance name", + "description": "Returns a generated name for the resource instance from an export operation.", + "readOnly": true, + "type": "string" + } + } + } + } +} diff --git a/dsc/pwsh.profile.resource.ps1 b/dsc/pwsh.profile.resource.ps1 new file mode 100644 index 00000000000..ad9cfa4a63a --- /dev/null +++ b/dsc/pwsh.profile.resource.ps1 @@ -0,0 +1,179 @@ +## Copyright (c) Microsoft Corporation. All rights reserved. +## Licensed under the MIT License. + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [ValidateSet('get', 'set', 'export')] + [string]$Operation, + [Parameter(ValueFromPipeline)] + [string[]]$UserInput +) + +Begin { + enum ProfileType { + AllUsersCurrentHost + AllUsersAllHosts + CurrentUserAllHosts + CurrentUserCurrentHost + } + + function New-PwshResource { + param( + [Parameter(Mandatory = $true)] + [ProfileType] $ProfileType, + + [Parameter(ParameterSetName = 'WithContent')] + [string] $Content, + + [Parameter(ParameterSetName = 'WithContent')] + [bool] $Exist + ) + + # Create the PSCustomObject with properties + $resource = [PSCustomObject]@{ + profileType = $ProfileType + content = $null + profilePath = GetProfilePath -profileType $ProfileType + _exist = $false + } + + # Add ToJson method + $resource | Add-Member -MemberType ScriptMethod -Name 'ToJson' -Value { + return ([ordered] @{ + profileType = $this.profileType + content = $this.content + profilePath = $this.profilePath + _exist = $this._exist + }) | ConvertTo-Json -Compress -EnumsAsStrings + } + + # Constructor logic - if Content and Exist parameters are provided (WithContent parameter set) + if ($PSCmdlet.ParameterSetName -eq 'WithContent') { + $resource.content = $Content + $resource._exist = $Exist + } else { + # Default constructor logic - read from file system + $fileExists = Test-Path $resource.profilePath + if ($fileExists) { + $resource.content = Get-Content -Path $resource.profilePath + } else { + $resource.content = $null + } + $resource._exist = $fileExists + } + + return $resource + } + + function GetProfilePath { + param ( + [ProfileType] $profileType + ) + + $path = switch ($profileType) { + 'AllUsersCurrentHost' { $PROFILE.AllUsersCurrentHost } + 'AllUsersAllHosts' { $PROFILE.AllUsersAllHosts } + 'CurrentUserAllHosts' { $PROFILE.CurrentUserAllHosts } + 'CurrentUserCurrentHost' { $PROFILE.CurrentUserCurrentHost } + } + + return $path + } + + function ExportOperation { + $allUserCurrentHost = New-PwshResource -ProfileType 'AllUsersCurrentHost' + $allUsersAllHost = New-PwshResource -ProfileType 'AllUsersAllHosts' + $currentUserAllHost = New-PwshResource -ProfileType 'CurrentUserAllHosts' + $currentUserCurrentHost = New-PwshResource -ProfileType 'CurrentUserCurrentHost' + + # Cannot use the ToJson() method here as we are adding a note property + $allUserCurrentHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'AllUsersCurrentHost' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $allUsersAllHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'AllUsersAllHosts' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $currentUserAllHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'CurrentUserAllHosts' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $currentUserCurrentHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'CurrentUserCurrentHost' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + } + + function GetOperation { + param ( + [Parameter(Mandatory = $true)] + $InputResource, + [Parameter()] + [switch] $AsJson + ) + + $profilePath = GetProfilePath -profileType $InputResource.profileType.ToString() + + $actualState = New-PwshResource -ProfileType $InputResource.profileType + + $actualState.profilePath = $profilePath + + $exists = Test-Path $profilePath + + if ($InputResource._exist -and $exists) { + $content = Get-Content -Path $profilePath + $actualState.Content = $content + } elseif ($InputResource._exist -and -not $exists) { + $actualState.Content = $null + $actualState._exist = $false + } elseif (-not $InputResource._exist -and $exists) { + $actualState.Content = Get-Content -Path $profilePath + $actualState._exist = $true + } else { + $actualState.Content = $null + $actualState._exist = $false + } + + if ($AsJson) { + return $actualState.ToJson() + } else { + return $actualState + } + } + + function SetOperation { + param ( + $InputResource + ) + + $actualState = GetOperation -InputResource $InputResource + + if ($InputResource._exist) { + if (-not $actualState._exist) { + $null = New-Item -Path $actualState.profilePath -ItemType File -Force + } + + if ($null -ne $InputResource.content) { + Set-Content -Path $actualState.profilePath -Value $InputResource.content + } + } elseif ($actualState._exist) { + Remove-Item -Path $actualState.profilePath -Force + } + } +} +End { + $inputJson = $input | ConvertFrom-Json + + if ($inputJson) { + $InputResource = New-PwshResource -ProfileType $inputJson.profileType -Content $inputJson.content -Exist $inputJson._exist + } + + switch ($Operation) { + 'get' { + GetOperation -InputResource $InputResource -AsJson + } + 'set' { + SetOperation -InputResource $InputResource + } + 'export' { + if ($inputJson) { + Write-Error "Input not supported for export operation" + exit 2 + } + + ExportOperation + } + } + + exit 0 +} diff --git a/experimental-feature-linux.json b/experimental-feature-linux.json index ca5b49878a4..31f7b965a5b 100644 --- a/experimental-feature-linux.json +++ b/experimental-feature-linux.json @@ -2,6 +2,7 @@ "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", + "PSProfileDSCResource", "PSSerializeJSONLongEnumAsNumber", "PSRedirectToVariable", "PSSubsystemPluginModel" diff --git a/experimental-feature-windows.json b/experimental-feature-windows.json index ca5b49878a4..31f7b965a5b 100644 --- a/experimental-feature-windows.json +++ b/experimental-feature-windows.json @@ -2,6 +2,7 @@ "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", + "PSProfileDSCResource", "PSSerializeJSONLongEnumAsNumber", "PSRedirectToVariable", "PSSubsystemPluginModel" diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 1c17a22ae9a..7e17ec43137 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -21,6 +21,7 @@ public class ExperimentalFeature internal const string EngineSource = "PSEngine"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); + internal const string PSProfileDSCResource = "PSProfileDSCResource"; #endregion @@ -109,6 +110,10 @@ static ExperimentalFeature() new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." + ), + new ExperimentalFeature( + name: PSProfileDSCResource, + description: "DSC v3 resources for managing PowerShell profile." ) }; diff --git a/src/powershell-unix/powershell-unix.csproj b/src/powershell-unix/powershell-unix.csproj index 802acf05e3a..20c61247d24 100644 --- a/src/powershell-unix/powershell-unix.csproj +++ b/src/powershell-unix/powershell-unix.csproj @@ -37,6 +37,10 @@ PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest + diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj index 5368518dd3c..e6efeac10f0 100644 --- a/src/powershell-win-core/powershell-win-core.csproj +++ b/src/powershell-win-core/powershell-win-core.csproj @@ -29,6 +29,10 @@ PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest + PreserveNewest PreserveNewest diff --git a/test/powershell/dsc/dsc.profileresource.Tests.ps1 b/test/powershell/dsc/dsc.profileresource.Tests.ps1 new file mode 100644 index 00000000000..f361e67ea8e --- /dev/null +++ b/test/powershell/dsc/dsc.profileresource.Tests.ps1 @@ -0,0 +1,204 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { + BeforeAll { + $DSC_ROOT = $env:DSC_ROOT + + if (-not (Test-Path -Path $DSC_ROOT)) { + throw "DSC_ROOT environment variable is not set or path does not exist." + } + + Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose + + $originalPath = $env:PATH + + $pathSeparator = [System.IO.Path]::PathSeparator + $env:PATH += "$pathSeparator$DSC_ROOT" + $env:PATH += "$pathSeparator$PSHome" + + Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose + + # Ensure DSC v3 is available + if (-not (Get-Command -name dsc -CommandType Application -ErrorAction SilentlyContinue)) { + Get-ChildItem $DSC_ROOT -Recurse 'dsc' | ForEach-Object { + Write-Verbose "Found DSC executable at $($_.FullName)" -Verbose + } + throw "DSC v3 is not installed" + } + + $dscExe = Get-Command -name dsc -CommandType Application | Select-Object -First 1 + + $testProfileContent = "# Test profile content currentuser currenthost" + $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost + Copy-Item -Path $testProfilePathCurrentUserCurrentHost -Destination "$TestDrive/currentuser-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathCurrentUserCurrentHost -Value $testProfileContent -Force -ItemType File + + $testProfileContent = "# Test profile content currentuser allhosts" + $testProfilePathCurrentUserAllHosts = $PROFILE.CurrentUserAllHosts + Copy-Item -Path $testProfilePathCurrentUserAllHosts -Destination "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathCurrentUserAllHosts -Value $testProfileContent -Force -ItemType File + } + AfterAll { + # Restore original profile + $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost + if (Test-Path "$TestDrive/currentuser-currenthost-profile.bak") { + Copy-Item -Path "$TestDrive/currentuser-currenthost-profile.bak" -Destination $testProfilePathCurrentUserCurrentHost -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathCurrentUserCurrentHost -Force -ErrorAction SilentlyContinue + } + + $testProfilePathCurrentUserAllHosts = $PROFILE.CurrentUserAllHosts + if (Test-Path "$TestDrive/currentuser-allhosts-profile.bak") { + Copy-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Destination $testProfilePathCurrentUserAllHosts -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathCurrentUserAllHosts -Force -ErrorAction SilentlyContinue + } + + $env:PATH = $originalPath + Remove-Item -Path "$TestDrive/currentuser-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + Remove-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + } + + It 'DSC resource is located at $PSHome' { + $resourceFile = Join-Path -Path $PSHome -ChildPath 'pwsh.profile.resource.ps1' + $resourceFile | Should -Exist + + $resourceManifest = Join-Path -Path $PSHome -ChildPath 'pwsh.profile.dsc.resource.json' + $resourceManifest | Should -Exist + } + + It 'DSC resource can be found' { + (& $dscExe resource list -o json | ConvertFrom-Json | Select-Object -Property type).type | Should -Contain 'Microsoft.PowerShell/Profile' + } + + It 'DSC resource can set current user current host profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get current user current host profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_currentuser_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can set content as empty for current user current host profile' -Pending { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_currenthost_emptycontent.dsc.yaml -o json) | ConvertFrom-Json + $setOutput.results.result.afterState.content | Should -BeExactly '' + } + + It 'DSC resource can set current user all hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_allhosts.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get current user all hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_currentuser_allhosts.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can export all profiles' { + $exportOutput = (& $dscExe config export --file $PSScriptRoot/psprofile_export.dsc.yaml -o json) | ConvertFrom-Json + + $exportOutput.resources | Should -HaveCount 4 + + $exportOutput.resources | ForEach-Object { + $_.type | Should -Be 'Microsoft.PowerShell/Profile' + $_.name | Should -BeIn @('AllUsersCurrentHost', 'AllUsersAllHosts', 'CurrentUserCurrentHost', 'CurrentUserAllHosts') + } + } +} + +Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdminOnWindows', 'RequireSudoOnUnix' { + BeforeAll { + $DSC_ROOT = $env:DSC_ROOT + + if (-not (Test-Path -Path $DSC_ROOT)) { + throw "DSC_ROOT environment variable is not set or path does not exist." + } + + Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose + $pathSeparator = [System.IO.Path]::PathSeparator + + $env:PATH += "$pathSeparator$DSC_ROOT" + + $env:PATH += "$pathSeparator$PSHome" + + Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose + + # Ensure DSC v3 is available + if (-not (Get-Command -name dsc -CommandType Application -ErrorAction SilentlyContinue)) { + Get-ChildItem $DSC_ROOT -Recurse 'dsc' | ForEach-Object { + Write-Verbose "Found DSC executable at $($_.FullName)" -Verbose + } + throw "DSC v3 is not installed" + } + + $dscExe = Get-Command -name dsc -CommandType Application | Select-Object -First 1 + + $testProfileContent = "# Test profile content allusers currenthost" + $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost + Copy-Item -Path $testProfilePathAllUsersCurrentHost -Destination "$TestDrive/allusers-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathAllUsersCurrentHost -Value $testProfileContent -Force -ItemType File + + $testProfileContent = "# Test profile content allusers allhosts" + $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts + Copy-Item -Path $testProfilePathAllUsersAllHosts -Destination "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathAllUsersAllHosts -Value $testProfileContent -Force -ItemType File + + $originalPath = $env:PATH + $env:PATH += "$pathSeparator$PSHome" + } + AfterAll { + $env:PATH = $originalPath + + $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost + if (Test-Path "$TestDrive/allusers-currenthost-profile.bak") { + Copy-Item -Path "$TestDrive/allusers-currenthost-profile.bak" -Destination $testProfilePathAllUsersCurrentHost -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathAllUsersCurrentHost -Force -ErrorAction SilentlyContinue + } + + $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts + if (Test-Path "$TestDrive/allusers-allhosts-profile.bak") { + Copy-Item -Path "$TestDrive/allusers-allhosts-profile.bak" -Destination $testProfilePathAllUsersAllHosts -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathAllUsersAllHosts -Force -ErrorAction SilentlyContinue + } + + Remove-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + Remove-Item -Path "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + } + + It 'DSC resource can set all users all hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_alluser_allhost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get all users all hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_alluser_allhost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can set all users current hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_allusers_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get all users current hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_allusers_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } +} diff --git a/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml b/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml new file mode 100644 index 00000000000..356119826c3 --- /dev/null +++ b/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: AllUsersAllHosts + content: "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml b/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml new file mode 100644 index 00000000000..bc51f0a4392 --- /dev/null +++ b/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: AllUsersCurrentHost + content: "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml b/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml new file mode 100644 index 00000000000..8ed8d98c3ab --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserAllHosts + content: "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml b/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml new file mode 100644 index 00000000000..5a42c28eb96 --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserCurrentHost + content: "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml b/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml new file mode 100644 index 00000000000..76439387d2e --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserCurrentHost + content: '' + _exist: true diff --git a/test/powershell/dsc/psprofile_export.dsc.yaml b/test/powershell/dsc/psprofile_export.dsc.yaml new file mode 100644 index 00000000000..cf7881b5df8 --- /dev/null +++ b/test/powershell/dsc/psprofile_export.dsc.yaml @@ -0,0 +1,5 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile diff --git a/tools/packaging/boms/linux.json b/tools/packaging/boms/linux.json index 9f5f886a4ca..db29e47a290 100644 --- a/tools/packaging/boms/linux.json +++ b/tools/packaging/boms/linux.json @@ -2442,5 +2442,15 @@ { "Pattern": "System.Management.Automation.dll", "FileType": "Product" + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] diff --git a/tools/packaging/boms/mac.json b/tools/packaging/boms/mac.json index a4b5bc2bffb..af4fcb0c967 100644 --- a/tools/packaging/boms/mac.json +++ b/tools/packaging/boms/mac.json @@ -2218,5 +2218,15 @@ { "Pattern": "System.Management.Automation.dll", "FileType": "Product" + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 2999db1a180..f811109f818 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -4605,5 +4605,15 @@ "Pattern": "System.Management.Automation.dll", "FileType": "Product", "Architecture": null + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] From 250e18cc9bbbf06a5562f3071355ff24ce92f880 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:06:49 +0000 Subject: [PATCH 200/378] Refactor IsComputerNameValid character validation (#26274) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../commands/management/Computer.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs index 0ea1c91aae6..ea8c111531c 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Computer.cs @@ -2019,35 +2019,24 @@ internal static void WriteNonTerminatingError(int errorcode, PSCmdlet cmdlet, st /// internal static bool IsComputerNameValid(string computerName) { - bool allDigits = true; + bool hasAsciiLetterOrHyphen = false; if (computerName.Length >= 64) return false; foreach (char t in computerName) { - if (t >= 'A' && t <= 'Z' || - t >= 'a' && t <= 'z') + if (char.IsAsciiLetter(t) || t is '-') { - allDigits = false; - continue; - } - else if (t >= '0' && t <= '9') - { - continue; + hasAsciiLetterOrHyphen = true; } - else if (t == '-') - { - allDigits = false; - continue; - } - else + else if (!char.IsAsciiDigit(t)) { return false; } } - return !allDigits; + return hasAsciiLetterOrHyphen; } /// From 77f1d99568dd809d6cbc10f02ea6a586070a5ea9 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Mon, 17 Nov 2025 12:36:48 +0900 Subject: [PATCH 201/378] Respect -Shuffle:$false in Get-Random (#26457) --- .../commands/utility/GetRandomCommandBase.cs | 2 +- .../Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs index fef7764c5b8..8e50b1cf5a9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetRandomCommandBase.cs @@ -488,7 +488,7 @@ protected override void ProcessRecord() { if (EffectiveParameterSet == MyParameterSet.RandomListItem) { - if (ParameterSetName == ShuffleParameterSet) + if (Shuffle) { // this allows for $null to be in an array passed to InputObject foreach (object item in InputObject ?? _nullInArray) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 index cd9fee41873..100ca90b357 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Random.Tests.ps1 @@ -162,6 +162,12 @@ Describe "Get-Random" -Tags "CI" { $randomNumber | Should -BeIn 1, 2, 3, 5, 8, 13 } + It "Should return a single random item when -Shuffle:`$false is used" { + $randomNumber = Get-Random -InputObject 1, 2, 3, 5, 8, 13 -Shuffle:$false + $randomNumber.Count | Should -Be 1 + $randomNumber | Should -BeIn 1, 2, 3, 5, 8, 13 + } + It "Should return for a string collection " { $randomNumber = Get-Random -InputObject "red", "yellow", "blue" $randomNumber | Should -Be ("red" -or "yellow" -or "blue") From e741cecab394958337a21fd54e280950197df44b Mon Sep 17 00:00:00 2001 From: yotsuda Date: Mon, 17 Nov 2025 15:45:14 +0900 Subject: [PATCH 202/378] Respect -Shuffle:$false in Get-SecureRandom (#26460) --- .../Microsoft.PowerShell.Utility/Get-SecureRandom.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-SecureRandom.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-SecureRandom.Tests.ps1 index acc560abdb3..957bfa30e9e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-SecureRandom.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-SecureRandom.Tests.ps1 @@ -150,6 +150,12 @@ Describe "Get-SecureRandom" -Tags "CI" { $randomNumber | Should -BeIn 1, 2, 3, 5, 8, 13 } + It "Should return a single random item when -Shuffle:`$false is used" { + $randomNumber = Get-SecureRandom -InputObject 1, 2, 3, 5, 8, 13 -Shuffle:$false + $randomNumber.Count | Should -Be 1 + $randomNumber | Should -BeIn 1, 2, 3, 5, 8, 13 + } + It "Should return for a string collection " { $randomNumber = Get-SecureRandom -InputObject "red", "yellow", "blue" $randomNumber | Should -Be ("red" -or "yellow" -or "blue") From 11d154c6730dc2ef05c4df09de119b2dc5a4fa88 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Tue, 18 Nov 2025 02:04:57 +0900 Subject: [PATCH 203/378] Respect -ListAvailable:$false in Get-TimeZone (#26463) --- .../commands/management/TimeZoneCommands.cs | 2 +- .../Microsoft.PowerShell.Management/TimeZone.Tests.ps1 | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs index 8fdb2c55acd..22a50e41176 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TimeZoneCommands.cs @@ -54,7 +54,7 @@ protected override void ProcessRecord() // make sure we've got the latest time zone settings TimeZoneInfo.ClearCachedData(); - if (this.ParameterSetName.Equals("ListAvailable", StringComparison.OrdinalIgnoreCase)) + if (ListAvailable) { // output the list of all available time zones WriteObject(TimeZoneInfo.GetSystemTimeZones(), true); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/TimeZone.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/TimeZone.Tests.ps1 index 5a23c7df75a..a3904fca41f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/TimeZone.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/TimeZone.Tests.ps1 @@ -71,6 +71,12 @@ Describe "Get-Timezone test cases" -Tags "CI" { $oneExpectedOffset | Should -BeIn $observedIdList } + It "Call with -ListAvailable:`$false returns current TimeZoneInfo (not list)" { + $result = Get-TimeZone -ListAvailable:$false + $result | Should -BeOfType TimeZoneInfo + $result.Id | Should -Be ([System.TimeZoneInfo]::Local).Id + } + It "Call Get-TimeZone using ID param and single item" { $selectedTZ = $TimeZonesAvailable[0] (Get-TimeZone -Id $selectedTZ.Id).Id | Should -Be $selectedTZ.Id From 6d61ef1034f4b6866fa1e727eb1d157427df28d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 11:51:56 -0800 Subject: [PATCH 204/378] Bump github/codeql-action from 4.31.2 to 4.31.3 (#26451) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index a16a840a606..6b9878be9ea 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 + uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 + uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 4246af344fd..4c502ed38a3 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5 + uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 with: sarif_file: results.sarif From bb44aa1bc4e83dcf4ab7cf31bf9ae241b395f86b Mon Sep 17 00:00:00 2001 From: kasperk81 <83082615+kasperk81@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:56:51 +0200 Subject: [PATCH 205/378] Mirror .NET/runtime ICU version range in PowerShell Linux packaging (#26304) --- tools/packaging/packaging.psm1 | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index baeb12e360a..8f9cec71790 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2125,6 +2125,22 @@ function Get-PackageDependencies # These should match those in the Dockerfiles, but exclude tools like Git, which, and curl $Dependencies = @() + + # ICU version range follows .NET runtime policy. + # See: https://github.com/dotnet/runtime/blob/3fe8518d51bbcaa179bbe275b2597fbe1b88bc5a/src/native/libs/System.Globalization.Native/pal_icushim.c#L235-L243 + # + # Version range rationale: + # - The runtime supports ICU versions >= the version it was built against + # and <= that version + 30, to allow sufficient headroom for future releases. + # - ICU typically releases about twice per year, so +30 provides roughly + # 15 years of forward compatibility. + # - On some platforms, the minimum supported version may be lower + # than the build version and we know that older versions just works. + # + $MinICUVersion = 60 # runtime minimum supported + $BuildICUVersion = 76 # current build version + $MaxICUVersion = $BuildICUVersion + 30 # headroom + if ($Distribution -eq 'deb') { $Dependencies = @( "libc6", @@ -2132,10 +2148,9 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu76|libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + (($MaxICUVersion..$MinICUVersion).ForEach{ "libicu$_" } -join '|'), "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) - } elseif ($Distribution -eq 'rh') { $Dependencies = @( "openssl-libs", From 015b5cd80152c3f4e44b40293a18e7798a18b1aa Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:26:45 -0800 Subject: [PATCH 206/378] Update build to use .NET SDK 10.0.100 (#26448) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../BenchmarkDotNet.Extensions.csproj | 4 +- .../ResultsComparer/ResultsComparer.csproj | 4 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 148 +++++++----------- 16 files changed, 80 insertions(+), 120 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 8541f8ba795..267f0bda7d6 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100-rc.1.25451.107", + "sdkImageVersion": "10.0.100", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 83e6a8b43e0..376af49c07f 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-rc.2.25502.107" + "version": "10.0.100" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index cc3760db39f..a338c175f14 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index f5f6fede1af..ef949508346 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index da15fe82350..1f9f342b259 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 228d6360022..45b4d8c0a0a 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 57994fb98f7..87f71daada9 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index bef80519d56..48b4d8ff29c 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 114a4c09aaf..e929166b20d 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index d67f17c60f9..91566f64fb1 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 3274f04acec..af3fc10ffce 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - - + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index de06b206f37..886b5f11826 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index d2004ea2fdd..15a6e49864c 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 056f6810c71..1dddf99ba5e 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 5cb4a1e48d8..0863a23d441 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -30,7 +30,7 @@ all - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 26936804614..d8165298b22 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -126,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -186,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -336,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -376,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -436,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -596,17 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Private.ServiceModel", - "Version": "4.10.3" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -616,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -626,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -636,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -646,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -656,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -666,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -675,8 +665,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.Duplex", - "Version": "4.10.3" + "Name": "System.ServiceModel.Http", + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -685,8 +675,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.Http", - "Version": "4.10.3" + "Name": "System.ServiceModel.NetFramingBase", + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -696,7 +686,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetTcp", - "Version": "4.10.3" + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -706,17 +696,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Primitives", - "Version": "4.10.3" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.ServiceModel.Security", - "Version": "4.10.3" + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -726,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -736,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -746,27 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Threading.AccessControl", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -786,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false From d486365b246c29ad9bc2704452ead96083e93a40 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Tue, 18 Nov 2025 21:49:38 +0900 Subject: [PATCH 207/378] Fix Invoke-RestMethod to support read-only files in multipart form data (#26454) --- .../Common/WebRequestPSCmdlet.Common.cs | 2 +- .../WebCmdlets.Tests.ps1 | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 7a784a1e495..f1a455974b9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -1995,7 +1995,7 @@ private static StreamContent GetMultipartStreamContent(object fieldName, Stream /// The file to use for the private static StreamContent GetMultipartFileContent(object fieldName, FileInfo file) { - StreamContent result = GetMultipartStreamContent(fieldName: fieldName, stream: new FileStream(file.FullName, FileMode.Open)); + StreamContent result = GetMultipartStreamContent(fieldName: fieldName, stream: new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)); result.Headers.ContentDisposition.FileName = file.Name; result.Headers.ContentDisposition.FileNameStar = file.Name; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 1ddb9f10ba9..7c0fffa5c4a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1727,6 +1727,26 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Files[0].Content | Should -Match $file1Contents } + It "Verifies Invoke-WebRequest -Form supports read-only file values" { + # Create a read-only test file + $readOnlyFile = Join-Path $TestDrive "readonly-test.txt" + "ReadOnly test content" | Out-File -FilePath $readOnlyFile -Encoding utf8 + Set-ItemProperty -Path $readOnlyFile -Name IsReadOnly -Value $true + + $form = @{TestFile = [System.IO.FileInfo]$readOnlyFile} + $uri = Get-WebListenerUrl -Test 'Multipart' + $response = Invoke-WebRequest -Uri $uri -Form $form -Method 'POST' + $result = $response.Content | ConvertFrom-Json + + $result.Headers.'Content-Type' | Should -Match 'multipart/form-data' + $result.Files.Count | Should -Be 1 + + $result.Files[0].Name | Should -BeExactly "TestFile" + $result.Files[0].FileName | Should -BeExactly "readonly-test.txt" + $result.Files[0].ContentType | Should -BeExactly 'application/octet-stream' + $result.Files[0].Content | Should -Match "ReadOnly test content" + } + It "Verifies Invoke-WebRequest -Form sets Content-Disposition FileName and FileNameStar." { $ContentDisposition = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("attachment") $ContentDisposition.FileName = $fileName @@ -3568,6 +3588,25 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Files[0].Content | Should -Match $file1Contents } + It "Verifies Invoke-RestMethod -Form supports read-only file values" { + # Create a read-only test file + $readOnlyFile = Join-Path $TestDrive "readonly-test.txt" + "ReadOnly test content" | Out-File -FilePath $readOnlyFile -Encoding utf8 + Set-ItemProperty -Path $readOnlyFile -Name IsReadOnly -Value $true + + $form = @{TestFile = [System.IO.FileInfo]$readOnlyFile} + $uri = Get-WebListenerUrl -Test 'Multipart' + $result = Invoke-RestMethod -Uri $uri -Form $form -Method 'POST' + + $result.Headers.'Content-Type' | Should -Match 'multipart/form-data' + $result.Files.Count | Should -Be 1 + + $result.Files[0].Name | Should -Be "TestFile" + $result.Files[0].FileName | Should -Be "readonly-test.txt" + $result.Files[0].ContentType | Should -Be 'application/octet-stream' + $result.Files[0].Content | Should -Match "ReadOnly test content" + } + It "Verifies Invoke-RestMethod -Form sets Content-Disposition FileName and FileNameStar." { $ContentDisposition = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("attachment") $ContentDisposition.FileName = $fileName From 6928efb4c5224805c9d6f9fef5a20e26a20fd89c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:47:44 -0800 Subject: [PATCH 208/378] Fix GitHub API rate limit errors in test actions (#26489) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/actions/test/nix/action.yml | 10 ++++++++-- .github/actions/test/windows/action.yml | 10 ++++++++-- .github/workflows/linux-ci.yml | 4 ++++ .github/workflows/macos-ci.yml | 4 ++++ .github/workflows/windows-ci.yml | 4 ++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index b8c1778974c..7f68e71c1f5 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -14,6 +14,9 @@ inputs: required: false default: ctrf type: string + GITHUB_TOKEN: + description: 'GitHub token for API authentication' + required: true runs: using: composite @@ -64,7 +67,10 @@ runs: shell: pwsh run: |- Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 - $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $headers = @{ + Authorization = "Bearer ${{ inputs.GITHUB_TOKEN }}" + } + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" -Headers $headers $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 $latestVersion = $latestRelease.tag_name.TrimStart("v") Write-Host "Latest DSC Version: $latestVersion" @@ -78,7 +84,7 @@ runs: $tempPath = Get-GWTempPath - Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose -Headers $headers New-Item -ItemType Directory -Path "$tempPath/DSC" -Force -Verbose tar xvf "$tempPath/DSC.tar.gz" -C "$tempPath/DSC" $dscRoot = "$tempPath/DSC" diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 923e9606e59..2c41f6aac5c 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -14,6 +14,9 @@ inputs: required: false default: ctrf type: string + GITHUB_TOKEN: + description: 'GitHub token for API authentication' + required: true runs: using: composite @@ -47,7 +50,10 @@ runs: shell: pwsh run: |- Import-Module .\.github\workflows\GHWorkflowHelper\GHWorkflowHelper.psm1 - $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $headers = @{ + Authorization = "Bearer ${{ inputs.GITHUB_TOKEN }}" + } + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" -Headers $headers $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 $latestVersion = $latestRelease.tag_name.TrimStart("v") Write-Host "Latest DSC Version: $latestVersion" @@ -55,7 +61,7 @@ runs: $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "DSC-*-x86_64-pc-windows-msvc.zip" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url Write-Host "Download URL: $downloadUrl" $tempPath = Get-GWTempPath - Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" -Headers $headers $null = New-Item -ItemType Directory -Path "$tempPath\DSC" -Force Expand-Archive -Path "$tempPath\DSC.zip" -DestinationPath "$tempPath\DSC" -Force diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 2058bd61568..030139b6c30 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -111,6 +111,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_elevated_ci: name: Linux Elevated CI needs: @@ -128,6 +129,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_unelevated_others: name: Linux Unelevated Others needs: @@ -145,6 +147,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_elevated_others: name: Linux Elevated Others needs: @@ -162,6 +165,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index bdb7c128d12..721077a6b70 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -93,6 +93,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_elevated_ci: name: macOS Elevated CI needs: @@ -110,6 +111,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_unelevated_others: name: macOS Unelevated Others needs: @@ -127,6 +129,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_elevated_others: name: macOS Elevated Others needs: @@ -144,6 +147,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 582860de34c..4f774fcdc9b 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -97,6 +97,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_elevated_ci: name: Windows Elevated CI needs: @@ -114,6 +115,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_unelevated_others: name: Windows Unelevated Others needs: @@ -131,6 +133,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_elevated_others: name: Windows Elevated Others needs: @@ -148,6 +151,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: From 230970bb5dcf16939533f6038e02c484aa50998f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:07:46 -0800 Subject: [PATCH 209/378] Bump github/codeql-action from 4.31.3 to 4.31.4 (#26484) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 6b9878be9ea..9ed85e11e23 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 + uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 + uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 4c502ed38a3..3f5951951e1 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v3.29.5 + uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 with: sarif_file: results.sarif From 108eb857bb2beed653556857f1fb551bdbdd1f0a Mon Sep 17 00:00:00 2001 From: yotsuda Date: Fri, 21 Nov 2025 21:06:23 +0900 Subject: [PATCH 210/378] Correct handling of explicit -[Operator]:$false parameter values in Where-Object (#26485) --- .../engine/InternalCommands.cs | 157 +++++++++--- .../Where-Object.Tests.ps1 | 238 ++++++++++++++++++ 2 files changed, 363 insertions(+), 32 deletions(-) diff --git a/src/System.Management.Automation/engine/InternalCommands.cs b/src/System.Management.Automation/engine/InternalCommands.cs index 844a965ac1e..4e50e2d130f 100644 --- a/src/System.Management.Automation/engine/InternalCommands.cs +++ b/src/System.Management.Automation/engine/InternalCommands.cs @@ -1441,8 +1441,11 @@ public SwitchParameter EQ set { - _binaryOperator = TokenKind.Ieq; - _forceBooleanEvaluation = false; + if (value) + { + _binaryOperator = TokenKind.Ieq; + _forceBooleanEvaluation = false; + } } } @@ -1459,7 +1462,10 @@ public SwitchParameter CEQ set { - _binaryOperator = TokenKind.Ceq; + if (value) + { + _binaryOperator = TokenKind.Ceq; + } } } @@ -1477,7 +1483,10 @@ public SwitchParameter NE set { - _binaryOperator = TokenKind.Ine; + if (value) + { + _binaryOperator = TokenKind.Ine; + } } } @@ -1494,7 +1503,10 @@ public SwitchParameter CNE set { - _binaryOperator = TokenKind.Cne; + if (value) + { + _binaryOperator = TokenKind.Cne; + } } } @@ -1512,7 +1524,10 @@ public SwitchParameter GT set { - _binaryOperator = TokenKind.Igt; + if (value) + { + _binaryOperator = TokenKind.Igt; + } } } @@ -1529,7 +1544,10 @@ public SwitchParameter CGT set { - _binaryOperator = TokenKind.Cgt; + if (value) + { + _binaryOperator = TokenKind.Cgt; + } } } @@ -1547,7 +1565,10 @@ public SwitchParameter LT set { - _binaryOperator = TokenKind.Ilt; + if (value) + { + _binaryOperator = TokenKind.Ilt; + } } } @@ -1564,7 +1585,10 @@ public SwitchParameter CLT set { - _binaryOperator = TokenKind.Clt; + if (value) + { + _binaryOperator = TokenKind.Clt; + } } } @@ -1582,7 +1606,10 @@ public SwitchParameter GE set { - _binaryOperator = TokenKind.Ige; + if (value) + { + _binaryOperator = TokenKind.Ige; + } } } @@ -1599,7 +1626,10 @@ public SwitchParameter CGE set { - _binaryOperator = TokenKind.Cge; + if (value) + { + _binaryOperator = TokenKind.Cge; + } } } @@ -1617,7 +1647,10 @@ public SwitchParameter LE set { - _binaryOperator = TokenKind.Ile; + if (value) + { + _binaryOperator = TokenKind.Ile; + } } } @@ -1634,7 +1667,10 @@ public SwitchParameter CLE set { - _binaryOperator = TokenKind.Cle; + if (value) + { + _binaryOperator = TokenKind.Cle; + } } } @@ -1652,7 +1688,10 @@ public SwitchParameter Like set { - _binaryOperator = TokenKind.Ilike; + if (value) + { + _binaryOperator = TokenKind.Ilike; + } } } @@ -1669,7 +1708,10 @@ public SwitchParameter CLike set { - _binaryOperator = TokenKind.Clike; + if (value) + { + _binaryOperator = TokenKind.Clike; + } } } @@ -1687,7 +1729,10 @@ public SwitchParameter NotLike set { - _binaryOperator = TokenKind.Inotlike; + if (value) + { + _binaryOperator = TokenKind.Inotlike; + } } } @@ -1704,7 +1749,10 @@ public SwitchParameter CNotLike set { - _binaryOperator = TokenKind.Cnotlike; + if (value) + { + _binaryOperator = TokenKind.Cnotlike; + } } } @@ -1722,7 +1770,10 @@ public SwitchParameter Match set { - _binaryOperator = TokenKind.Imatch; + if (value) + { + _binaryOperator = TokenKind.Imatch; + } } } @@ -1739,7 +1790,10 @@ public SwitchParameter CMatch set { - _binaryOperator = TokenKind.Cmatch; + if (value) + { + _binaryOperator = TokenKind.Cmatch; + } } } @@ -1757,7 +1811,10 @@ public SwitchParameter NotMatch set { - _binaryOperator = TokenKind.Inotmatch; + if (value) + { + _binaryOperator = TokenKind.Inotmatch; + } } } @@ -1774,7 +1831,10 @@ public SwitchParameter CNotMatch set { - _binaryOperator = TokenKind.Cnotmatch; + if (value) + { + _binaryOperator = TokenKind.Cnotmatch; + } } } @@ -1792,7 +1852,10 @@ public SwitchParameter Contains set { - _binaryOperator = TokenKind.Icontains; + if (value) + { + _binaryOperator = TokenKind.Icontains; + } } } @@ -1809,7 +1872,10 @@ public SwitchParameter CContains set { - _binaryOperator = TokenKind.Ccontains; + if (value) + { + _binaryOperator = TokenKind.Ccontains; + } } } @@ -1827,7 +1893,10 @@ public SwitchParameter NotContains set { - _binaryOperator = TokenKind.Inotcontains; + if (value) + { + _binaryOperator = TokenKind.Inotcontains; + } } } @@ -1844,7 +1913,10 @@ public SwitchParameter CNotContains set { - _binaryOperator = TokenKind.Cnotcontains; + if (value) + { + _binaryOperator = TokenKind.Cnotcontains; + } } } @@ -1862,7 +1934,10 @@ public SwitchParameter In set { - _binaryOperator = TokenKind.In; + if (value) + { + _binaryOperator = TokenKind.In; + } } } @@ -1879,7 +1954,10 @@ public SwitchParameter CIn set { - _binaryOperator = TokenKind.Cin; + if (value) + { + _binaryOperator = TokenKind.Cin; + } } } @@ -1897,7 +1975,10 @@ public SwitchParameter NotIn set { - _binaryOperator = TokenKind.Inotin; + if (value) + { + _binaryOperator = TokenKind.Inotin; + } } } @@ -1914,7 +1995,10 @@ public SwitchParameter CNotIn set { - _binaryOperator = TokenKind.Cnotin; + if (value) + { + _binaryOperator = TokenKind.Cnotin; + } } } @@ -1931,7 +2015,10 @@ public SwitchParameter Is set { - _binaryOperator = TokenKind.Is; + if (value) + { + _binaryOperator = TokenKind.Is; + } } } @@ -1948,7 +2035,10 @@ public SwitchParameter IsNot set { - _binaryOperator = TokenKind.IsNot; + if (value) + { + _binaryOperator = TokenKind.IsNot; + } } } @@ -1965,7 +2055,10 @@ public SwitchParameter Not set { - _binaryOperator = TokenKind.Not; + if (value) + { + _binaryOperator = TokenKind.Not; + } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1 index c12a1bdb516..eae7d9951a3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1 @@ -142,4 +142,242 @@ Describe "Where-Object" -Tags "CI" { $Result[0] | Should -Be $dynObj $Result[1] | Should -Be $dynObj } + + Context "Switch parameter explicit `$false handling" { + BeforeAll { + $testData = @( + [PSCustomObject]@{ Name = 'Alice'; Age = 25; City = 'New York' } + [PSCustomObject]@{ Name = 'Bob'; Age = 30; City = 'Boston' } + [PSCustomObject]@{ Name = 'Charlie'; Age = 35; City = 'Chicago' } + ) + } + + It "-EQ:`$false should behave like default boolean evaluation" { + # With -EQ:$false, the parameter is not specified, so default boolean evaluation applies + # "... | Where-Object Name" is equivalent to "... | Where-Object {$true -eq $_.Name}" + # Non-empty strings are truthy + $result = $testData | Where-Object Name -EQ:$false + $result | Should -HaveCount 3 + } + + It "-GT:`$false should behave like default boolean evaluation" { + # With -GT:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -GT:$false + $result | Should -HaveCount 3 + } + + It "-LT:`$false should behave like default boolean evaluation" { + # With -LT:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -LT:$false + $result | Should -HaveCount 3 + } + + It "-NE:`$false should behave like default boolean evaluation" { + # With -NE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -NE:$false + $result | Should -HaveCount 3 + } + + It "-GE:`$false should behave like default boolean evaluation" { + # With -GE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -GE:$false + $result | Should -HaveCount 3 + } + + It "-LE:`$false should behave like default boolean evaluation" { + # With -LE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -LE:$false + $result | Should -HaveCount 3 + } + + It "-NotLike:`$false should behave like default boolean evaluation" { + # With -NotLike:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object City -NotLike:$false + $result | Should -HaveCount 3 + } + + It "-NotMatch:`$false should behave like default boolean evaluation" { + # With -NotMatch:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -NotMatch:$false + $result | Should -HaveCount 3 + } + + It "-NotContains:`$false should behave like default boolean evaluation" { + # With -NotContains:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -NotContains:$false + $result | Should -HaveCount 3 + } + + It "-NotIn:`$false should behave like default boolean evaluation" { + # With -NotIn:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -NotIn:$false + $result | Should -HaveCount 3 + } + + It "-IsNot:`$false should behave like default boolean evaluation" { + # With -IsNot:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -IsNot:$false + $result | Should -HaveCount 3 + } + + It "-Like:`$false should behave like default boolean evaluation" { + # With -Like:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object City -Like:$false + $result | Should -HaveCount 3 + } + + It "-Match:`$false should behave like default boolean evaluation" { + # With -Match:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -Match:$false + $result | Should -HaveCount 3 + } + + It "-Contains:`$false should behave like default boolean evaluation" { + # With -Contains:$false, the parameter is not specified, so default boolean evaluation applies + # "... | Where-Object Name" checks if Name property is truthy + $result = $testData | Where-Object Name -Contains:$false + $result | Should -HaveCount 3 + } + + It "-In:`$false should behave like default boolean evaluation" { + # With -In:$false, the parameter is not specified, so default boolean evaluation applies + # "... | Where-Object Name" checks if Name property is truthy + $result = $testData | Where-Object Name -In:$false + $result | Should -HaveCount 3 + } + + It "-Is:`$false should behave like default boolean evaluation" { + # With -Is:$false, the parameter is not specified, so default boolean evaluation applies + # "... | Where-Object Name" checks if Name property is truthy + $result = $testData | Where-Object Name -Is:$false + $result | Should -HaveCount 3 + } + + It "-Not:`$false should behave like default boolean evaluation" { + $testData2 = @( + [PSCustomObject]@{ Name = ''; Value = 1 } + [PSCustomObject]@{ Name = 'Test'; Value = 2 } + ) + # With -Not:$false, the parameter is not specified, so default boolean evaluation applies + # "... | Where-Object Name" returns objects where Name is truthy (non-empty) + $result = $testData2 | Where-Object Name -Not:$false + $result | Should -HaveCount 1 + $result.Name | Should -Be 'Test' + } + + It "-GT:`$false with -Value should throw an error requiring an operator" { + # When a switch parameter is set to $false with -Value specified, + # it should throw an error because no valid operator is active + { $testData | Where-Object Age -GT:$false -Value 25 } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + + It "-EQ:`$false with -Value should throw an error requiring an operator" { + # Similar behavior for -EQ:$false with -Value + { $testData | Where-Object Name -EQ:$false -Value 'Alice' } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + + It "-Like:`$false with -Value should throw an error requiring an operator" { + # Similar behavior for -Like:$false with -Value + { $testData | Where-Object Name -Like:$false -Value 'A*' } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + + It "-CEQ:`$false should behave like default boolean evaluation" { + # With -CEQ:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CEQ:$false + $result | Should -HaveCount 3 + } + + It "-CNE:`$false should behave like default boolean evaluation" { + # With -CNE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CNE:$false + $result | Should -HaveCount 3 + } + + It "-CGT:`$false should behave like default boolean evaluation" { + # With -CGT:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -CGT:$false + $result | Should -HaveCount 3 + } + + It "-CLT:`$false should behave like default boolean evaluation" { + # With -CLT:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -CLT:$false + $result | Should -HaveCount 3 + } + + It "-CGE:`$false should behave like default boolean evaluation" { + # With -CGE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -CGE:$false + $result | Should -HaveCount 3 + } + + It "-CLE:`$false should behave like default boolean evaluation" { + # With -CLE:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Age -CLE:$false + $result | Should -HaveCount 3 + } + + It "-CLike:`$false should behave like default boolean evaluation" { + # With -CLike:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object City -CLike:$false + $result | Should -HaveCount 3 + } + + It "-CNotLike:`$false should behave like default boolean evaluation" { + # With -CNotLike:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object City -CNotLike:$false + $result | Should -HaveCount 3 + } + + It "-CMatch:`$false should behave like default boolean evaluation" { + # With -CMatch:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CMatch:$false + $result | Should -HaveCount 3 + } + + It "-CNotMatch:`$false should behave like default boolean evaluation" { + # With -CNotMatch:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CNotMatch:$false + $result | Should -HaveCount 3 + } + + It "-CContains:`$false should behave like default boolean evaluation" { + # With -CContains:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CContains:$false + $result | Should -HaveCount 3 + } + + It "-CNotContains:`$false should behave like default boolean evaluation" { + # With -CNotContains:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CNotContains:$false + $result | Should -HaveCount 3 + } + + It "-CIn:`$false should behave like default boolean evaluation" { + # With -CIn:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CIn:$false + $result | Should -HaveCount 3 + } + + It "-CNotIn:`$false should behave like default boolean evaluation" { + # With -CNotIn:$false, the parameter is not specified, so default boolean evaluation applies + $result = $testData | Where-Object Name -CNotIn:$false + $result | Should -HaveCount 3 + } + + It "-CEQ:`$false with -Value should throw an error requiring an operator" { + # Similar behavior for -CEQ:$false with -Value + { $testData | Where-Object Name -CEQ:$false -Value 'Alice' } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + + It "-CGT:`$false with -Value should throw an error requiring an operator" { + # Similar behavior for -CGT:$false with -Value + { $testData | Where-Object Age -CGT:$false -Value 25 } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + + It "-CLike:`$false with -Value should throw an error requiring an operator" { + # Similar behavior for -CLike:$false with -Value + { $testData | Where-Object Name -CLike:$false -Value 'A*' } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' + } + } } From fb6403d4da3e9379f7350c2d6b1d22d732698e76 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Fri, 21 Nov 2025 21:12:28 +0900 Subject: [PATCH 211/378] Respect -Repeat/-MtuSize/-Traceroute:$false in Test-Connection (#26479) --- .../management/TestConnectionCommand.cs | 44 +++++++++---------- .../Test-Connection.Tests.ps1 | 29 ++++++++++++ 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs index 17c9ab9a5d3..2a4a453f8f7 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs @@ -242,14 +242,13 @@ public class TestConnectionCommand : PSCmdlet, IDisposable /// protected override void BeginProcessing() { - switch (ParameterSetName) + if (Repeat) { - case RepeatPingParameterSet: - Count = int.MaxValue; - break; - case TcpPortParameterSet: - SetCountForTcpTest(); - break; + Count = int.MaxValue; + } + else if (ParameterSetName == TcpPortParameterSet) + { + SetCountForTcpTest(); } } @@ -265,21 +264,22 @@ protected override void ProcessRecord() foreach (var targetName in TargetName) { - switch (ParameterSetName) + if (MtuSize) + { + ProcessMTUSize(targetName); + } + else if (Traceroute) + { + ProcessTraceroute(targetName); + } + else if (ParameterSetName == TcpPortParameterSet) + { + ProcessConnectionByTCPPort(targetName); + } + else { - case DefaultPingParameterSet: - case RepeatPingParameterSet: - ProcessPing(targetName); - break; - case MtuSizeDetectParameterSet: - ProcessMTUSize(targetName); - break; - case TraceRouteParameterSet: - ProcessTraceroute(targetName); - break; - case TcpPortParameterSet: - ProcessConnectionByTCPPort(targetName); - break; + // None of the switch parameters are true: handle default ping or -Repeat + ProcessPing(targetName); } } } @@ -298,7 +298,7 @@ protected override void StopProcessing() private void SetCountForTcpTest() { - if (Repeat.IsPresent) + if (Repeat) { Count = int.MaxValue; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 index 2138a447581..ad01b461b55 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 @@ -258,6 +258,15 @@ Describe "Test-Connection" -tags "CI", "RequireSudoOnUnix" { $pingResults.Where( { $_.Status -eq 'Success' }, 'Default', 1 ).BufferSize | Should -Be 32 } } + + It "Repeat with explicit false should behave like default ping" { + # -Repeat:$false should behave the same as not specifying -Repeat + $pingResults = Test-Connection $targetAddress -Repeat:$false + + # Should get exactly 4 pings (the default Count value) + $pingResults.Count | Should -Be 4 + $pingResults[0].Address | Should -BeExactly $targetAddress + } } Context "MTUSizeDetect" { @@ -291,6 +300,16 @@ Describe "Test-Connection" -tags "CI", "RequireSudoOnUnix" { $result | Should -BeOfType Int32 $result | Should -BeGreaterThan 0 } + + It "MtuSize with explicit false should behave like default ping" { + # -MtuSize:$false should behave the same as not specifying -MtuSize (default ping) + $pingResults = Test-Connection $targetAddress -MtuSize:$false + + # Should return PingStatus, not PingMtuStatus + $pingResults[0] | Should -BeOfType Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus + # Should get 4 pings (the default Count value) + $pingResults.Count | Should -Be 4 + } } Context "TraceRoute" { @@ -332,6 +351,16 @@ Describe "Test-Connection" -tags "CI", "RequireSudoOnUnix" { $results.Hostname | Should -Not -BeNullOrEmpty } + + It "Traceroute with explicit false should behave like default ping" { + # -Traceroute:$false should behave the same as not specifying -Traceroute (default ping) + $pingResults = Test-Connection $targetAddress -Traceroute:$false + + # Should return PingStatus, not TraceStatus + $pingResults[0] | Should -BeOfType Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus + # Should get 4 pings (the default Count value) + $pingResults.Count | Should -Be 4 + } } } From e81985d8f2b32f4bad0684749d29dbe3d5c074e1 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Sat, 22 Nov 2025 02:50:32 +0900 Subject: [PATCH 212/378] Respect -UseWindowsPowerShell:$false in New-PSSession (#26469) --- .../remoting/commands/newrunspacecommand.cs | 11 ++++- .../engine/Remoting/PSSession.Tests.ps1 | 45 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs index 8986def5a6d..60ca0c35e50 100644 --- a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs @@ -267,7 +267,16 @@ protected override void ProcessRecord() case NewPSSessionCommand.UseWindowsPowerShellParameterSet: { - remoteRunspaces = CreateRunspacesForUseWindowsPowerShellParameterSet(); + if (UseWindowsPowerShell) + { + remoteRunspaces = CreateRunspacesForUseWindowsPowerShellParameterSet(); + } + else + { + // When -UseWindowsPowerShell:$false is explicitly specified, + // fall back to the default ComputerName parameter set behavior + goto case NewPSSessionCommand.ComputerNameParameterSet; + } } break; diff --git a/test/powershell/engine/Remoting/PSSession.Tests.ps1 b/test/powershell/engine/Remoting/PSSession.Tests.ps1 index 689e587ddb1..317ed4af734 100644 --- a/test/powershell/engine/Remoting/PSSession.Tests.ps1 +++ b/test/powershell/engine/Remoting/PSSession.Tests.ps1 @@ -91,3 +91,48 @@ Describe "SkipCACheck and SkipCNCheck PSSession options are required for New-PSS $er.Exception.ErrorCode | Should -Be $expectedErrorCode } } + +Describe "New-PSSession -UseWindowsPowerShell switch parameter" -Tag "CI" { + + BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + + if (-not $IsWindows) { + $PSDefaultParameterValues['it:skip'] = $true + } + } + + AfterAll { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + } + + It "Should respect explicit -UseWindowsPowerShell:`$false parameter value" { + # Test 1: -UseWindowsPowerShell:$true should create a Windows PowerShell 5.1 session + $sessionWithTrue = $null + try { + { $script:sessionWithTrue = New-PSSession -UseWindowsPowerShell:$true } | Should -Not -Throw + $script:sessionWithTrue | Should -Not -BeNullOrEmpty + + # Verify it's Windows PowerShell 5.1 + $version = Invoke-Command -Session $script:sessionWithTrue -ScriptBlock { $PSVersionTable.PSVersion } + $version.Major | Should -Be 5 + $version.Minor | Should -Be 1 + } + finally { + if ($script:sessionWithTrue) { Remove-PSSession $script:sessionWithTrue -ErrorAction SilentlyContinue } + } + + # Test 2: -UseWindowsPowerShell:$false should use WSMan transport (not Process) + $sessionWithFalse = $null + try { + { $script:sessionWithFalse = New-PSSession -UseWindowsPowerShell:$false } | Should -Not -Throw + $script:sessionWithFalse | Should -Not -BeNullOrEmpty + + # Transport should be WSMan, not Process + $script:sessionWithFalse.Transport | Should -Be 'WSMan' + } + finally { + if ($script:sessionWithFalse) { Remove-PSSession $script:sessionWithFalse -ErrorAction SilentlyContinue } + } + } +} From bb712def99cc6b2c8ac5a7e3a4d3e84ad7c3845f Mon Sep 17 00:00:00 2001 From: yotsuda Date: Sat, 22 Nov 2025 02:56:07 +0900 Subject: [PATCH 213/378] Respect -Qualifier/-NoQualifier/-Leaf/-IsAbsolute:$false in Split-Path (#26474) --- .../commands/management/ParsePathCommand.cs | 220 +++++++++--------- .../Split-Path.Tests.ps1 | 30 ++- 2 files changed, 132 insertions(+), 118 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs index b6609f8b692..ca616301ebb 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/ParsePathCommand.cs @@ -289,137 +289,125 @@ protected override void ProcessRecord() { string result = null; - switch (ParameterSetName) + // Check switch parameters in order of specificity + if (IsAbsolute) { - case isAbsoluteSet: - string ignored; - bool isPathAbsolute = - SessionState.Path.IsPSAbsolute(pathsToParse[index], out ignored); + string ignored; + bool isPathAbsolute = + SessionState.Path.IsPSAbsolute(pathsToParse[index], out ignored); - WriteObject(isPathAbsolute); - continue; + WriteObject(isPathAbsolute); + continue; + } + else if (Qualifier) + { + int separatorIndex = pathsToParse[index].IndexOf(':'); - case qualifierSet: - int separatorIndex = pathsToParse[index].IndexOf(':'); + if (separatorIndex < 0) + { + FormatException e = + new( + StringUtil.Format(NavigationResources.ParsePathFormatError, pathsToParse[index])); + WriteError( + new ErrorRecord( + e, + "ParsePathFormatError", // RENAME + ErrorCategory.InvalidArgument, + pathsToParse[index])); + continue; + } + else + { + // Check to see if it is provider or drive qualified - if (separatorIndex < 0) - { - FormatException e = - new( - StringUtil.Format(NavigationResources.ParsePathFormatError, pathsToParse[index])); - WriteError( - new ErrorRecord( - e, - "ParsePathFormatError", // RENAME - ErrorCategory.InvalidArgument, - pathsToParse[index])); - continue; - } - else + if (SessionState.Path.IsProviderQualified(pathsToParse[index])) { - // Check to see if it is provider or drive qualified - - if (SessionState.Path.IsProviderQualified(pathsToParse[index])) - { - // The plus 2 is for the length of the provider separator - // which is "::" - - result = - pathsToParse[index].Substring( - 0, - separatorIndex + 2); - } - else - { - result = - pathsToParse[index].Substring( - 0, - separatorIndex + 1); - } - } + // The plus 2 is for the length of the provider separator + // which is "::" - break; - - case parentSet: - case literalPathSet: - try - { result = - SessionState.Path.ParseParent( - pathsToParse[index], - string.Empty, - CmdletProviderContext, - true); + pathsToParse[index].Substring( + 0, + separatorIndex + 2); } - catch (PSNotSupportedException) - { - // Since getting the parent path is not supported, - // the provider must be a container, item, or drive - // provider. Since the paths for these types of - // providers can't be split, asking for the parent - // is asking for an empty string. - result = string.Empty; - } - - break; - - case leafSet: - case leafBaseSet: - case extensionSet: - try + else { - // default handles leafSet result = - SessionState.Path.ParseChildName( - pathsToParse[index], - CmdletProviderContext, - true); - if (LeafBase) - { - result = System.IO.Path.GetFileNameWithoutExtension(result); - } - else if (Extension) - { - result = System.IO.Path.GetExtension(result); - } + pathsToParse[index].Substring( + 0, + separatorIndex + 1); } - catch (PSNotSupportedException) + } + } + else if (Leaf || LeafBase || Extension) + { + try + { + result = + SessionState.Path.ParseChildName( + pathsToParse[index], + CmdletProviderContext, + true); + if (LeafBase) { - // Since getting the leaf part of a path is not supported, - // the provider must be a container, item, or drive - // provider. Since the paths for these types of - // providers can't be split, asking for the leaf - // is asking for the specified path back. - result = pathsToParse[index]; + result = System.IO.Path.GetFileNameWithoutExtension(result); } - catch (DriveNotFoundException driveNotFound) + else if (Extension) { - WriteError( - new ErrorRecord( - driveNotFound.ErrorRecord, - driveNotFound)); - continue; - } - catch (ProviderNotFoundException providerNotFound) - { - WriteError( - new ErrorRecord( - providerNotFound.ErrorRecord, - providerNotFound)); - continue; + result = System.IO.Path.GetExtension(result); } - - break; - - case noQualifierSet: - result = RemoveQualifier(pathsToParse[index]); - break; - - default: - Dbg.Diagnostics.Assert( - false, - "Only a known parameter set should be called"); - break; + } + catch (PSNotSupportedException) + { + // Since getting the leaf part of a path is not supported, + // the provider must be a container, item, or drive + // provider. Since the paths for these types of + // providers can't be split, asking for the leaf + // is asking for the specified path back. + result = pathsToParse[index]; + } + catch (DriveNotFoundException driveNotFound) + { + WriteError( + new ErrorRecord( + driveNotFound.ErrorRecord, + driveNotFound)); + continue; + } + catch (ProviderNotFoundException providerNotFound) + { + WriteError( + new ErrorRecord( + providerNotFound.ErrorRecord, + providerNotFound)); + continue; + } + } + else if (NoQualifier) + { + result = RemoveQualifier(pathsToParse[index]); + } + else + { + // None of the switch parameters are true: default to -Parent behavior + try + { + result = + SessionState.Path.ParseParent( + pathsToParse[index], + string.Empty, + CmdletProviderContext, + true); + } + catch (PSNotSupportedException) + { + // Since getting the parent path is not supported, + // the provider must be a container, item, or drive + // provider. Since the paths for these types of + // providers can't be split, asking for the parent + // is asking for an empty string. + result = string.Empty; + } } if (result != null) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Split-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Split-Path.Tests.ps1 index b9537a4a961..e34126b101f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Split-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Split-Path.Tests.ps1 @@ -96,7 +96,33 @@ Describe "Split-Path" -Tags "CI" { Split-Path -Parent "\\server1\share1" | Should -BeExactly "${dirSep}${dirSep}server1" } - It 'Does not split a drive leter'{ - Split-Path -Path 'C:\' | Should -BeNullOrEmpty + It 'Does not split a drive letter' { + Split-Path -Path 'C:\' | Should -BeNullOrEmpty + } + + It "Should handle explicit -Qualifier:`$false parameter value correctly" { + # When -Qualifier:$false is specified, it should behave like -Parent (default) + # For env:PATH, the parent is empty string + $result = Split-Path -Path "env:PATH" -Qualifier:$false + $result | Should -BeNullOrEmpty + } + + It "Should handle explicit -NoQualifier:`$false parameter value correctly" { + # When -NoQualifier:$false is specified, it should behave like -Parent (default) + # For env:PATH with no qualifier, we expect empty string (parent of PATH in env drive) + $result = Split-Path -Path "env:PATH" -NoQualifier:$false + $result | Should -BeNullOrEmpty + } + + It "Should handle explicit -Leaf:`$false parameter value correctly" { + # When -Leaf:$false is specified, it should behave like -Parent (default) + $dirSep = [string]([System.IO.Path]::DirectorySeparatorChar) + Split-Path -Path "/usr/bin" -Leaf:$false | Should -BeExactly "${dirSep}usr" + } + + It "Should handle explicit -IsAbsolute:`$false parameter value correctly" { + # When -IsAbsolute:$false is specified, it should behave like -Parent (default) + $dirSep = [string]([System.IO.Path]::DirectorySeparatorChar) + Split-Path -Path "fs:/usr/bin" -IsAbsolute:$false | Should -BeExactly "fs:${dirSep}usr" } } From e2075afafe25dd0c2d090ab4032dbacbbcd32b0c Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Fri, 21 Nov 2025 16:08:16 -0600 Subject: [PATCH 214/378] Explain the parameter `-UseNuGetOrg` in build documentation (#26507) --- docs/building/linux.md | 2 ++ docs/building/macos.md | 2 ++ docs/building/windows-core.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/building/linux.md b/docs/building/linux.md index bd7f9aadf69..6ccf12073e2 100644 --- a/docs/building/linux.md +++ b/docs/building/linux.md @@ -64,6 +64,8 @@ Import-Module ./build.psm1 Start-PSBuild -UseNuGetOrg ``` +> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead. + Congratulations! If everything went right, PowerShell is now built. The `Start-PSBuild` script will output the location of the executable: diff --git a/docs/building/macos.md b/docs/building/macos.md index 4f15e3fb547..7fd767ffa1c 100644 --- a/docs/building/macos.md +++ b/docs/building/macos.md @@ -37,3 +37,5 @@ We cannot do this for you in the build module due to #[847][]. Start a PowerShell session by running `pwsh`, and then use `Start-PSBuild -UseNuGetOrg` from the module. After building, PowerShell will be at `./src/powershell-unix/bin/Debug/net6.0/osx-x64/publish/pwsh`. + +> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead. diff --git a/docs/building/windows-core.md b/docs/building/windows-core.md index 48e5c951633..20774695fcd 100644 --- a/docs/building/windows-core.md +++ b/docs/building/windows-core.md @@ -61,6 +61,8 @@ Import-Module ./build.psm1 Start-PSBuild -Clean -PSModuleRestore -UseNuGetOrg ``` +> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead. + Congratulations! If everything went right, PowerShell is now built and executable as `./src/powershell-win-core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe`. This location is of the form `./[project]/bin/[configuration]/[framework]/[rid]/publish/[binary name]`, From f4476c5226d0610373a5989c810dd0ee23da3607 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:36:14 -0800 Subject: [PATCH 215/378] Bump actions/checkout from 5 to 6 (#26505) --- .github/workflows/analyze-reusable.yml | 2 +- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/labels.yml | 2 +- .github/workflows/linux-ci.yml | 18 +++++++++--------- .github/workflows/macos-ci.yml | 14 +++++++------- .github/workflows/scorecards.yml | 2 +- .github/workflows/verify-markdown-links.yml | 2 +- .github/workflows/windows-ci.yml | 12 ++++++------ .../workflows/windows-packaging-reusable.yml | 2 +- .github/workflows/xunit-tests.yml | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 9ed85e11e23..c1d812e533a 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: '0' diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index ac57bd87b5a..be2dd55df7d 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,7 +22,7 @@ jobs: # You can define any steps you want, and they will run before the agent starts. # If you do not check out your code, Copilot will do this for you. steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 1000 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index dadc6fd4370..dbef2e1c8b2 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: 'Dependency Review' uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index cd0a1d31726..61b5eebb88f 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Verify PR has label starting with 'cl-' id: verify-labels diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 030139b6c30..49d1c0a055f 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false @@ -76,7 +76,7 @@ jobs: contents: read steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check for merge conflict markers uses: "./.github/actions/infrastructure/merge-conflict-checker" @@ -88,7 +88,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 @@ -103,7 +103,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Linux Unelevated CI @@ -121,7 +121,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Linux Elevated CI @@ -139,7 +139,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Linux Unelevated Others @@ -157,7 +157,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Linux Elevated Others @@ -181,7 +181,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -255,7 +255,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Linux Packaging diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 721077a6b70..60596c75ed7 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -56,7 +56,7 @@ jobs: buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Change Detection id: filter @@ -71,7 +71,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Build @@ -85,7 +85,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -103,7 +103,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -121,7 +121,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -139,7 +139,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -166,7 +166,7 @@ jobs: - macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - uses: actions/setup-dotnet@v5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3f5951951e1..8df06cd9f14 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml index b26539eb0cf..df37ba3c513 100644 --- a/.github/workflows/verify-markdown-links.yml +++ b/.github/workflows/verify-markdown-links.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Verify markdown links id: verify diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 4f774fcdc9b..92bbf2f4c9e 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -60,7 +60,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Change Detection id: filter @@ -75,7 +75,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Build @@ -89,7 +89,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Windows Unelevated CI @@ -107,7 +107,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Windows Elevated CI @@ -125,7 +125,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Windows Unelevated Others @@ -143,7 +143,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 - name: Windows Elevated Others diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 1f03aaf5944..f3a46cae908 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index efd05b76045..940e1cb839c 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -20,7 +20,7 @@ jobs: runs-on: ${{ inputs.runner_os }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 1000 From 8948c417c0ceb0a4f954b51599294ac06881eb5b Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Sat, 22 Nov 2025 16:38:35 +0900 Subject: [PATCH 216/378] Make Export-Csv -Append and -NoHeader mutually exclusive (#26472) --- .../commands/utility/CsvCommands.cs | 8 ++++++++ .../resources/CsvCommandStrings.resx | 3 +++ .../Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index fa49c33d2ab..e84a79b99b6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -270,6 +270,14 @@ protected override void BeginProcessing() this.ThrowTerminatingError(errorRecord); } + // Validate that Append and NoHeader are not specified together. + if (Append && NoHeader) + { + InvalidOperationException exception = new(CsvCommandStrings.CannotSpecifyAppendAndNoHeader); + ErrorRecord errorRecord = new(exception, "CannotSpecifyBothAppendAndNoHeader", ErrorCategory.InvalidData, null); + this.ThrowTerminatingError(errorRecord); + } + _shouldProcess = ShouldProcess(Path); if (!_shouldProcess) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx index 0eff0d6f84f..8c5ded13465 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx @@ -157,4 +157,7 @@ EOF is reached. + + You must specify either the -Append or -NoHeader parameters, but not both. + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 index db5c6aff9e3..ea05d66d392 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 @@ -187,6 +187,10 @@ Describe "Export-Csv" -Tags "CI" { $results[1].PSObject.properties.Name | Should -Not -Contain 'third' } + It "Should throw when -Append and -NoHeader are specified together" { + { $P1 | Export-Csv -Path $testCsv -Append -NoHeader -ErrorAction Stop } | Should -Throw -ErrorId "CannotSpecifyBothAppendAndNoHeader,Microsoft.PowerShell.Commands.ExportCsvCommand" + } + It "First line should be #TYPE if -IncludeTypeInformation used and pstypenames object property is empty" { $object = [PSCustomObject]@{first = 1} $pstypenames = $object.pstypenames | ForEach-Object -Process {$_} From 70a6a80f6b88e5488b364fb077fd238b9085f6f1 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Sat, 22 Nov 2025 22:28:27 +0900 Subject: [PATCH 217/378] Add -Extension parameter to Join-Path cmdlet (#26482) --- .../commands/management/CombinePathCommand.cs | 21 ++++ .../Join-Path.Tests.ps1 | 98 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs index 71ef5df8f08..79b1c862bfd 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs @@ -51,6 +51,21 @@ public class JoinPathCommand : CoreCommandWithCredentialsBase [Parameter] public SwitchParameter Resolve { get; set; } + /// + /// Gets or sets the extension to use for the resulting path. + /// If not specified, the original extension (if any) is preserved. + /// + /// Behavior: + /// - If the path has an existing extension, it will be replaced with the specified extension. + /// - If the path does not have an extension, the specified extension will be added. + /// - If an empty string is provided, any existing extension will be removed. + /// - A leading dot in the extension is optional; if omitted, one will be added automatically. + /// + /// + [Parameter(ValueFromPipelineByPropertyName = true)] + [ValidateNotNull] + public string Extension { get; set; } + #endregion Parameters #region Command code @@ -128,6 +143,12 @@ protected override void ProcessRecord() continue; } + // If Extension parameter is present it is not null due to [ValidateNotNull]. + if (Extension is not null) + { + joinedPath = System.IO.Path.ChangeExtension(joinedPath, Extension.Length == 0 ? null : Extension); + } + if (Resolve) { // Resolve the paths. The default API (GetResolvedPSPathFromPSPath) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Join-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Join-Path.Tests.ps1 index a66bddd5e4f..9b0898fee90 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Join-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Join-Path.Tests.ps1 @@ -84,4 +84,102 @@ Describe "Join-Path cmdlet tests" -Tags "CI" { $result = Join-Path -Path $Path -ChildPath $ChildPath $result | Should -BeExactly $ExpectedResult } + It "should handle extension parameter: " -TestCases @( + @{ + TestName = "change extension" + ChildPath = "file.txt" + Extension = ".log" + ExpectedChildPath = "file.log" + } + @{ + TestName = "add extension to file without extension" + ChildPath = "file" + Extension = ".txt" + ExpectedChildPath = "file.txt" + } + @{ + TestName = "extension without leading dot" + ChildPath = "file.txt" + Extension = "log" + ExpectedChildPath = "file.log" + } + @{ + TestName = "double extension with dot" + ChildPath = "file.txt" + Extension = ".tar.gz" + ExpectedChildPath = "file.tar.gz" + } + @{ + TestName = "double extension without dot" + ChildPath = "file.txt" + Extension = "tar.gz" + ExpectedChildPath = "file.tar.gz" + } + @{ + TestName = "remove extension with empty string" + ChildPath = "file.txt" + Extension = "" + ExpectedChildPath = "file" + } + @{ + TestName = "preserve dots in base name when removing extension with empty string" + ChildPath = "file...txt" + Extension = "" + ExpectedChildPath = "file.." + } + @{ + TestName = "replace only the last extension for files with multiple dots" + ChildPath = "file.backup.txt" + Extension = ".log" + ExpectedChildPath = "file.backup.log" + } + @{ + TestName = "preserve dots in base name when changing extension" + ChildPath = "file...txt" + Extension = ".md" + ExpectedChildPath = "file...md" + } + @{ + TestName = "add extension to directory-like path" + ChildPath = "subfolder" + Extension = ".log" + ExpectedChildPath = "subfolder.log" + } + ) { + param($TestName, $ChildPath, $Extension, $ExpectedChildPath) + $result = Join-Path -Path "folder" -ChildPath $ChildPath -Extension $Extension + $result | Should -BeExactly "folder${SepChar}${ExpectedChildPath}" + } + It "should handle extension parameter with multiple child path segments: " -TestCases @( + @{ + TestName = "change extension when joining multiple child path segments" + ChildPaths = @("subfolder", "file.txt") + Extension = ".log" + ExpectedPath = "folder${SepChar}subfolder${SepChar}file.log" + } + ) { + param($TestName, $ChildPaths, $Extension, $ExpectedPath) + $result = Join-Path -Path "folder" -ChildPath $ChildPaths -Extension $Extension + $result | Should -BeExactly $ExpectedPath + } + It "should change extension for multiple paths" { + $result = Join-Path -Path "folder1", "folder2" -ChildPath "file.txt" -Extension ".log" + $result.Count | Should -Be 2 + $result[0] | Should -BeExactly "folder1${SepChar}file.log" + $result[1] | Should -BeExactly "folder2${SepChar}file.log" + } + It "should resolve path when -Extension changes to existing file" { + New-Item -Path TestDrive:\testfile.log -ItemType File -Force | Out-Null + $result = Join-Path -Path TestDrive: -ChildPath "testfile.txt" -Extension ".log" -Resolve + $result | Should -BeLike "*testfile.log" + } + It "should throw error when -Extension changes to non-existing file with -Resolve" { + { Join-Path -Path TestDrive: -ChildPath "testfile.txt" -Extension ".nonexistent" -Resolve -ErrorAction Stop; Throw "Previous statement unexpectedly succeeded..." } | + Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.JoinPathCommand" + } + It "should accept Extension from pipeline by property name" { + $obj = [PSCustomObject]@{ Path = "folder"; ChildPath = "file.txt"; Extension = ".log" } + $result = $obj | Join-Path + $result | Should -BeExactly "folder${SepChar}file.log" + } } From 9ee3c61c26f63070ba72b7303384db7956137aa3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 24 Nov 2025 12:05:03 -0800 Subject: [PATCH 218/378] Close pipe client handles after creating the child ssh process (#26491) --- .../remoting/common/RunspaceConnectionInfo.cs | 34 +++++++++---------- .../fanin/OutOfProcTransportManager.cs | 8 ++--- .../Remoting/SSHRemotingCmdlets.Tests.ps1 | 21 ++++++++++++ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index b6913e0cc1c..242bde2ac53 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2211,11 +2211,11 @@ internal int StartSSHProcess( CommandTypes.Application, SearchResolutionOptions.None, CommandOrigin.Internal, - context) as ApplicationInfo; + context); - if (cmdInfo != null) + if (cmdInfo is ApplicationInfo appInfo) { - filePath = cmdInfo.Path; + filePath = appInfo.Path; } } else @@ -2273,13 +2273,13 @@ internal int StartSSHProcess( // Subsystem powershell /usr/local/bin/pwsh -SSHServerMode -NoLogo -NoProfile // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified, so any file executed in the runspace would be in the user's local system/process or a system they have access to in which case restricted remoting security guidelines should be used. - System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(filePath); + ProcessStartInfo startInfo = new(filePath); // pass "-i identity_file" command line argument to ssh if KeyFilePath is set // if KeyFilePath is not set, then ssh will use IdentityFile / IdentityAgent from ssh_config if defined else none by default if (!string.IsNullOrEmpty(this.KeyFilePath)) { - if (!System.IO.File.Exists(this.KeyFilePath)) + if (!File.Exists(this.KeyFilePath)) { throw new FileNotFoundException( StringUtil.Format(RemotingErrorIdStrings.KeyFileNotFound, this.KeyFilePath)); @@ -2326,7 +2326,7 @@ internal int StartSSHProcess( // note that ssh expects IPv6 addresses to not be enclosed in square brackets so trim them if present startInfo.ArgumentList.Add(string.Create(CultureInfo.InvariantCulture, $@"-s {this.ComputerName.TrimStart('[').TrimEnd(']')} {this.Subsystem}")); - startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(filePath); + startInfo.WorkingDirectory = Path.GetDirectoryName(filePath); startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; @@ -2580,7 +2580,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr // Allocate the unmanaged array to hold each string pointer. // It needs to have an extra element to null terminate the array. arrPtr = (byte**)Marshal.AllocHGlobal(sizeof(IntPtr) * arrLength); - System.Diagnostics.Debug.Assert(arrPtr != null, "Invalid array ptr"); + Debug.Assert(arrPtr != null, "Invalid array ptr"); // Zero the memory so that if any of the individual string allocations fails, // we can loop through the array to free any that succeeded. @@ -2597,7 +2597,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr byte[] byteArr = System.Text.Encoding.UTF8.GetBytes(arr[i]); arrPtr[i] = (byte*)Marshal.AllocHGlobal(byteArr.Length + 1); // +1 for null termination - System.Diagnostics.Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); + Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); Marshal.Copy(byteArr, 0, (IntPtr)arrPtr[i], byteArr.Length); // copy over the data from the managed byte array arrPtr[i][byteArr.Length] = (byte)'\0'; // null terminate @@ -2641,13 +2641,13 @@ internal static extern unsafe int ForkAndExecProcess( /// P-Invoking native APIs. /// private static int StartSSHProcessImpl( - System.Diagnostics.ProcessStartInfo startInfo, + ProcessStartInfo startInfo, out StreamWriter stdInWriterVar, out StreamReader stdOutReaderVar, out StreamReader stdErrReaderVar) { Exception ex = null; - System.Diagnostics.Process sshProcess = null; + Process sshProcess = null; // // These std pipe handles are bound to managed Reader/Writer objects and returned to the transport // manager object, which uses them for PSRP communication. The lifetime of these handles are then @@ -2668,7 +2668,7 @@ private static int StartSSHProcessImpl( catch (InvalidOperationException e) { ex = e; } catch (ArgumentException e) { ex = e; } catch (FileNotFoundException e) { ex = e; } - catch (System.ComponentModel.Win32Exception e) { ex = e; } + catch (Win32Exception e) { ex = e; } if ((ex != null) || (sshProcess == null) || @@ -2693,9 +2693,9 @@ private static int StartSSHProcessImpl( { if (stdInWriterVar != null) { stdInWriterVar.Dispose(); } else { stdInPipeServer.Dispose(); } - if (stdOutReaderVar != null) { stdInWriterVar.Dispose(); } else { stdOutPipeServer.Dispose(); } + if (stdOutReaderVar != null) { stdOutReaderVar.Dispose(); } else { stdOutPipeServer.Dispose(); } - if (stdErrReaderVar != null) { stdInWriterVar.Dispose(); } else { stdErrPipeServer.Dispose(); } + if (stdErrReaderVar != null) { stdErrReaderVar.Dispose(); } else { stdErrPipeServer.Dispose(); } throw; } @@ -2705,7 +2705,7 @@ private static int StartSSHProcessImpl( private static void KillSSHProcessImpl(int pid) { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(pid)) + using (var sshProcess = Process.GetProcessById(pid)) { if ((sshProcess != null) && (sshProcess.Handle != IntPtr.Zero) && !sshProcess.HasExited) { @@ -2736,7 +2736,7 @@ private static Process CreateProcessWithRedirectedStd( SafeFileHandle stdInPipeClient = null; SafeFileHandle stdOutPipeClient = null; SafeFileHandle stdErrPipeClient = null; - string randomName = System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName()); + string randomName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); try { @@ -2829,16 +2829,14 @@ private static Process CreateProcessWithRedirectedStd( catch (Exception) { stdInPipeServer?.Dispose(); - stdInPipeClient?.Dispose(); stdOutPipeServer?.Dispose(); - stdOutPipeClient?.Dispose(); stdErrPipeServer?.Dispose(); - stdErrPipeClient?.Dispose(); throw; } finally { + lpStartupInfo.Dispose(); lpProcessInformation.Dispose(); } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index d9532c8691a..47ff6270dba 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1733,7 +1733,7 @@ public override void CreateAsync() bool sshTerminated = false; try { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(_sshProcessId)) + using (var sshProcess = Process.GetProcessById(_sshProcessId)) { sshTerminated = sshProcess == null || sshProcess.Handle == IntPtr.Zero || sshProcess.HasExited; } @@ -1847,7 +1847,7 @@ private void ProcessErrorThread(object state) // Messages in error stream from ssh are unreliable, and may just be warnings or // banner text. // So just report the messages but don't act on them. - System.Console.WriteLine(error); + Console.WriteLine(error); } catch (IOException) { } @@ -1907,10 +1907,10 @@ private void ProcessReaderThread(object state) break; } - if (data.StartsWith(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) + if (data.StartsWith(OutOfProcessTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) { // Error message from the server. - string errorData = data.Substring(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix.Length); + string errorData = data.Substring(OutOfProcessTextWriter.ErrorPrefix.Length); HandleErrorDataReceived(errorData); } else diff --git a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 index 1568d284d0f..c1090bdc186 100644 --- a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 @@ -70,3 +70,24 @@ Describe "SSHConnection parameter hashtable type conversions" -Tags 'Feature', ' $err.FullyQualifiedErrorId | Should -Match 'PSSessionOpenFailed' } } + +Describe "No hangs when host doesn't exist" -Tags "CI" { + $testCases = @( + @{ + Name = 'Verifies no hang for New-PSSession with non-existing host name' + ScriptBlock = { New-PSSession -HostName "test-notexist" -UserName "test" -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionOpenFailed' + }, + @{ + Name = 'Verifies no hang for Invoke-Command with non-existing host name' + ScriptBlock = { Invoke-Command -HostName "test-notexist" -UserName "test" -ScriptBlock { 1 } -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionStateBroken' + } + ) + + It "" -TestCases $testCases { + param ($ScriptBlock, $FullyQualifiedErrorId) + + $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -ExceptionType 'System.Management.Automation.Remoting.PSRemotingTransportException' + } +} From eb2ead439a9d2f7366ef0fb5cad26235a77c8805 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 24 Nov 2025 14:38:23 -0800 Subject: [PATCH 219/378] Fix formatting to properly handle the `Reset` VT sequences that appear in the middle of a string (#26424) --- .../FormatAndOutput/common/ComplexWriter.cs | 37 +++++++-- .../FormatAndOutput/common/ListWriter.cs | 2 +- .../engine/Formatting/PSStyle.Tests.ps1 | 81 ++++++++++++++++++- 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/ComplexWriter.cs b/src/System.Management.Automation/FormatAndOutput/common/ComplexWriter.cs index 61a3f962daf..a69ad41c965 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/ComplexWriter.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/ComplexWriter.cs @@ -9,7 +9,6 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Text; -using System.Text.RegularExpressions; namespace Microsoft.PowerShell.Commands.Internal.Format { @@ -317,6 +316,7 @@ internal struct GetWordsResult { internal string Word; internal string Delim; + internal bool VtResetAdded; } /// @@ -367,9 +367,19 @@ private static IEnumerable GetWords(string s) { var vtSpan = s.AsSpan(i, len); sb.Append(vtSpan); - vtSeqs.Append(vtSpan); - wordHasVtSeqs = true; + if (vtSpan.SequenceEqual(PSStyle.Instance.Reset)) + { + // The Reset sequence will void all previous VT sequences. + vtSeqs.Clear(); + wordHasVtSeqs = false; + } + else + { + vtSeqs.Append(vtSpan); + wordHasVtSeqs = true; + } + i += len - 1; continue; } @@ -390,15 +400,18 @@ private static IEnumerable GetWords(string s) if (delimiter is not null) { + bool vtResetAdded = false; if (wordHasVtSeqs && !sb.EndsWith(PSStyle.Instance.Reset)) { + vtResetAdded = true; sb.Append(PSStyle.Instance.Reset); } var result = new GetWordsResult() { Word = sb.ToString(), - Delim = delimiter + Delim = delimiter, + VtResetAdded = vtResetAdded }; sb.Clear().Append(vtSeqs); @@ -611,7 +624,7 @@ private static StringCollection GenerateLinesWithWordWrap(DisplayCells displayCe if (suffix is not null) { - wordToAdd = wordToAdd.EndsWith(resetStr) + wordToAdd = word.VtResetAdded ? wordToAdd.Insert(wordToAdd.Length - resetStr.Length, suffix) : wordToAdd + suffix; } @@ -760,9 +773,19 @@ internal static List SplitLines(string s) { var vtSpan = s.AsSpan(i, len); sb.Append(vtSpan); - vtSeqs.Append(vtSpan); - hasVtSeqs = true; + if (vtSpan.SequenceEqual(PSStyle.Instance.Reset)) + { + // The Reset sequence will void all previous VT sequences. + vtSeqs.Clear(); + hasVtSeqs = false; + } + else + { + vtSeqs.Append(vtSpan); + hasVtSeqs = true; + } + i += len - 1; continue; } diff --git a/src/System.Management.Automation/FormatAndOutput/common/ListWriter.cs b/src/System.Management.Automation/FormatAndOutput/common/ListWriter.cs index 7598c6b2797..988b1133748 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/ListWriter.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/ListWriter.cs @@ -259,7 +259,7 @@ private void WriteSingleLineHelper(string prependString, string line, LineOutput _cachedBuilder.Append(headPadding).Append(str); } - if (str.Contains(ValueStringDecorated.ESC) && !str.EndsWith(reset)) + if (str.Contains(ValueStringDecorated.ESC) && !str.AsSpan().TrimEnd().EndsWith(reset, StringComparison.Ordinal)) { _cachedBuilder.Append(reset); } diff --git a/test/powershell/engine/Formatting/PSStyle.Tests.ps1 b/test/powershell/engine/Formatting/PSStyle.Tests.ps1 index d8a124a2332..18baed17dd2 100644 --- a/test/powershell/engine/Formatting/PSStyle.Tests.ps1 +++ b/test/powershell/engine/Formatting/PSStyle.Tests.ps1 @@ -488,7 +488,7 @@ Billy Bob… Senior DevOps … 13 $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") } - It "Word wrapping for string with escape sequences" { + It "Word wrapping for string with escape sequences (1)" { $expected = @" `e[32;1mLongDescription : `e[0m`e[33mPowerShell `e[0m `e[33mscripting `e[0m @@ -501,7 +501,46 @@ Billy Bob… Senior DevOps … 13 $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") } - It "Splitting multi-line string with escape sequences" { + It "Word wrapping for string with escape sequences (2)" { + $expected = @" +`e[32;1mLongDescription : `e[0m`e[33mPowerShell`e[0m + scripting + language +"@ + $obj = [pscustomobject] @{ LongDescription = "`e[33mPowerShell`e[0m scripting language" } + $obj | Format-List | Out-String -Width 35 | Out-File $outFile + + $text = Get-Content $outFile -Raw + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } + + It "Word wrapping for string with escape sequences (3)" { + $expected = @" +`e[32;1mLongDescription : `e[0m`e[33mPowerShell`e[0m + `e[32mscripting `e[0m + `e[32mlanguage`e[0m +"@ + $obj = [pscustomobject] @{ LongDescription = "`e[33mPowerShell`e[0m `e[32mscripting language" } + $obj | Format-List | Out-String -Width 35 | Out-File $outFile + + $text = Get-Content $outFile -Raw + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } + + It "Word wrapping for string with escape sequences (4)" { + $expected = @" +`e[32;1mLongDescription : `e[0m`e[33mPowerShell`e[0m + `e[32mscripting`e[0m + language +"@ + $obj = [pscustomobject] @{ LongDescription = "`e[33mPowerShell`e[0m `e[32mscripting`e[0m language" } + $obj | Format-List | Out-String -Width 35 | Out-File $outFile + + $text = Get-Content $outFile -Raw + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } + + It "Splitting multi-line string with escape sequences (1)" { $expected = @" `e[32;1mb : `e[0m`e[33mPowerShell is a task automation and configuration management program from Microsoft,`e[0m `e[33mconsisting of a command-line shell and the associated scripting language`e[0m @@ -513,6 +552,30 @@ Billy Bob… Senior DevOps … 13 $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") } + It "Splitting multi-line string with escape sequences (2)" { + $expected = @" +`e[32;1mb : `e[0m`e[33mPowerShell is a task automation and configuration management program from Microsoft,`e[0m + consisting of a command-line shell and the associated scripting language +"@ + $obj = [pscustomobject] @{ b = "`e[33mPowerShell is a task automation and configuration management program from Microsoft,`e[0m`nconsisting of a command-line shell and the associated scripting language" } + $obj | Format-List | Out-File $outFile + + $text = Get-Content $outFile -Raw + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } + + It "Splitting multi-line string with escape sequences (3)" { + $expected = @" +`e[32;1mb : `e[0m`e[33mPowerShell is a task automation and configuration management program from Microsoft,`e[0m + `e[32mconsisting of a command-line shell and the associated scripting language`e[0m +"@ + $obj = [pscustomobject] @{ b = "`e[33mPowerShell is a task automation and configuration management program from Microsoft,`e[0m`n`e[32mconsisting of a command-line shell and the associated scripting language" } + $obj | Format-List | Out-File $outFile + + $text = Get-Content $outFile -Raw + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } + It "Wrapping long word with escape sequences" { $expected = @" `e[32;1mb : `e[0m`e[33mC:\repos\PowerShell\src\powershell-w`e[0m @@ -525,4 +588,18 @@ Billy Bob… Senior DevOps … 13 $text = Get-Content $outFile -Raw $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") } + + It "Format 'MatchInfo' object correctly" { + $expected = @" +`e[32;1mb : `e[0mmouclass `e[7mMouse`e[0m Class Driver Mouse Class Driver Kernel Manual Running OK TRUE FALSE 12,288 `e[0m + 32,768 0 C:\WINDOWS\system32\drivers\mouclass.sys 4,096 +"@ + + ## This string mimics the VT decorated string for a 'MatchInfo' object that matches the word 'mouse'. + $str = "mouclass `e[7mMouse`e[0m Class Driver Mouse Class Driver Kernel Manual Running OK TRUE FALSE 12,288 32,768 0 C:\WINDOWS\system32\drivers\mouclass.sys 4,096" + $obj = [pscustomobject] @{ b = $str } + $text = $obj | Format-List | Out-String -Width 150 + + $text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") + } } From b9ff1da7fc2250c247b9a2283a2fb7ed8dae9281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:33:46 -0800 Subject: [PATCH 220/378] Bump github/codeql-action from 4.31.4 to 4.31.5 (#26527) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index c1d812e533a..8f4b31ac47a 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 + uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 + uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 8df06cd9f14..68eb0ea4b99 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v3.29.5 + uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 with: sarif_file: results.sarif From 01e36432fcfb3e5a0b801817a35ec5332ff7a199 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Wed, 26 Nov 2025 15:48:53 +0900 Subject: [PATCH 221/378] Add tab completion for $PSBoundParameters.Keys switch cases and access patterns (#26483) --- .../CommandCompletion/CompletionAnalysis.cs | 262 +++++++++++++++++- .../TabCompletion/TabCompletion.Tests.ps1 | 181 ++++++++++++ 2 files changed, 437 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs index 8aafa939d84..a6b6f4170b3 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs @@ -251,8 +251,7 @@ private static bool CompleteAgainstSwitchFile(Ast lastAst, Token tokenBeforeCurs { Tuple fileConditionTuple; - var errorStatement = lastAst as ErrorStatementAst; - if (errorStatement != null && errorStatement.Flags != null && errorStatement.Kind != null && tokenBeforeCursor != null && + if (lastAst is ErrorStatementAst errorStatement && errorStatement.Flags is not null && errorStatement.Kind is not null && tokenBeforeCursor is not null && errorStatement.Kind.Kind.Equals(TokenKind.Switch) && errorStatement.Flags.TryGetValue("file", out fileConditionTuple)) { // Handle "switch -file " @@ -267,19 +266,234 @@ private static bool CompleteAgainstSwitchFile(Ast lastAst, Token tokenBeforeCurs return false; } - errorStatement = pipeline.Parent as ErrorStatementAst; - if (errorStatement == null || errorStatement.Kind == null || errorStatement.Flags == null) + if (pipeline.Parent is not ErrorStatementAst parentErrorStatement || parentErrorStatement.Kind is null || parentErrorStatement.Flags is null) { return false; } - return (errorStatement.Kind.Kind.Equals(TokenKind.Switch) && - errorStatement.Flags.TryGetValue("file", out fileConditionTuple) && fileConditionTuple.Item2 == pipeline); + return (parentErrorStatement.Kind.Kind.Equals(TokenKind.Switch) && + parentErrorStatement.Flags.TryGetValue("file", out fileConditionTuple) && fileConditionTuple.Item2 == pipeline); } return false; } + /// + /// Check if we should complete parameter names for switch cases on $PSBoundParameters.Keys + /// + private static List CompleteAgainstSwitchCaseCondition(CompletionContext completionContext) + { + var lastAst = completionContext.RelatedAsts.Last(); + + PipelineAst conditionPipeline = null; + Ast switchAst = null; + + // Check if we're in a switch statement (complete) or error statement (incomplete switch) + if (lastAst.Parent is SwitchStatementAst switchStatementAst) + { + // Verify that the lastAst is one of the clause conditions (not in the body) + bool isClauseCondition = switchStatementAst.Clauses.Any(clause => clause.Item1 == lastAst); + + if (!isClauseCondition) + { + return null; + } + + conditionPipeline = switchStatementAst.Condition as PipelineAst; + switchAst = switchStatementAst; + } + else + { + // Check for incomplete switch parsed as ErrorStatementAst + if (lastAst.Parent is not ErrorStatementAst errorStatementAst || errorStatementAst.Kind is null || + errorStatementAst.Kind.Kind != TokenKind.Switch) + { + return null; + } + + // For ErrorStatementAst, the case value is in Bodies, condition is in Conditions + bool isInBodies = errorStatementAst.Bodies != null && errorStatementAst.Bodies.Any(body => body == lastAst); + + if (!isInBodies) + { + return null; + } + + // Get the condition from ErrorStatementAst.Conditions + if (errorStatementAst.Conditions != null && errorStatementAst.Conditions.Count > 0) + { + conditionPipeline = errorStatementAst.Conditions[0] as PipelineAst; + } + switchAst = errorStatementAst; + } + + if (conditionPipeline == null || conditionPipeline.PipelineElements.Count != 1) + { + return null; + } + + if (conditionPipeline.PipelineElements[0] is not CommandExpressionAst commandExpressionAst) + { + return null; + } + + // Check if the expression is a member access on $PSBoundParameters.Keys + if (commandExpressionAst.Expression is not MemberExpressionAst memberExpressionAst) + { + return null; + } + + // Check if the target is $PSBoundParameters + if (memberExpressionAst.Expression is not VariableExpressionAst variableExpressionAst || + !variableExpressionAst.VariablePath.UserPath.Equals("PSBoundParameters", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + // Check if the member is "Keys" + if (memberExpressionAst.Member is not StringConstantExpressionAst memberNameAst || + !memberNameAst.Value.Equals("Keys", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + // Find the nearest param block by traversing up the AST + var paramBlockAst = FindNearestParamBlock(switchAst.Parent); + + if (paramBlockAst == null || paramBlockAst.Parameters.Count == 0) + { + return null; + } + + // Generate completion results from parameter names + var wordToComplete = completionContext.WordToComplete ?? string.Empty; + return CreateParameterCompletionResults(paramBlockAst, wordToComplete); + } + + /// + /// Check if we should complete parameter names for $PSBoundParameters access patterns + /// Supports: $PSBoundParameters.ContainsKey('...'), $PSBoundParameters['...'], $PSBoundParameters.Remove('...') + /// + private static List CompleteAgainstPSBoundParametersAccess(CompletionContext completionContext) + { + var lastAst = completionContext.RelatedAsts.Last(); + + // Must be a string constant + if (lastAst is not StringConstantExpressionAst stringAst) + { + return null; + } + + ExpressionAst targetAst = null; + + // Check for method invocation: $PSBoundParameters.ContainsKey('...') or $PSBoundParameters.Remove('...') + if (lastAst.Parent is InvokeMemberExpressionAst invokeMemberAst) + { + if (invokeMemberAst.Member is StringConstantExpressionAst memberName && + (memberName.Value.Equals("ContainsKey", StringComparison.OrdinalIgnoreCase) || + memberName.Value.Equals("Remove", StringComparison.OrdinalIgnoreCase))) + { + targetAst = invokeMemberAst.Expression; + } + } + // Check for indexer: $PSBoundParameters['...'] + else if (lastAst.Parent is IndexExpressionAst indexAst) + { + targetAst = indexAst.Target; + } + + if (targetAst is null) + { + return null; + } + + // Check if target is $PSBoundParameters + if (targetAst is not VariableExpressionAst variableAst || + !variableAst.VariablePath.UserPath.Equals("PSBoundParameters", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + // Find the nearest param block + var paramBlockAst = FindNearestParamBlock(lastAst.Parent); + + if (paramBlockAst == null || paramBlockAst.Parameters.Count == 0) + { + return null; + } + + // Generate completion results from parameter names + var wordToComplete = completionContext.WordToComplete ?? string.Empty; + + // Determine quote style based on the string constant type + string quoteChar = string.Empty; + if (stringAst.StringConstantType == StringConstantType.SingleQuoted) + { + quoteChar = "'"; + } + else if (stringAst.StringConstantType == StringConstantType.DoubleQuoted) + { + quoteChar = "\""; + } + + return CreateParameterCompletionResults(paramBlockAst, wordToComplete, quoteChar); + } + + /// + /// Finds the nearest ParamBlockAst by traversing up the AST hierarchy. + /// + /// The AST node to start searching from. + /// The nearest ParamBlockAst if found; otherwise, null. + private static ParamBlockAst FindNearestParamBlock(Ast startAst) + { + Ast current = startAst; + while (current != null) + { + if (current is FunctionDefinitionAst functionDefinitionAst) + { + return functionDefinitionAst.Body?.ParamBlock; + } + else if (current is ScriptBlockAst scriptBlockAst) + { + var paramBlock = scriptBlockAst.ParamBlock; + if (paramBlock != null) + { + return paramBlock; + } + } + + current = current.Parent; + } + + return null; + } + + /// + /// Creates completion results from parameter names with optional quote wrapping. + /// + /// The parameter block containing parameters to complete. + /// The partial word to match against parameter names. + /// Optional quote character to wrap completion text (empty string for no quotes). + /// A list of completion results, or null if no matches found. + private static List CreateParameterCompletionResults( + ParamBlockAst paramBlockAst, + string wordToComplete, + string quoteChar = "") + { + var result = paramBlockAst.Parameters + .Select(parameter => parameter.Name.VariablePath.UserPath) + .Where(parameterName => parameterName.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase)) + .Select(parameterName => + new CompletionResult( + quoteChar + parameterName + quoteChar, + parameterName, + CompletionResultType.ParameterValue, + parameterName)) + .ToList(); + + return result.Count > 0 ? result : null; + } + private static bool CompleteOperator(Token tokenAtCursor, Ast lastAst) { if (tokenAtCursor.Kind == TokenKind.Minus) @@ -516,6 +730,13 @@ internal List GetResultHelper(CompletionContext completionCont { // Handles quoted string inside index expression like: $PSVersionTable[""] completionContext.WordToComplete = (tokenAtCursor as StringToken).Value; + // Check for $PSBoundParameters indexer first + var psBoundResult = CompleteAgainstPSBoundParametersAccess(completionContext); + if (psBoundResult != null && psBoundResult.Count > 0) + { + return psBoundResult; + } + return CompletionCompleters.CompleteIndexExpression(completionContext, indexExpressionAst.Target); } @@ -1915,6 +2136,21 @@ private static List GetResultForString(CompletionContext compl string strValue = constantString != null ? constantString.Value : expandableString.Value; + // Check for switch case completion on $PSBoundParameters.Keys + completionContext.WordToComplete = strValue; + var switchCaseResult = CompleteAgainstSwitchCaseCondition(completionContext); + if (switchCaseResult != null && switchCaseResult.Count > 0) + { + return switchCaseResult; + } + + // Check for $PSBoundParameters access patterns (ContainsKey, indexer, Remove) + var psBoundResult = CompleteAgainstPSBoundParametersAccess(completionContext); + if (psBoundResult != null && psBoundResult.Count > 0) + { + return psBoundResult; + } + bool shouldContinue; List result = GetResultForEnumPropertyValueOfDSCResource(completionContext, strValue, ref replacementIndex, ref replacementLength, out shouldContinue); if (!shouldContinue || (result != null && result.Count > 0)) @@ -2076,6 +2312,20 @@ private static List GetResultForIdentifier(CompletionContext c var tokenAtCursorText = tokenAtCursor.Text; completionContext.WordToComplete = tokenAtCursorText; + // Check for switch case completion on $PSBoundParameters.Keys + var switchCaseResult = CompleteAgainstSwitchCaseCondition(completionContext); + if (switchCaseResult != null && switchCaseResult.Count > 0) + { + return switchCaseResult; + } + + // Check for $PSBoundParameters access patterns (ContainsKey, indexer, Remove) + var psBoundResult = CompleteAgainstPSBoundParametersAccess(completionContext); + if (psBoundResult != null && psBoundResult.Count > 0) + { + return psBoundResult; + } + if (lastAst.Parent is BreakStatementAst || lastAst.Parent is ContinueStatementAst) { return CompleteLoopLabel(completionContext); diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index 046d00b442f..f8762a63929 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -4012,4 +4012,185 @@ Describe "WSMan Config Provider tab complete tests" -Tags Feature,RequireAdminOn # https://github.com/PowerShell/PowerShell/issues/4744 # TODO: move to test cases above once working } + + Context "Tab completion for switch cases on `$PSBoundParameters.Keys" { + It "Should complete parameter names in switch case for `$PSBoundParameters.Keys" { + $inputScript = @" +function Test-Func { + param( + [string]`$Param1, + [string]`$Param2, + [int]`$Count + ) + switch (`$PSBoundParameters.Keys) { + P + } +} +"@ + $cursorPosition = $inputScript.IndexOf("P", $inputScript.IndexOf("Keys)")) + 1 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 2 + $completionTexts = $res.CompletionMatches.CompletionText | Sort-Object + $completionTexts[0] | Should -BeExactly "Param1" + $completionTexts[1] | Should -BeExactly "Param2" + } + + It "Should complete all parameter names when prefix matches single param" { + $inputScript = @" +function Test-Func { + param( + [string]`$Name, + [int]`$Value + ) + switch (`$PSBoundParameters.Keys) { + N + } +} +"@ + $cursorPosition = $inputScript.IndexOf("N", $inputScript.IndexOf("Keys)")) + 1 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 1 + $res.CompletionMatches[0].CompletionText | Should -BeExactly "Name" + } + + It "Should complete parameter names in scriptblock param" { + $inputScript = @" +`$sb = { + param( + [string]`$ScriptParam1, + [string]`$ScriptParam2 + ) + switch (`$PSBoundParameters.Keys) { + S + } +} +"@ + $cursorPosition = $inputScript.IndexOf("S", $inputScript.IndexOf("Keys)")) + 1 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 2 + $completionTexts = $res.CompletionMatches.CompletionText | Sort-Object + $completionTexts[0] | Should -BeExactly "ScriptParam1" + $completionTexts[1] | Should -BeExactly "ScriptParam2" + } + } + + Context "Tab completion for `$PSBoundParameters access patterns" { + It "Should complete parameter names for ContainsKey method" { + $inputScript = @" +function Test-Func { + param([string]`$Param1, [string]`$Param2, [int]`$Count) + if (`$PSBoundParameters.ContainsKey('P')) { } +} +"@ + $cursorPosition = $inputScript.IndexOf("'P'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 2 + $completionTexts = $res.CompletionMatches.CompletionText | Sort-Object + $completionTexts[0] | Should -BeExactly "'Param1'" + $completionTexts[1] | Should -BeExactly "'Param2'" + } + + It "Should complete parameter names for indexer access" { + $inputScript = @" +function Test-Func { + param([string]`$Param1, [string]`$Param2, [int]`$Count) + `$value = `$PSBoundParameters['P'] +} +"@ + $cursorPosition = $inputScript.IndexOf("'P'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 2 + $completionTexts = $res.CompletionMatches.CompletionText | Sort-Object + $completionTexts[0] | Should -BeExactly "'Param1'" + $completionTexts[1] | Should -BeExactly "'Param2'" + } + + It "Should complete parameter names for Remove method" { + $inputScript = @" +function Test-Func { + param([string]`$Param1, [string]`$Param2, [int]`$Count) + `$PSBoundParameters.Remove('C') +} +"@ + $cursorPosition = $inputScript.IndexOf("'C'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 1 + $res.CompletionMatches[0].CompletionText | Should -BeExactly "'Count'" + } + + It "Should complete with double quotes when using double-quoted string" { + $inputScript = @" +function Test-Func { + param([string]`$Param1, [string]`$Param2) + if (`$PSBoundParameters.ContainsKey("P")) { } +} +"@ + $cursorPosition = $inputScript.IndexOf('"P"') + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + $res.CompletionMatches | Should -HaveCount 2 + $completionTexts = $res.CompletionMatches.CompletionText | Sort-Object + $completionTexts[0] | Should -BeExactly '"Param1"' + $completionTexts[1] | Should -BeExactly '"Param2"' + } + + It "Should not complete for non-PSBoundParameters variable with indexer" { + $inputScript = @" +function Test-Func { + param([string]`$Param1) + `$hash = @{} + `$value = `$hash['P'] +} +"@ + $cursorPosition = $inputScript.IndexOf("'P'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + # Should not return Param1 as completion + $paramCompletion = $res.CompletionMatches | Where-Object { $_.CompletionText -eq "'Param1'" } + $paramCompletion | Should -BeNullOrEmpty + } + + It "Should not complete for non-PSBoundParameters variable with ContainsKey" { + $inputScript = @" +function Test-Func { + param([string]`$Param1) + `$hash = @{} + if (`$hash.ContainsKey('P')) { } +} +"@ + $cursorPosition = $inputScript.IndexOf("'P'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + # Should not return Param1 as completion + $paramCompletion = $res.CompletionMatches | Where-Object { $_.CompletionText -eq "'Param1'" } + $paramCompletion | Should -BeNullOrEmpty + } + + It "Should not complete for non-PSBoundParameters variable with Remove" { + $inputScript = @" +function Test-Func { + param([string]`$Param1) + `$hash = @{} + `$hash.Remove('P') +} +"@ + $cursorPosition = $inputScript.IndexOf("'P'") + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + # Should not return Param1 as completion + $paramCompletion = $res.CompletionMatches | Where-Object { $_.CompletionText -eq "'Param1'" } + $paramCompletion | Should -BeNullOrEmpty + } + + It "Should not complete for non-PSBoundParameters variable with double quotes" { + $inputScript = @" +function Test-Func { + param([string]`$Param1) + `$hash = @{} + if (`$hash.ContainsKey("P")) { } +} +"@ + $cursorPosition = $inputScript.IndexOf('"P"') + 2 + $res = TabExpansion2 -inputScript $inputScript -cursorColumn $cursorPosition + # Should not return Param1 as completion + $paramCompletion = $res.CompletionMatches | Where-Object { $_.CompletionText -eq '"Param1"' } + $paramCompletion | Should -BeNullOrEmpty + } + } } From ef0f9ae0ba9a67cab954d8d58c9868dd89569939 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:01:52 -0800 Subject: [PATCH 222/378] Bump github/codeql-action from 4.31.5 to 4.31.6 (#26554) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 8f4b31ac47a..21bc1ed1e92 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 + uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 + uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 68eb0ea4b99..3c322397db0 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 + uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 with: sarif_file: results.sarif From 11f91dfee3eeb7445be8680e0e59ef84f2cad2f5 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 3 Dec 2025 08:16:56 +0000 Subject: [PATCH 223/378] Disable AMSI content logging in release (#26235) --- .../engine/runtime/Operations/MiscOps.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index 50054f6501d..d584666ab62 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -3644,6 +3644,7 @@ internal static object[] GetSlice(IList list, int startIndex) internal static class MemberInvocationLoggingOps { +#if DEBUG private static readonly Lazy DumpLogAMSIContent = new Lazy( () => { object result = Environment.GetEnvironmentVariable("__PSDumpAMSILogContent"); @@ -3654,6 +3655,7 @@ internal static class MemberInvocationLoggingOps return false; } ); +#endif private static string ArgumentToString(object arg) { @@ -3708,20 +3710,24 @@ internal static void LogMemberInvocation(string targetName, string name, object[ string content = $"<{targetName}>.{name}({argsBuilder})"; +#if DEBUG if (DumpLogAMSIContent.Value) { Console.WriteLine("\n=== Amsi notification report content ==="); Console.WriteLine(content); } +#endif var success = AmsiUtils.ReportContent( name: contentName, content: content); +#if DEBUG if (DumpLogAMSIContent.Value) { Console.WriteLine($"=== Amsi notification report success: {success} ==="); } +#endif } catch (PSSecurityException) { @@ -3729,12 +3735,16 @@ internal static void LogMemberInvocation(string targetName, string name, object[ // must be propagated. throw; } +#pragma warning disable CS0168 // variable declared but never used catch (Exception ex) +#pragma warning restore CS0168 { +#if DEBUG if (DumpLogAMSIContent.Value) { Console.WriteLine($"!!! Amsi notification report exception: {ex} !!!"); } +#endif } } } From 5c57c3e19c85a03b9b493c14d9f4f6ec7b51bce6 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Wed, 3 Dec 2025 17:35:44 +0900 Subject: [PATCH 224/378] Fix NOTES section formatting in comment-based help (#26512) --- .../DefaultFormatters/Help_format_ps1xml.cs | 5 +--- .../ScriptHelp.NotesFormatting.Tests.ps1 | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 test/powershell/Language/Scripting/ScriptHelp.NotesFormatting.Tests.ps1 diff --git a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/Help_format_ps1xml.cs b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/Help_format_ps1xml.cs index 05f57286026..6825ec14e6c 100644 --- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/Help_format_ps1xml.cs +++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/Help_format_ps1xml.cs @@ -680,10 +680,7 @@ private static IEnumerable ViewsOf_MamlCommandHelpInfo_Ful .StartFrame(leftIndent: 4) .AddPropertyExpressionBinding(@"title") .AddNewline() - .AddNewline() - .StartFrame(leftIndent: 4) - .AddPropertyExpressionBinding(@"alert", enumerateCollection: true, customControl: sharedControls[11]) - .EndFrame() + .AddPropertyExpressionBinding(@"alert", enumerateCollection: true, customControl: sharedControls[11]) .AddNewline() .EndFrame() .EndEntry() diff --git a/test/powershell/Language/Scripting/ScriptHelp.NotesFormatting.Tests.ps1 b/test/powershell/Language/Scripting/ScriptHelp.NotesFormatting.Tests.ps1 new file mode 100644 index 00000000000..77c0c65b1af --- /dev/null +++ b/test/powershell/Language/Scripting/ScriptHelp.NotesFormatting.Tests.ps1 @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'Comment-based help NOTES section formatting' -Tags "CI", "Feature" { + It 'NOTES section should have single blank line after header and 4-space indentation' { + $helpText = Get-Help Remove-PSSession -Full | Out-String + $lines = $helpText -split "`r?`n" + + # Find NOTES section + $notesIndex = -1 + for ($i = 0; $i -lt $lines.Count; $i++) { + if ($lines[$i] -match '^NOTES\s*$') { + $notesIndex = $i + break + } + } + + $notesIndex | Should -BeGreaterThan -1 -Because "NOTES section should exist" + + # The line after NOTES header should be blank + $lines[$notesIndex + 1] | Should -Match '^\s*$' -Because "There should be a blank line after NOTES header" + + # The second line after NOTES header should have content with 4-space indentation + $contentLine = $lines[$notesIndex + 2] + $contentLine | Should -Match '^[ ]{4}\S' -Because "Content should have exactly 4-space indentation" + } +} From 6311c7c2f6aa913408aa6fb2e619cd15c95ebd40 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Fri, 5 Dec 2025 13:54:52 +0900 Subject: [PATCH 225/378] Add -ExcludeProperty parameter to Format-* cmdlets (#26514) --- .../format-object/Format-Object.cs | 32 +++++++++-- .../format-wide/Format-Wide.cs | 35 +++++++++--- .../commands/utility/Select-Object.cs | 41 ------------- .../common/BaseFormattingCommand.cs | 37 ++++++++++-- .../common/BaseFormattingCommandParameters.cs | 5 ++ .../common/FormatViewGenerator.cs | 15 ++++- .../common/FormatViewGenerator_Complex.cs | 22 +++++-- .../common/FormatViewGenerator_List.cs | 8 ++- .../common/FormatViewGenerator_Table.cs | 57 ++++++++++--------- .../common/FormatViewGenerator_Wide.cs | 49 ++++++++-------- .../common/Utilities/Mshexpression.cs | 37 ++++++++++++ .../CommandCompletion/CompletionCompleters.cs | 3 +- .../Format-Custom.Tests.ps1 | 44 ++++++++++++++ .../Format-List.Tests.ps1 | 44 ++++++++++++++ .../Format-Table.Tests.ps1 | 44 ++++++++++++++ .../Format-Wide.Tests.ps1 | 52 +++++++++++++++++ 16 files changed, 401 insertions(+), 124 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs index 2179243279d..c2c16ff2cd1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs @@ -41,6 +41,12 @@ public object[] Property private object[] _props; + /// + /// Gets or sets the properties to exclude from formatting. + /// + [Parameter] + public string[] ExcludeProperty { get; set; } + /// /// /// @@ -61,6 +67,18 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() { FormattingCommandLineParameters parameters = new(); + // Check View conflicts first (before any auto-expansion) + if (!string.IsNullOrEmpty(this.View)) + { + // View cannot be used with Property or ExcludeProperty + if ((_props is not null && _props.Length != 0) || (ExcludeProperty is not null && ExcludeProperty.Length != 0)) + { + ReportCannotSpecifyViewAndProperty(); + } + + parameters.viewName = this.View; + } + if (_props != null) { ParameterProcessor processor = new(new FormatObjectParameterDefinition()); @@ -68,15 +86,17 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() parameters.mshParameterList = processor.ProcessParameters(_props, invocationContext); } - if (!string.IsNullOrEmpty(this.View)) + if (ExcludeProperty is not null) { - // we have a view command line switch - if (parameters.mshParameterList.Count != 0) + parameters.excludePropertyFilter = new PSPropertyExpressionFilter(ExcludeProperty); + + // ExcludeProperty implies -Property * for better UX + if (_props is null || _props.Length == 0) { - ReportCannotSpecifyViewAndProperty(); + ParameterProcessor processor = new(new FormatObjectParameterDefinition()); + TerminatingErrorContext invocationContext = new(this); + parameters.mshParameterList = processor.ProcessParameters(new object[] { "*" }, invocationContext); } - - parameters.viewName = this.View; } parameters.groupByParameter = this.ProcessGroupByParameter(); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs index aeddf498f44..c6aef5c20be 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-wide/Format-Wide.cs @@ -42,9 +42,14 @@ public object Property private object _prop; /// - /// Optional, non positional parameter. + /// Gets or sets the properties to exclude from formatting. + /// + [Parameter] + public string[] ExcludeProperty { get; set; } + + /// + /// Gets or sets a value indicating whether to autosize the output. /// - /// [Parameter] public SwitchParameter AutoSize { @@ -74,6 +79,18 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() { FormattingCommandLineParameters parameters = new(); + // Check View conflicts first (before any auto-expansion) + if (!string.IsNullOrEmpty(this.View)) + { + // View cannot be used with Property or ExcludeProperty + if (_prop is not null || (ExcludeProperty is not null && ExcludeProperty.Length != 0)) + { + ReportCannotSpecifyViewAndProperty(); + } + + parameters.viewName = this.View; + } + if (_prop != null) { ParameterProcessor processor = new(new FormatWideParameterDefinition()); @@ -81,15 +98,17 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() parameters.mshParameterList = processor.ProcessParameters(new object[] { _prop }, invocationContext); } - if (!string.IsNullOrEmpty(this.View)) + if (ExcludeProperty is not null) { - // we have a view command line switch - if (parameters.mshParameterList.Count != 0) + parameters.excludePropertyFilter = new PSPropertyExpressionFilter(ExcludeProperty); + + // ExcludeProperty implies -Property * for better UX + if (_prop is null) { - ReportCannotSpecifyViewAndProperty(); + ParameterProcessor processor = new(new FormatWideParameterDefinition()); + TerminatingErrorContext invocationContext = new(this); + parameters.mshParameterList = processor.ProcessParameters(new object[] { "*" }, invocationContext); } - - parameters.viewName = this.View; } // we cannot specify -column and -autosize, they are mutually exclusive diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs index 9db27335da5..e0b0bff07c5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs @@ -12,47 +12,6 @@ namespace Microsoft.PowerShell.Commands { - /// - /// Helper class to do wildcard matching on PSPropertyExpressions. - /// - internal sealed class PSPropertyExpressionFilter - { - /// - /// Initializes a new instance of the class - /// with the specified array of patterns. - /// - /// Array of pattern strings to use. - internal PSPropertyExpressionFilter(string[] wildcardPatternsStrings) - { - ArgumentNullException.ThrowIfNull(wildcardPatternsStrings); - - _wildcardPatterns = new WildcardPattern[wildcardPatternsStrings.Length]; - for (int k = 0; k < wildcardPatternsStrings.Length; k++) - { - _wildcardPatterns[k] = WildcardPattern.Get(wildcardPatternsStrings[k], WildcardOptions.IgnoreCase); - } - } - - /// - /// Try to match the expression against the array of wildcard patterns. - /// The first match shortcircuits the search. - /// - /// PSPropertyExpression to test against. - /// True if there is a match, else false. - internal bool IsMatch(PSPropertyExpression expression) - { - for (int k = 0; k < _wildcardPatterns.Length; k++) - { - if (_wildcardPatterns[k].IsMatch(expression.ToString())) - return true; - } - - return false; - } - - private readonly WildcardPattern[] _wildcardPatterns; - } - internal sealed class SelectObjectExpressionParameterDefinition : CommandParameterDefinition { protected override void SetEntries() diff --git a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs index 18b74cbcfe1..683553a3b30 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs @@ -9,6 +9,7 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; +using Microsoft.PowerShell.Commands; namespace Microsoft.PowerShell.Commands.Internal.Format { @@ -729,6 +730,12 @@ public class OuterFormatTableAndListBase : OuterFormatShapeCommandBase [Parameter(Position = 0)] public object[] Property { get; set; } + /// + /// Optional parameter for excluding properties from formatting. + /// + [Parameter] + public string[] ExcludeProperty { get; set; } + #endregion internal override FormattingCommandLineParameters GetCommandLineParameters() @@ -751,6 +758,18 @@ internal override FormattingCommandLineParameters GetCommandLineParameters() internal void GetCommandLineProperties(FormattingCommandLineParameters parameters, bool isTable) { + // Check View conflicts first (before any auto-expansion) + if (!string.IsNullOrEmpty(this.View)) + { + // View cannot be used with Property or ExcludeProperty + if ((Property is not null && Property.Length != 0) || (ExcludeProperty is not null && ExcludeProperty.Length != 0)) + { + ReportCannotSpecifyViewAndProperty(); + } + + parameters.viewName = this.View; + } + if (Property != null) { CommandParameterDefinition def; @@ -765,15 +784,21 @@ internal void GetCommandLineProperties(FormattingCommandLineParameters parameter parameters.mshParameterList = processor.ProcessParameters(Property, invocationContext); } - if (!string.IsNullOrEmpty(this.View)) + if (ExcludeProperty is not null) { - // we have a view command line switch - if (parameters.mshParameterList.Count != 0) + parameters.excludePropertyFilter = new PSPropertyExpressionFilter(ExcludeProperty); + + // ExcludeProperty implies -Property * for better UX + if (Property is null || Property.Length == 0) { - ReportCannotSpecifyViewAndProperty(); - } + CommandParameterDefinition def = isTable + ? new FormatTableParameterDefinition() + : new FormatListParameterDefinition(); + ParameterProcessor processor = new ParameterProcessor(def); + TerminatingErrorContext invocationContext = new TerminatingErrorContext(this); - parameters.viewName = this.View; + parameters.mshParameterList = processor.ProcessParameters(new object[] { "*" }, invocationContext); + } } } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommandParameters.cs b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommandParameters.cs index 7f88727ace7..498f6098a24 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommandParameters.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommandParameters.cs @@ -70,6 +70,11 @@ internal sealed class FormattingCommandLineParameters /// Extension mechanism for shape specific parameters. /// internal ShapeSpecificParameters shapeParameters = null; + + /// + /// Filter for excluding properties from formatting. + /// + internal PSPropertyExpressionFilter excludePropertyFilter = null; } /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index db1bc0704aa..cb20e708cc4 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Internal; @@ -348,7 +349,19 @@ protected class DataBaseInfo protected DataBaseInfo dataBaseInfo = new DataBaseInfo(); protected List activeAssociationList = null; - protected FormattingCommandLineParameters inputParameters = null; + /// + /// Apply ExcludeProperty filter to activeAssociationList if specified. + /// This method filters and updates "activeAssociationList" instance property. + /// + protected void ApplyExcludePropertyFilter() + { + if (this.parameters is not null && this.parameters.excludePropertyFilter is not null) + { + this.activeAssociationList = this.activeAssociationList + .Where(item => !this.parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) + .ToList(); + } + } protected string GetExpressionDisplayValue(PSObject so, int enumerationLimit, PSPropertyExpression ex, FieldFormattingDirective directive) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs index b2bbd27c2b9..972a7160830 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Internal; @@ -16,7 +17,6 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper PSObject so, TypeInfoDataBase db, FormattingCommandLineParameters parameters) { base.Initialize(errorContext, expressionFactory, so, db, parameters); - this.inputParameters = parameters; } internal override FormatStartData GenerateStartData(PSObject so) @@ -40,7 +40,7 @@ internal override FormatEntryData GeneratePayload(PSObject so, int enumerationLi private ComplexViewEntry GenerateComplexViewEntryFromProperties(PSObject so, int enumerationLimit) { ComplexViewObjectBrowser browser = new ComplexViewObjectBrowser(this.ErrorManager, this.expressionFactory, enumerationLimit); - return browser.GenerateView(so, this.inputParameters); + return browser.GenerateView(so, this.parameters); } private ComplexViewEntry GenerateComplexViewEntryFromDataBaseInfo(PSObject so, int enumerationLimit) @@ -425,17 +425,18 @@ internal ComplexViewObjectBrowser(FormatErrorManager resultErrorManager, PSPrope /// of the object. /// /// Object to process. - /// Parameters from the command line. + /// Parameters from the command line. /// Complex view entry to send to the output command. - internal ComplexViewEntry GenerateView(PSObject so, FormattingCommandLineParameters inputParameters) + internal ComplexViewEntry GenerateView(PSObject so, FormattingCommandLineParameters parameters) { - _complexSpecificParameters = (ComplexSpecificParameters)inputParameters.shapeParameters; + _parameters = parameters; + _complexSpecificParameters = (ComplexSpecificParameters)parameters.shapeParameters; int maxDepth = _complexSpecificParameters.maxDepth; TraversalInfo level = new TraversalInfo(0, maxDepth); List mshParameterList = null; - mshParameterList = inputParameters.mshParameterList; + mshParameterList = parameters.mshParameterList; // create a top level entry as root of the tree ComplexViewEntry cve = new ComplexViewEntry(); @@ -513,6 +514,14 @@ private void DisplayObject(PSObject so, TraversalInfo currentLevel, List activeAssociationList = AssociationManager.SetupActiveProperties(parameterList, so, _expressionFactory); + // Apply ExcludeProperty filter if specified + if (_parameters != null && _parameters.excludePropertyFilter != null) + { + activeAssociationList = activeAssociationList + .Where(item => !_parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) + .ToList(); + } + // create a format entry FormatEntry fe = new FormatEntry(); formatValueList.Add(fe); @@ -758,6 +767,7 @@ private List AddIndentationLevel(List formatValueList) return feFrame.formatValueList; } + private FormattingCommandLineParameters _parameters; private ComplexSpecificParameters _complexSpecificParameters; /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs index f7acd9ed226..6ef1b24ce14 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs @@ -31,7 +31,7 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper _listBody = (ListControlBody)this.dataBaseInfo.view.mainControl; } - this.inputParameters = parameters; + this.parameters = parameters; SetUpActiveProperties(so); } @@ -227,10 +227,12 @@ private void SetUpActiveProperties(PSObject so) { List mshParameterList = null; - if (this.inputParameters != null) - mshParameterList = this.inputParameters.mshParameterList; + if (this.parameters != null) + mshParameterList = this.parameters.mshParameterList; this.activeAssociationList = AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory); + + ApplyExcludePropertyFilter(); } } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index 0ddc307b646..33d2bd53506 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -40,40 +40,45 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper rawMshParameterList = parameters.mshParameterList; // check if we received properties from the command line - if (rawMshParameterList != null && rawMshParameterList.Count > 0) + if (rawMshParameterList is not null && rawMshParameterList.Count > 0) { this.activeAssociationList = AssociationManager.ExpandTableParameters(rawMshParameterList, so); - return; } - - // we did not get any properties: - // try to get properties from the default property set of the object - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count > 0) + else { - // we got a valid set of properties from the default property set..add computername for - // remoteobjects (if available) - if (PSObjectHelper.ShouldShowComputerNameProperty(so)) + // we did not get any properties: + // try to get properties from the default property set of the object + this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (this.activeAssociationList.Count > 0) { - activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, - new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); + // we got a valid set of properties from the default property set..add computername for + // remoteobjects (if available) + if (PSObjectHelper.ShouldShowComputerNameProperty(so)) + { + activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, + new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); + } + } + else + { + // we failed to get anything from the default property set + this.activeAssociationList = AssociationManager.ExpandAll(so); + if (this.activeAssociationList.Count > 0) + { + // Remove PSComputerName and PSShowComputerName from the display as needed. + AssociationManager.HandleComputerNameProperties(so, activeAssociationList); + FilterActiveAssociationList(); + } + else + { + // we were unable to retrieve any properties, so we leave an empty list + this.activeAssociationList = new List(); + return; + } } - - return; - } - - // we failed to get anything from the default property set - this.activeAssociationList = AssociationManager.ExpandAll(so); - if (this.activeAssociationList.Count > 0) - { - // Remove PSComputerName and PSShowComputerName from the display as needed. - AssociationManager.HandleComputerNameProperties(so, activeAssociationList); - FilterActiveAssociationList(); - return; } - // we were unable to retrieve any properties, so we leave an empty list - this.activeAssociationList = new List(); + ApplyExcludePropertyFilter(); } /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs index 26c0af670c7..a45c006e7fc 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs @@ -13,7 +13,6 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper PSObject so, TypeInfoDataBase db, FormattingCommandLineParameters parameters) { base.Initialize(errorContext, expressionFactory, so, db, parameters); - this.inputParameters = parameters; } internal override FormatStartData GenerateStartData(PSObject so) @@ -159,39 +158,37 @@ private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enume private void SetUpActiveProperty(PSObject so) { - List rawMshParameterList = null; - - if (this.inputParameters != null) - rawMshParameterList = this.inputParameters.mshParameterList; + List rawMshParameterList = this.parameters?.mshParameterList; // check if we received properties from the command line - if (rawMshParameterList != null && rawMshParameterList.Count > 0) + if (rawMshParameterList is not null && rawMshParameterList.Count > 0) { this.activeAssociationList = AssociationManager.ExpandParameters(rawMshParameterList, so); - return; - } - - // we did not get any properties: - // try to get the display property of the object - PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); - if (displayNameExpression != null) - { - this.activeAssociationList = new List(); - this.activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, displayNameExpression)); - return; } - - // try to get the default property set (we will use the first property) - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count > 0) + else { - // we got a valid set of properties from the default property set - return; + // we did not get any properties: + // try to get the display property of the object + PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); + if (displayNameExpression is not null) + { + this.activeAssociationList = new List(); + this.activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, displayNameExpression)); + } + else + { + // try to get the default property set (we will use the first property) + this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (this.activeAssociationList.Count == 0) + { + // we failed to get anything from the default property set + // just get all the properties + this.activeAssociationList = AssociationManager.ExpandAll(so); + } + } } - // we failed to get anything from the default property set - // just get all the properties - this.activeAssociationList = AssociationManager.ExpandAll(so); + ApplyExcludePropertyFilter(); } } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/Utilities/Mshexpression.cs b/src/System.Management.Automation/FormatAndOutput/common/Utilities/Mshexpression.cs index 552d511fd4e..55ee3c30ddb 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/Utilities/Mshexpression.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/Utilities/Mshexpression.cs @@ -375,5 +375,42 @@ private static PSObject IfHashtableWrapAsPSCustomObject(PSObject target, out boo private bool _isResolved = false; #endregion Private Members + + } + + /// + /// Helper class to do wildcard matching on PSPropertyExpressions. + /// + internal sealed class PSPropertyExpressionFilter + { + /// + /// Initializes a new instance of the class + /// with the specified array of patterns. + /// + /// Array of pattern strings to use. + internal PSPropertyExpressionFilter(string[] wildcardPatternsStrings) + { + ArgumentNullException.ThrowIfNull(wildcardPatternsStrings); + + _wildcardPatterns = new WildcardPattern[wildcardPatternsStrings.Length]; + for (int k = 0; k < wildcardPatternsStrings.Length; k++) + { + _wildcardPatterns[k] = WildcardPattern.Get(wildcardPatternsStrings[k], WildcardOptions.IgnoreCase); + } + } + + /// + /// Try to match the expression against the array of wildcard patterns. + /// The first match short-circuits the search. + /// + /// PSPropertyExpression to test against. + /// True if there is a match, else false. + internal bool IsMatch(PSPropertyExpression expression) + { + string expressionString = expression.ToString(); + return _wildcardPatterns.Any(pattern => pattern.IsMatch(expressionString)); + } + + private readonly WildcardPattern[] _wildcardPatterns; } } diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 335a704dd62..73406e449bf 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -2504,7 +2504,8 @@ private static void NativeCommandArgumentCompletion( case "Format-Table": case "Format-Wide": { - if (parameterName.Equals("Property", StringComparison.OrdinalIgnoreCase)) + if (parameterName.Equals("Property", StringComparison.OrdinalIgnoreCase) + || parameterName.Equals("ExcludeProperty", StringComparison.OrdinalIgnoreCase)) { NativeCompletionMemberName(context, result, commandAst, boundArguments?[parameterName]); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Custom.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Custom.Tests.ps1 index 80aad6ef5b9..c82d8b77b8a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Custom.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Custom.Tests.ps1 @@ -466,4 +466,48 @@ SelectScriptBlock $ps.Invoke() -replace '\r?\n', "^" | Should -BeExactly $expectedOutput $ps.Streams.Error | Should -BeNullOrEmpty } + + Context 'ExcludeProperty parameter' { + It 'Should exclude specified properties' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle' } + $result = $obj | Format-Custom -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Not -Match 'Age' + } + + It 'Should work with wildcard patterns' { + $obj = [pscustomobject]@{ Prop1 = 1; Prop2 = 2; Other = 3 } + $result = $obj | Format-Custom -ExcludeProperty Prop* | Out-String + $result | Should -Match 'Other' + $result | Should -Not -Match 'Prop1' + $result | Should -Not -Match 'Prop2' + } + + It 'Should work without Property parameter (implies -Property *)' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3 } + $result = $obj | Format-Custom -ExcludeProperty B | Out-String + $result | Should -Match 'A\s*=' + $result | Should -Match 'C\s*=' + $result | Should -Not -Match 'B\s*=' + } + + It 'Should work with Property parameter' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle'; Country = 'USA' } + $result = $obj | Format-Custom -Property Name, Age, City, Country -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Match 'Country' + $result | Should -Not -Match 'Age' + } + + It 'Should handle multiple excluded properties' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3; D = 4 } + $result = $obj | Format-Custom -ExcludeProperty B, D | Out-String + $result | Should -Match 'A\s*=' + $result | Should -Match 'C\s*=' + $result | Should -Not -Match 'B\s*=' + $result | Should -Not -Match 'D\s*=' + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-List.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-List.Tests.ps1 index b9079b92139..342383f3880 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-List.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-List.Tests.ps1 @@ -261,4 +261,48 @@ Describe 'Format-List color tests' -Tag 'CI' { $output = Get-Content "$TestDrive/outfile.txt" -Raw $output.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "") } + + Context 'ExcludeProperty parameter' { + It 'Should exclude specified properties' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle' } + $result = $obj | Format-List -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Not -Match 'Age' + } + + It 'Should work with wildcard patterns' { + $obj = [pscustomobject]@{ Prop1 = 1; Prop2 = 2; Other = 3 } + $result = $obj | Format-List -ExcludeProperty Prop* | Out-String + $result | Should -Match 'Other' + $result | Should -Not -Match 'Prop1' + $result | Should -Not -Match 'Prop2' + } + + It 'Should work without Property parameter (implies -Property *)' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3 } + $result = $obj | Format-List -ExcludeProperty B | Out-String + $result | Should -Match 'A' + $result | Should -Match 'C' + $result | Should -Not -Match 'B' + } + + It 'Should work with Property parameter' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle'; Country = 'USA' } + $result = $obj | Format-List -Property Name, Age, City, Country -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Match 'Country' + $result | Should -Not -Match 'Age' + } + + It 'Should handle multiple excluded properties' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3; D = 4 } + $result = $obj | Format-List -ExcludeProperty B, D | Out-String + $result | Should -Match 'A' + $result | Should -Match 'C' + $result | Should -Not -Match 'B' + $result | Should -Not -Match 'D' + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 index 34f2245909c..d102ef8bbdf 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 @@ -953,4 +953,48 @@ Describe 'Table color tests' -Tag 'CI' { $actual | Should -BeExactly $expected } + + Context 'ExcludeProperty parameter' { + It 'Should exclude specified properties' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle' } + $result = $obj | Format-Table -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Not -Match 'Age' + } + + It 'Should work with wildcard patterns' { + $obj = [pscustomobject]@{ Prop1 = 1; Prop2 = 2; Other = 3 } + $result = $obj | Format-Table -ExcludeProperty Prop* | Out-String + $result | Should -Match 'Other' + $result | Should -Not -Match 'Prop1' + $result | Should -Not -Match 'Prop2' + } + + It 'Should work without Property parameter (implies -Property *)' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3 } + $result = $obj | Format-Table -ExcludeProperty B | Out-String + $result | Should -Match 'A' + $result | Should -Match 'C' + $result | Should -Not -Match 'B' + } + + It 'Should work with Property parameter' { + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle'; Country = 'USA' } + $result = $obj | Format-Table -Property Name, Age, City, Country -ExcludeProperty Age | Out-String + $result | Should -Match 'Name' + $result | Should -Match 'City' + $result | Should -Match 'Country' + $result | Should -Not -Match 'Age' + } + + It 'Should handle multiple excluded properties' { + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3; D = 4 } + $result = $obj | Format-Table -ExcludeProperty B, D | Out-String + $result | Should -Match 'A' + $result | Should -Match 'C' + $result | Should -Not -Match 'B' + $result | Should -Not -Match 'D' + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Wide.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Wide.Tests.ps1 index c81db9fa1f9..10acd699068 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Wide.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Wide.Tests.ps1 @@ -105,4 +105,56 @@ Describe "Format-Wide DRT basic functionality" -Tags "CI" { $result | Should -Match " GroupingKey:" $result | Should -Match "name2\s+name3" } + + Context 'ExcludeProperty parameter' { + It 'Should exclude specified property and display first remaining' { + # PSCustomObject properties are in definition order: Name, Age, City + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle' } + # Exclude Name, should display Age (first remaining) + $result = $obj | Format-Wide -ExcludeProperty Name | Out-String + $result | Should -Match '30' + $result | Should -Not -Match 'Test' + } + + It 'Should work with wildcard patterns' { + # Properties: Prop1, Prop2, Other + $obj = [pscustomobject]@{ Prop1 = 1; Prop2 = 2; Other = 3 } + # Exclude Prop*, should display Other (only remaining) + $result = $obj | Format-Wide -ExcludeProperty Prop* | Out-String + $result | Should -Match '3' + $result | Should -Not -Match '1' + $result | Should -Not -Match '2' + } + + It 'Should work without Property parameter (implies -Property *)' { + # Properties: A, B, C + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3 } + # Exclude B, C - should display A (first remaining) + $result = $obj | Format-Wide -ExcludeProperty B, C | Out-String + $result | Should -Match '1' + $result | Should -Not -Match '2' + $result | Should -Not -Match '3' + } + + It 'Should display first remaining property after exclusion' { + # Properties: Name, Age, City, Country + $obj = [pscustomobject]@{ Name = 'Test'; Age = 30; City = 'Seattle'; Country = 'USA' } + # Exclude Name and Age, should display City (first remaining) + $result = $obj | Format-Wide -ExcludeProperty Name, Age | Out-String + $result | Should -Match 'Seattle' + $result | Should -Not -Match 'Test' + $result | Should -Not -Match '30' + # USA might appear but not in the wide field, or might not appear at all since only first property is shown + } + + It 'Should handle multiple excluded properties' { + # Properties: A, B, C, D + $obj = [pscustomobject]@{ A = 1; B = 2; C = 3; D = 4 } + # Exclude A and B, should display C (first remaining) + $result = $obj | Format-Wide -ExcludeProperty A, B | Out-String + $result | Should -Match '3' + $result | Should -Not -Match '1' + $result | Should -Not -Match '2' + } + } } From 2a49561af4c92b90d5ada6f7780a8a3dbdb02d32 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 8 Dec 2025 15:14:07 -0800 Subject: [PATCH 226/378] Update `Microsoft.PowerShell.PSResourceGet` to `v1.2.0-preview5` (#26589) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index d2a49e26d2a..b6e5506e0b0 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 235ff058e71d6caca57d1f06ed49de5fe4cdb223 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Thu, 11 Dec 2025 01:22:36 +0900 Subject: [PATCH 227/378] Centralize ExcludeProperty filter application in ViewGenerator base class (#26574) --- .../common/FormatViewGenerator.cs | 46 +++++-- .../common/FormatViewGenerator_Complex.cs | 10 +- .../common/FormatViewGenerator_List.cs | 34 ++--- .../common/FormatViewGenerator_Table.cs | 116 +++++++++--------- .../common/FormatViewGenerator_Wide.cs | 82 ++++++------- 5 files changed, 146 insertions(+), 142 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index cb20e708cc4..963b5a0f88b 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -348,19 +348,49 @@ protected class DataBaseInfo protected DataBaseInfo dataBaseInfo = new DataBaseInfo(); - protected List activeAssociationList = null; /// - /// Apply ExcludeProperty filter to activeAssociationList if specified. - /// This method filters and updates "activeAssociationList" instance property. + /// Builds the raw association list for the given object. + /// Subclasses override this to provide cmdlet-specific property expansion logic. /// - protected void ApplyExcludePropertyFilter() + /// The object to build the association list for. + /// The list of properties specified by the user, or null if not specified. + /// The raw association list, or null if not applicable. + protected virtual List BuildRawAssociationList(PSObject so, List propertyList) { - if (this.parameters is not null && this.parameters.excludePropertyFilter is not null) + return null; + } + + /// + /// Builds the active association list for the given object, with ExcludeProperty filter applied. + /// + /// The object to build the association list for. + /// The filtered association list. + protected List BuildActiveAssociationList(PSObject so) + { + var propertyList = parameters?.mshParameterList; + var excludeFilter = parameters?.excludePropertyFilter; + var rawList = BuildRawAssociationList(so, propertyList); + return ApplyExcludeFilter(rawList, excludeFilter); + } + + /// + /// Applies the ExcludeProperty filter to the given association list. + /// + /// The list to filter. + /// The exclude filter to apply. + /// The filtered list, or the original list if no filter is specified. + internal static List ApplyExcludeFilter( + List associationList, + PSPropertyExpressionFilter excludeFilter) + { + if (associationList is null || excludeFilter is null) { - this.activeAssociationList = this.activeAssociationList - .Where(item => !this.parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) - .ToList(); + return associationList; } + + return associationList + .Where(item => !excludeFilter.IsMatch(item.ResolvedExpression)) + .ToList(); } protected string GetExpressionDisplayValue(PSObject so, int enumerationLimit, PSPropertyExpression ex, diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs index 972a7160830..b81c0c0f860 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Internal; @@ -514,13 +513,8 @@ private void DisplayObject(PSObject so, TraversalInfo currentLevel, List activeAssociationList = AssociationManager.SetupActiveProperties(parameterList, so, _expressionFactory); - // Apply ExcludeProperty filter if specified - if (_parameters != null && _parameters.excludePropertyFilter != null) - { - activeAssociationList = activeAssociationList - .Where(item => !_parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) - .ToList(); - } + // Apply ExcludeProperty filter using the centralized method + activeAssociationList = ViewGenerator.ApplyExcludeFilter(activeAssociationList, _parameters?.excludePropertyFilter); // create a format entry FormatEntry fe = new FormatEntry(); diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs index 6ef1b24ce14..35287d7c2e4 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs @@ -30,9 +30,14 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper { _listBody = (ListControlBody)this.dataBaseInfo.view.mainControl; } + } - this.parameters = parameters; - SetUpActiveProperties(so); + /// + /// Builds the raw association list for list formatting. + /// + protected override List BuildRawAssociationList(PSObject so, List propertyList) + { + return AssociationManager.SetupActiveProperties(propertyList, so, this.expressionFactory); } /// @@ -178,17 +183,14 @@ private ListControlEntryDefinition GetActiveListControlEntryDefinition(ListContr private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enumerationLimit) { - // compute active properties every time - if (this.activeAssociationList == null) - { - SetUpActiveProperties(so); - } + // Build active association list (with ExcludeProperty filter applied) + var associationList = BuildActiveAssociationList(so); ListViewEntry lve = new ListViewEntry(); - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < associationList.Count; k++) { - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k]; + MshResolvedExpressionParameterAssociation a = associationList[k]; ListViewField lvf = new ListViewField(); if (a.OriginatingParameter != null) @@ -218,21 +220,7 @@ private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enume lvf.formatPropertyField.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive); lve.listViewFieldList.Add(lvf); } - - this.activeAssociationList = null; return lve; } - - private void SetUpActiveProperties(PSObject so) - { - List mshParameterList = null; - - if (this.parameters != null) - mshParameterList = this.parameters.mshParameterList; - - this.activeAssociationList = AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory); - - ApplyExcludePropertyFilter(); - } } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index 33d2bd53506..3b14c0754ba 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -14,6 +14,8 @@ internal sealed class TableViewGenerator : ViewGenerator // tableBody to use for this instance of the ViewGenerator; private TableControlBody _tableBody; + private List _activeAssociationList; + internal override void Initialize(TerminatingErrorContext terminatingErrorContext, PSPropertyExpressionFactory mshExpressionFactory, TypeInfoDataBase db, ViewDefinition view, FormattingCommandLineParameters formatParameters) { base.Initialize(terminatingErrorContext, mshExpressionFactory, db, view, formatParameters); @@ -34,51 +36,48 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper _tableBody = (TableControlBody)this.dataBaseInfo.view.mainControl; } - List rawMshParameterList = null; - - if (parameters != null) - rawMshParameterList = parameters.mshParameterList; + // Build the active association list (with ExcludeProperty filter applied) + _activeAssociationList = BuildActiveAssociationList(so); + } + /// + /// Builds the raw association list for table formatting. + /// + protected override List BuildRawAssociationList(PSObject so, List propertyList) + { // check if we received properties from the command line - if (rawMshParameterList is not null && rawMshParameterList.Count > 0) + if (propertyList is not null && propertyList.Count > 0) { - this.activeAssociationList = AssociationManager.ExpandTableParameters(rawMshParameterList, so); + return AssociationManager.ExpandTableParameters(propertyList, so); } - else + + // we did not get any properties: + // try to get properties from the default property set of the object + var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (list.Count > 0) { - // we did not get any properties: - // try to get properties from the default property set of the object - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count > 0) - { - // we got a valid set of properties from the default property set..add computername for - // remoteobjects (if available) - if (PSObjectHelper.ShouldShowComputerNameProperty(so)) - { - activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, - new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); - } - } - else + // we got a valid set of properties from the default property set..add computername for + // remoteobjects (if available) + if (PSObjectHelper.ShouldShowComputerNameProperty(so)) { - // we failed to get anything from the default property set - this.activeAssociationList = AssociationManager.ExpandAll(so); - if (this.activeAssociationList.Count > 0) - { - // Remove PSComputerName and PSShowComputerName from the display as needed. - AssociationManager.HandleComputerNameProperties(so, activeAssociationList); - FilterActiveAssociationList(); - } - else - { - // we were unable to retrieve any properties, so we leave an empty list - this.activeAssociationList = new List(); - return; - } + list.Add(new MshResolvedExpressionParameterAssociation(null, + new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); } + + return list; } - ApplyExcludePropertyFilter(); + // we failed to get anything from the default property set + list = AssociationManager.ExpandAll(so); + if (list.Count > 0) + { + // Remove PSComputerName and PSShowComputerName from the display as needed. + AssociationManager.HandleComputerNameProperties(so, list); + return LimitAssociationListSize(list); + } + + // we were unable to retrieve any properties, so we leave an empty list + return new List(); } /// @@ -129,30 +128,29 @@ internal override FormatStartData GenerateStartData(PSObject so) } /// - /// Method to filter resolved expressions as per table view needs. + /// Limits the association list size for table view. /// For v1.0, table view supports only 10 properties. - /// - /// This method filters and updates "activeAssociationList" instance property. /// - /// None. - /// This method updates "activeAssociationList" instance property. - private void FilterActiveAssociationList() + /// The list to limit. + /// The limited list. + private static List LimitAssociationListSize( + List list) { - // we got a valid set of properties from the default property set - // make sure we do not have too many properties - // NOTE: this is an arbitrary number, chosen to be a sensitive default - const int nMax = 10; + const int maxCount = 10; + + if (list.Count <= maxCount) + { + return list; + } - if (activeAssociationList.Count > nMax) + var result = new List(maxCount); + for (int k = 0; k < maxCount; k++) { - List tmp = this.activeAssociationList; - this.activeAssociationList = new List(); - for (int k = 0; k < nMax; k++) - this.activeAssociationList.Add(tmp[k]); + result.Add(list[k]); } - return; + return result; } private TableHeaderInfo GenerateTableHeaderInfoFromDataBaseInfo(PSObject so) @@ -228,9 +226,9 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) thi.hideHeader = this.HideHeaders; thi.repeatHeader = this.RepeatHeader; - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < _activeAssociationList.Count; k++) { - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k]; + MshResolvedExpressionParameterAssociation a = _activeAssociationList[k]; TableColumnInfo ci = new TableColumnInfo(); // set the label of the column @@ -241,7 +239,7 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) ci.propertyName = (string)key; } - ci.propertyName ??= this.activeAssociationList[k].ResolvedExpression.ToString(); + ci.propertyName ??= _activeAssociationList[k].ResolvedExpression.ToString(); // set the width of the table if (a.OriginatingParameter != null) @@ -473,13 +471,13 @@ private TableRowEntry GenerateTableRowEntryFromDataBaseInfo(PSObject so, int enu private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int enumerationLimit) { TableRowEntry tre = new TableRowEntry(); - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < _activeAssociationList.Count; k++) { FormatPropertyField fpf = new FormatPropertyField(); FieldFormattingDirective directive = null; - if (activeAssociationList[k].OriginatingParameter != null) + if (_activeAssociationList[k].OriginatingParameter != null) { - directive = activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; + directive = _activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; } if (directive is null) @@ -488,7 +486,7 @@ private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int e directive.isTable = true; } - fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.activeAssociationList[k].ResolvedExpression, directive); + fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, _activeAssociationList[k].ResolvedExpression, directive); tre.formatPropertyFieldList.Add(fpf); } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs index a45c006e7fc..bfa364cc450 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs @@ -15,6 +15,40 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper base.Initialize(errorContext, expressionFactory, so, db, parameters); } + /// + /// Builds the raw association list for wide formatting. + /// + protected override List BuildRawAssociationList(PSObject so, List propertyList) + { + // check if we received properties from the command line + if (propertyList is not null && propertyList.Count > 0) + { + return AssociationManager.ExpandParameters(propertyList, so); + } + + // we did not get any properties: + // try to get the display property of the object + PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); + if (displayNameExpression is not null) + { + return new List + { + new MshResolvedExpressionParameterAssociation(null, displayNameExpression) + }; + } + + // try to get the default property set (we will use the first property) + var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (list.Count == 0) + { + // we failed to get anything from the default property set + // just get all the properties + list = AssociationManager.ExpandAll(so); + } + + return list; + } + internal override FormatStartData GenerateStartData(PSObject so) { FormatStartData startFormat = base.GenerateStartData(so); @@ -129,20 +163,17 @@ private WideControlEntryDefinition GetActiveWideControlEntryDefinition(WideContr private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enumerationLimit) { - // compute active properties every time - if (this.activeAssociationList == null) - { - SetUpActiveProperty(so); - } + // Build active association list (with ExcludeProperty filter applied) + var associationList = BuildActiveAssociationList(so); WideViewEntry wve = new WideViewEntry(); FormatPropertyField fpf = new FormatPropertyField(); wve.formatPropertyField = fpf; - if (this.activeAssociationList.Count > 0) + if (associationList.Count > 0) { // get the first one - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[0]; + MshResolvedExpressionParameterAssociation a = associationList[0]; FieldFormattingDirective directive = null; if (a.OriginatingParameter != null) { @@ -151,44 +182,7 @@ private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enume fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive); } - - this.activeAssociationList = null; return wve; } - - private void SetUpActiveProperty(PSObject so) - { - List rawMshParameterList = this.parameters?.mshParameterList; - - // check if we received properties from the command line - if (rawMshParameterList is not null && rawMshParameterList.Count > 0) - { - this.activeAssociationList = AssociationManager.ExpandParameters(rawMshParameterList, so); - } - else - { - // we did not get any properties: - // try to get the display property of the object - PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); - if (displayNameExpression is not null) - { - this.activeAssociationList = new List(); - this.activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, displayNameExpression)); - } - else - { - // try to get the default property set (we will use the first property) - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count == 0) - { - // we failed to get anything from the default property set - // just get all the properties - this.activeAssociationList = AssociationManager.ExpandAll(so); - } - } - } - - ApplyExcludePropertyFilter(); - } } } From 7f92d588fa02d58e31ba7c86840f3f1c94bdc466 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Thu, 11 Dec 2025 03:21:32 +0900 Subject: [PATCH 228/378] Add ToRegex method to WildcardPattern class (#26515) --- .../engine/regex.cs | 41 +++++++--- .../engine/WildcardPattern.Tests.ps1 | 77 +++++++++++++++++++ 2 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 test/powershell/engine/WildcardPattern.Tests.ps1 diff --git a/src/System.Management.Automation/engine/regex.cs b/src/System.Management.Automation/engine/regex.cs index d69f3bdb88f..6e0ef9741d6 100644 --- a/src/System.Management.Automation/engine/regex.cs +++ b/src/System.Management.Automation/engine/regex.cs @@ -73,18 +73,6 @@ public sealed class WildcardPattern // Default is WildcardOptions.None. internal WildcardOptions Options { get; } - /// - /// Wildcard pattern converted to regex pattern. - /// - internal string PatternConvertedToRegex - { - get - { - var patternRegex = WildcardPatternToRegexParser.Parse(this); - return patternRegex.ToString(); - } - } - /// /// Initializes and instance of the WildcardPattern class /// for the specified wildcard pattern. @@ -205,6 +193,35 @@ public bool IsMatch(string input) return input != null && _isMatch(input); } + /// + /// Converts the wildcard pattern to its regular expression equivalent. + /// + /// + /// A object that represents the regular expression equivalent of the wildcard pattern. + /// The regex is configured with options matching the wildcard pattern's options. + /// + /// + /// This method converts a wildcard pattern to a regular expression. + /// The conversion follows these rules: + /// + /// * (asterisk) converts to .* (matches any string) + /// ? (question mark) converts to . (matches any single character) + /// [abc] (bracket expression) converts to [abc] (matches any character in the set) + /// Literal characters are escaped as needed for regex + /// + /// + /// + /// + /// var pattern = new WildcardPattern("*.txt"); + /// Regex regex = pattern.ToRegex(); + /// // regex.ToString() returns: "\.txt$" + /// + /// + public Regex ToRegex() + { + return WildcardPatternToRegexParser.Parse(this); + } + /// /// Escape special chars, except for those specified in , in a string by replacing them with their escape codes. /// diff --git a/test/powershell/engine/WildcardPattern.Tests.ps1 b/test/powershell/engine/WildcardPattern.Tests.ps1 new file mode 100644 index 00000000000..81ced10f253 --- /dev/null +++ b/test/powershell/engine/WildcardPattern.Tests.ps1 @@ -0,0 +1,77 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "WildcardPattern.ToRegex Tests" -Tags "CI" { + It "Converts '' to regex pattern ''" -TestCases @( + @{ Pattern = '*.txt'; Expected = '\.txt$' } + @{ Pattern = 'test?.log'; Expected = '^test.\.log$' } + @{ Pattern = 'file[0-9].txt'; Expected = '^file[0-9]\.txt$' } + @{ Pattern = 'test.log'; Expected = '^test\.log$' } + @{ Pattern = '*test*file*.txt'; Expected = 'test.*file.*\.txt$' } + @{ Pattern = 'file[0-9][a-z].txt'; Expected = '^file[0-9][a-z]\.txt$' } + @{ Pattern = 'test*'; Expected = '^test' } + @{ Pattern = '*test*'; Expected = 'test' } + ) { + param($Pattern, $Expected) + $wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern) + $regex = $wildcardPattern.ToRegex() + $regex | Should -BeOfType ([regex]) + $regex.ToString() | Should -BeExactly $Expected + } + + It "Converts '' with option" -TestCases @( + @{ Pattern = 'TEST'; OptionName = 'IgnoreCase'; Option = [System.Management.Automation.WildcardOptions]::IgnoreCase; Expected = '^TEST$'; ExpectedRegexOptions = 'IgnoreCase, Singleline'; TestString = 'test'; ExpectedMatch = $true } + @{ Pattern = 'test'; OptionName = 'CultureInvariant'; Option = [System.Management.Automation.WildcardOptions]::CultureInvariant; Expected = '^test$'; ExpectedRegexOptions = 'Singleline, CultureInvariant'; TestString = 'test'; ExpectedMatch = $true } + @{ Pattern = 'test*'; OptionName = 'Compiled'; Option = [System.Management.Automation.WildcardOptions]::Compiled; Expected = '^test'; ExpectedRegexOptions = 'Compiled, Singleline'; TestString = 'testing'; ExpectedMatch = $true } + ) { + param($Pattern, $OptionName, $Option, $Expected, $ExpectedRegexOptions, $TestString, $ExpectedMatch) + $wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern, $Option) + $regex = $wildcardPattern.ToRegex() + $regex | Should -BeOfType ([regex]) + $regex.ToString() | Should -BeExactly $Expected + $regex.Options.ToString() | Should -BeExactly $ExpectedRegexOptions + $regex.IsMatch($TestString) | Should -Be $ExpectedMatch + } + + It "Regex from '' matches '': " -TestCases @( + @{ Pattern = '*test*file*.txt'; TestString = 'mytestmyfile123.txt'; ShouldMatch = $true } + @{ Pattern = 'file[0-9][a-z].txt'; TestString = 'file5a.txt'; ShouldMatch = $true } + @{ Pattern = 'file[0-9][a-z].txt'; TestString = 'file55.txt'; ShouldMatch = $false } + ) { + param($Pattern, $TestString, $ShouldMatch) + $regex = [System.Management.Automation.WildcardPattern]::new($Pattern).ToRegex() + $regex.IsMatch($TestString) | Should -Be $ShouldMatch + } + + Context "Edge cases" { + It "Handles empty pattern" { + $pattern = [System.Management.Automation.WildcardPattern]::new("") + $regex = $pattern.ToRegex() + $regex | Should -BeOfType ([regex]) + $regex.ToString() | Should -Be "^$" + } + + It "Handles pattern with only asterisk" { + $pattern = [System.Management.Automation.WildcardPattern]::new("*") + $regex = $pattern.ToRegex() + $regex | Should -BeOfType ([regex]) + $regex.ToString() | Should -BeExactly "" + $regex.IsMatch("anything") | Should -BeTrue + $regex.IsMatch("") | Should -BeTrue + } + + It "Handles escaped '' wildcard character" -TestCases @( + @{ Char = '*'; Pattern = 'file`*.txt'; Expected = '^file\*\.txt$' } + @{ Char = '?'; Pattern = 'file`?.txt'; Expected = '^file\?\.txt$' } + @{ Char = '['; Pattern = 'file`[.txt'; Expected = '^file\[\.txt$' } + @{ Char = ']'; Pattern = 'file`].txt'; Expected = '^file]\.txt$' } + ) { + param($Char, $Pattern, $Expected) + $wildcardPattern = [System.Management.Automation.WildcardPattern]::new($Pattern) + $regex = $wildcardPattern.ToRegex() + $regex | Should -BeOfType ([regex]) + $regex.ToString() | Should -BeExactly $Expected + } + + } +} From 06ffbaeb443b0420052f31681de076216d73a84f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:58:06 -0800 Subject: [PATCH 229/378] Bump github/codeql-action from 4.31.6 to 4.31.7 (#26586) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 21bc1ed1e92..55275cbcc3b 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 + uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 + uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3c322397db0..f6ca3ccac1c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5 + uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 with: sarif_file: results.sarif From 2e7765eef17ee274925a97efab1b9f52973eeb59 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:26:46 +0500 Subject: [PATCH 230/378] Fix $PSDefaultParameterValues leak causing tests to skip unexpectedly (#26602) This fixes test isolation issues where six test files were leaking $PSDefaultParameterValues["It:Skip"] settings to subsequent tests, causing widespread test skipping on Linux. The fixes address two distinct patterns: using .Remove() which doesn't restore the original state (4 files), and imbalanced Push-DefaultParameterValueStack/Pop-DefaultParameterValueStack calls (2 files). --- .../Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 | 3 ++- .../Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 | 3 ++- test/powershell/engine/ETS/CimAdapter.Tests.ps1 | 4 +++- test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 | 2 -- test/powershell/engine/Remoting/SessionOption.Tests.ps1 | 3 ++- test/powershell/engine/Security/FileSignature.Tests.ps1 | 1 + 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 index 82f944612f9..f1937f824a6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 @@ -7,6 +7,7 @@ $DefaultResultValue = 0 try { # set up for testing + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = ! $IsWindows Enable-Testhook -testhookName $RenameTesthook # we also set TestStopComputer @@ -73,7 +74,7 @@ try } finally { - $PSDefaultParameterValues.Remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues Disable-Testhook -testhookName $RenameTestHook Disable-Testhook -testhookName TestStopComputer Set-TesthookResult -testhookName $RenameResultName -value 0 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 index 0e50d7c3603..52938a0b881 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 @@ -3,6 +3,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { Context "Windows ACL test" { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["It:Skip"] = -not $IsWindows } @@ -103,7 +104,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { } AfterAll { - $PSDefaultParameterValues.Remove("It:Skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } } } diff --git a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 index 1e71bc28b95..3cfff4bd9e4 100644 --- a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 +++ b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 @@ -3,6 +3,8 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + function getIndex { param([string[]]$strings,[string]$pattern) @@ -32,7 +34,7 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { } } AfterAll { - $PSDefaultParameterValues.Remove("it:pending") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } It "Namespace-qualified Win32_Process is present" -Skip:(!$IsWindows) { diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index a5d49b75005..2093eaa7ce5 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -83,9 +83,7 @@ Describe "JEA session Transcript script test" -Tag @("Feature", 'RequireAdminOnW AfterAll { if ($skipTest) { Pop-DefaultParameterValueStack - return } - Pop-DefaultParameterValueStack } It "Configuration name should be in the transcript header" { diff --git a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 index 1ff51e2a707..e85777e90ba 100644 --- a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 +++ b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. try { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() if ( ! $IsWindows ) { $PSDefaultParameterValues['it:skip'] = $true } @@ -52,5 +53,5 @@ try { } } finally { - $PSDefaultParameterValues.remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } diff --git a/test/powershell/engine/Security/FileSignature.Tests.ps1 b/test/powershell/engine/Security/FileSignature.Tests.ps1 index 51194903a94..9dd26f98aed 100644 --- a/test/powershell/engine/Security/FileSignature.Tests.ps1 +++ b/test/powershell/engine/Security/FileSignature.Tests.ps1 @@ -89,6 +89,7 @@ Describe "Windows file content signatures" -Tags @('Feature', 'RequireAdminOnWin AfterAll { if ($shouldSkip) { + Pop-DefaultParameterValueStack return } From 592668bd0b0e46e370e9ac1ad4b8f5420efb51ae Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 12 Dec 2025 09:43:08 -0800 Subject: [PATCH 231/378] Refactor the module path construction code to make it more robust and easier to maintain (#26565) --- .../host/msh/ConsoleHost.cs | 21 ++- .../engine/Modules/ModuleIntrinsics.cs | 177 ++++++++---------- test/powershell/Host/ConsoleHost.Tests.ps1 | 27 +++ 3 files changed, 123 insertions(+), 102 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 5f59540ecf4..2d9902d176a 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -2201,7 +2201,6 @@ private void ReportException(Exception e, Executor exec) if (e1 != null) { // that didn't work. Write out the error ourselves as a last resort. - ReportExceptionFallback(e, null); } } @@ -2222,7 +2221,7 @@ private void ReportExceptionFallback(Exception e, string header) Console.Error.WriteLine(header); } - if (e == null) + if (e is null) { return; } @@ -2230,7 +2229,9 @@ private void ReportExceptionFallback(Exception e, string header) // See if the exception has an error record attached to it... ErrorRecord er = null; if (e is IContainsErrorRecord icer) + { er = icer.ErrorRecord; + } if (e is PSRemotingTransportException) { @@ -2247,8 +2248,22 @@ private void ReportExceptionFallback(Exception e, string header) } // Add the position message for the error if it's available. - if (er != null && er.InvocationInfo != null) + if (er?.InvocationInfo is { }) + { Console.Error.WriteLine(er.InvocationInfo.PositionMessage); + } + + // Print the stack trace. + Console.Error.WriteLine($"\n--- {e.GetType().FullName} ---"); + Console.Error.WriteLine(e.StackTrace); + + Exception inner = e.InnerException; + while (inner is { }) + { + Console.Error.WriteLine($"--- inner {inner.GetType().FullName} ---"); + Console.Error.WriteLine(inner.StackTrace); + inner = inner.InnerException; + } } /// diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index b687e502763..301ee8c3b49 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -10,9 +10,7 @@ using System.Management.Automation.Language; using System.Text; using System.Threading; - using Microsoft.PowerShell.Commands; -using Microsoft.Win32; using Dbg = System.Management.Automation.Diagnostics; @@ -39,18 +37,22 @@ public class ModuleIntrinsics private static readonly string s_windowsPowerShellPSHomeModulePath = Path.Combine(System.Environment.SystemDirectory, "WindowsPowerShell", "v1.0", "Modules"); + static ModuleIntrinsics() + { + // Initialize the module path. + SetModulePath(); + } + internal ModuleIntrinsics(ExecutionContext context) { _context = context; - - // And initialize the module path... - SetModulePath(); + ModuleTable = new Dictionary(StringComparer.OrdinalIgnoreCase); } private readonly ExecutionContext _context; // Holds the module collection... - internal Dictionary ModuleTable { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + internal Dictionary ModuleTable { get; } private const int MaxModuleNestingDepth = 10; @@ -176,11 +178,9 @@ private PSModuleInfo CreateModuleImplementation(string name, string path, object sb.SessionState = ss; } - else + else if (moduleCode is string sbText) { - var sbText = moduleCode as string; - if (sbText != null) - sb = ScriptBlock.Create(_context, sbText); + sb = ScriptBlock.Create(_context, sbText); } } @@ -1082,91 +1082,80 @@ internal static string GetExpandedEnvironmentVariable(string name, EnvironmentVa return result; } - /// - /// Checks if a particular string (path) is a member of 'combined path' string (like %Path% or %PSModulePath%) - /// - /// 'Combined path' string to analyze; can not be null. - /// Path to search for; can not be another 'combined path' (semicolon-separated); can not be null. - /// Index of pathToLookFor in pathToScan; -1 if not found. - private static int PathContainsSubstring(string pathToScan, string pathToLookFor) - { - // we don't support if any of the args are null - parent function should ensure this; empty values are ok - Diagnostics.Assert(pathToScan != null, "pathToScan should not be null according to contract of the function"); - Diagnostics.Assert(pathToLookFor != null, "pathToLookFor should not be null according to contract of the function"); - - int pos = 0; // position of the current substring in pathToScan - string[] substrings = pathToScan.Split(Path.PathSeparator, StringSplitOptions.None); // we want to process empty entries - string goodPathToLookFor = pathToLookFor.Trim().TrimEnd(Path.DirectorySeparatorChar); // trailing backslashes and white-spaces will mess up equality comparison - foreach (string substring in substrings) - { - string goodSubstring = substring.Trim().TrimEnd(Path.DirectorySeparatorChar); // trailing backslashes and white-spaces will mess up equality comparison - - // We have to use equality comparison on individual substrings (as opposed to simple 'string.IndexOf' or 'string.Contains') - // because of cases like { pathToScan="C:\Temp\MyDir\MyModuleDir", pathToLookFor="C:\Temp" } - - if (string.Equals(goodSubstring, goodPathToLookFor, StringComparison.OrdinalIgnoreCase)) - { - return pos; // match found - return index of it in the 'pathToScan' string - } - else - { - pos += substring.Length + 1; // '1' is for trailing semicolon - } - } - // if we are here, that means a match was not found - return -1; - } - /// /// Adds paths to a 'combined path' string (like %Path% or %PSModulePath%) if they are not already there. /// /// Path string (like %Path% or %PSModulePath%). - /// Collection of individual paths to add. + /// An individual path to add, or multiple paths separated by the path separator character. /// -1 to append to the end; 0 to insert in the beginning of the string; etc... /// Result string. - private static string AddToPath(string basePath, string pathToAdd, int insertPosition) + private static string UpdatePath(string basePath, string pathToAdd, ref int insertPosition) { // we don't support if any of the args are null - parent function should ensure this; empty values are ok - Diagnostics.Assert(basePath != null, "basePath should not be null according to contract of the function"); - Diagnostics.Assert(pathToAdd != null, "pathToAdd should not be null according to contract of the function"); + Dbg.Assert(basePath != null, "basePath should not be null according to contract of the function"); + Dbg.Assert(pathToAdd != null, "pathToAdd should not be null according to contract of the function"); + + // The 'pathToAdd' could be a 'combined path' (path-separator-separated). + string[] newPaths = pathToAdd.Split( + Path.PathSeparator, + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - StringBuilder result = new StringBuilder(basePath); + if (newPaths.Length is 0) + { + // The 'pathToAdd' doesn't really contain any paths to add. + return basePath; + } + + var result = new StringBuilder(basePath, capacity: basePath.Length + pathToAdd.Length + newPaths.Length); + var addedPaths = new HashSet(StringComparer.OrdinalIgnoreCase); + string[] initialPaths = basePath.Split( + Path.PathSeparator, + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + foreach (string p in initialPaths) + { + // Remove the trailing directory separators. + // Trailing white spaces were already removed by 'StringSplitOptions.TrimEntries'. + addedPaths.Add(Path.TrimEndingDirectorySeparator(p)); + } - if (!string.IsNullOrEmpty(pathToAdd)) // we don't want to append empty paths + foreach (string subPathToAdd in newPaths) { - foreach (string subPathToAdd in pathToAdd.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries)) // in case pathToAdd is a 'combined path' (semicolon-separated) + // Remove the trailing directory separators. + // Trailing white spaces were already removed by 'StringSplitOptions.TrimEntries'. + string normalizedPath = Path.TrimEndingDirectorySeparator(subPathToAdd); + if (addedPaths.Contains(normalizedPath)) { - int position = PathContainsSubstring(result.ToString(), subPathToAdd); // searching in effective 'result' value ensures that possible duplicates in pathsToAdd are handled correctly - if (position == -1) // subPathToAdd not found - add it - { - if (insertPosition == -1 || insertPosition > basePath.Length) // append subPathToAdd to the end - { - bool endsWithPathSeparator = false; - if (result.Length > 0) - { - endsWithPathSeparator = (result[result.Length - 1] == Path.PathSeparator); - } + // The normalized sub path was already added - skip it. + continue; + } - if (endsWithPathSeparator) - { - result.Append(subPathToAdd); - } - else - { - result.Append(Path.PathSeparator + subPathToAdd); - } - } - else if (insertPosition > result.Length) - { - // handle case where path is a singleton with no path separator already - result.Append(Path.PathSeparator).Append(subPathToAdd); - } - else // insert at the requested location (this is used by DSC ( location) and by 'user-specific location' (SpecialFolder.MyDocuments or EVT.User)) - { - result.Insert(insertPosition, subPathToAdd + Path.PathSeparator); - } + // The normalized sub path was not found - add it. + if (insertPosition is -1 || insertPosition >= result.Length) + { + // Append the normalized sub path to the end. + if (result.Length > 0 && result[^1] != Path.PathSeparator) + { + result.Append(Path.PathSeparator); } + + result.Append(normalizedPath); + // Next insertion should happen at the end. + insertPosition = result.Length; + } + else + { + // Insert at the requested location. + // This is used by the user-specific module path, the shared module path ( location), and the PSHome module path. + string strToInsert = normalizedPath + Path.PathSeparator; + result.Insert(insertPosition, strToInsert); + + // Next insertion should happen after the just inserted string. + insertPosition += strToInsert.Length; } + + // Add it to the set. + addedPaths.Add(normalizedPath); } return result.ToString(); @@ -1218,7 +1207,7 @@ public static string GetModulePath(string currentProcessModulePath, string hklmM string psHomeModulePath = GetPSHomeModulePath(); // $PSHome\Modules location // If the variable isn't set, then set it to the default value - if (currentProcessModulePath == null) // EVT.Process does Not exist - really corner case + if (string.IsNullOrEmpty(currentProcessModulePath)) // EVT.Process does Not exist - really corner case { // Handle the default case... if (string.IsNullOrEmpty(hkcuUserModulePath)) // EVT.User does Not exist -> set to location @@ -1270,21 +1259,6 @@ public static string GetModulePath(string currentProcessModulePath, string hklmM return currentProcessModulePath; } - private static string UpdatePath(string path, string pathToAdd, ref int insertIndex) - { - if (!string.IsNullOrEmpty(pathToAdd)) - { - path = AddToPath(path, pathToAdd, insertIndex); - insertIndex = path.IndexOf(Path.PathSeparator, PathContainsSubstring(path, pathToAdd)); - if (insertIndex != -1) - { - // advance past the path separator - insertIndex++; - } - } - return path; - } - /// /// Checks if $env:PSModulePath is not set and sets it as appropriate. Note - because these /// strings go through the provider, we need to escape any wildcards before passing them @@ -1358,11 +1332,16 @@ private static string SetModulePath() { string currentModulePath = GetExpandedEnvironmentVariable(Constants.PSModulePathEnvVar, EnvironmentVariableTarget.Process); #if !UNIX - // if the current process and user env vars are the same, it means we need to append the machine one as it's incomplete - // otherwise, the user modified it and we should use the process one + // if the current process and user env vars are the same, it means we need to append the machine one as it's incomplete. + // Otherwise, the user modified it and we should use the process one. if (string.CompareOrdinal(GetExpandedEnvironmentVariable(Constants.PSModulePathEnvVar, EnvironmentVariableTarget.User), currentModulePath) == 0) { - currentModulePath = currentModulePath + Path.PathSeparator + GetExpandedEnvironmentVariable(Constants.PSModulePathEnvVar, EnvironmentVariableTarget.Machine); + string machineScopeValue = GetExpandedEnvironmentVariable(Constants.PSModulePathEnvVar, EnvironmentVariableTarget.Machine); + currentModulePath = string.IsNullOrEmpty(currentModulePath) + ? machineScopeValue + : string.IsNullOrEmpty(machineScopeValue) + ? currentModulePath + : string.Concat(currentModulePath, Path.PathSeparator, machineScopeValue); } #endif string allUsersModulePath = PowerShellConfig.Instance.GetModulePath(ConfigScope.AllUsers); diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index ee501a83b63..534cce2d356 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -386,6 +386,33 @@ export $envVarName='$guid' } } + Context "-SettingsFile Commandline switch set 'PSModulePath'" { + + BeforeAll { + $CustomSettingsFile = Join-Path -Path $TestDrive -ChildPath 'powershell.test.json' + $mPath1 = Join-Path $PSHOME 'Modules' + $mPath2 = Join-Path $TestDrive 'NonExist' + $pathSep = [System.IO.Path]::PathSeparator + + ## Use multiple paths in the setting. + $ModulePath = "${mPath1}${pathSep}${mPath2}".Replace('\', "\\") + Set-Content -Path $CustomSettingsfile -Value "{`"Microsoft.PowerShell:ExecutionPolicy`":`"Unrestricted`", `"PSModulePath`": `"$ModulePath`" }" -ErrorAction Stop + } + + It "Verify PowerShell PSModulePath should contain paths from config file" { + $psModulePath = & $powershell -NoProfile -SettingsFile $CustomSettingsFile -Command '$env:PSModulePath' + + ## $mPath1 already exists in the value of env PSModulePath, so it won't be added again. + $index = $psModulePath.IndexOf("${mPath1}${pathSep}", [System.StringComparison]::OrdinalIgnoreCase) + $index | Should -BeGreaterThan 0 + $index += $mPath1.Length + $psModulePath.IndexOf($mPath1, $index, [System.StringComparison]::OrdinalIgnoreCase) | Should -BeExactly -1 + + ## $mPath2 should be added at the index position 0. + $psModulePath.StartsWith("${mPath2}${pathSep}", [System.StringComparison]::OrdinalIgnoreCase) | Should -BeTrue + } + } + Context "Pipe to/from powershell" { BeforeAll { if ($null -ne $PSStyle) { From 15d0a2841379462b159c9203fb4849b03a0f3d4e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 12 Dec 2025 10:40:16 -0800 Subject: [PATCH 232/378] Use consistent indentation in the file `HelpersCommon.psm1` (#26608) --- .../Modules/HelpersCommon/HelpersCommon.psm1 | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 index 5c05198ff8a..02588b612db 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 @@ -69,7 +69,7 @@ function Get-RandomFileName $SCRIPT:TesthookType = [system.management.automation.internal.internaltesthooks] function Test-TesthookIsSet { - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", '')] # , Justification = "an error message is not appropriate for this function")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", '')] # , Justification = "an error message is not appropriate for this function")] param ( [ValidateNotNullOrEmpty()] [Parameter(Mandatory=$true)] @@ -197,7 +197,7 @@ public class TestDynamic : DynamicObject # Upload an artifact in VSTS # On other systems will just log where the file was placed function Send-VstsLogFile { - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = "needed for VSO")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = "needed for VSO")] param ( [parameter(Mandatory,ParameterSetName='contents')] [string[]] @@ -324,8 +324,8 @@ function New-RandomHexString $script:CanWriteToPsHome = $null function Test-CanWriteToPsHome { - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '', Justification = "an error message is not appropriate for this function")] - param () + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '', Justification = "an error message is not appropriate for this function")] + param () if ($null -ne $script:CanWriteToPsHome) { return $script:CanWriteToPsHome } @@ -476,20 +476,20 @@ function Test-IsWindows2016 { # Ensure that the global:PSDefaultParameterValues variable is a hashtable function Initialize-PSDefaultParameterValue { - if ( $global:PSDefaultParameterValues -isnot [hashtable] ) { - $global:PSDefaultParameterValues = @{} - } + if ( $global:PSDefaultParameterValues -isnot [hashtable] ) { + $global:PSDefaultParameterValues = @{} + } } # reset the stack function Reset-DefaultParameterValueStack { - $script:DefaultParameterValueStack = [system.collections.generic.Stack[hashtable]]::new() + $script:DefaultParameterValueStack = [system.collections.generic.Stack[hashtable]]::new() Initialize-PSDefaultParameterValue } # return the current stack function Get-DefaultParameterValueStack { - $script:DefaultParameterValueStack + $script:DefaultParameterValueStack } # PSDefaultParameterValue may not have both skip and pending keys @@ -507,35 +507,35 @@ function Test-PSDefaultParameterValue { # if $ht is null, then the current value of $global:PSDefaultParameterValues is pushed # if $NewValue is used, then $ht is used as the new value of $global:PSDefaultParameterValues function Push-DefaultParameterValueStack { - param ([hashtable]$ht, [switch]$NewValue) + param ([hashtable]$ht, [switch]$NewValue) Initialize-PSDefaultParameterValue - $script:DefaultParameterValueStack.Push($global:PSDefaultParameterValues.Clone()) - if ( $ht ) { - if ( $NewValue ) { - $global:PSDefaultParameterValues = $ht - } - else { - foreach ($k in $ht.Keys) { - $global:PSDefaultParameterValues[$k] = $ht[$k] - } - } + $script:DefaultParameterValueStack.Push($global:PSDefaultParameterValues.Clone()) + if ( $ht ) { + if ( $NewValue ) { + $global:PSDefaultParameterValues = $ht + } + else { + foreach ($k in $ht.Keys) { + $global:PSDefaultParameterValues[$k] = $ht[$k] + } + } if ( ! (Test-PSDefaultParameterValue)) { Write-Warning -Message "PSDefaultParameterValues may not have both skip and pending keys, resetting." Pop-DefaultParameterValueStack } - } + } } function Pop-DefaultParameterValueStack { - try { - $global:PSDefaultParameterValues = $script:DefaultParameterValueStack.Pop() - return $true - } - catch { + try { + $global:PSDefaultParameterValues = $script:DefaultParameterValueStack.Pop() + return $true + } + catch { Initialize-PSDefaultParameterValue - return $false - } + return $false + } } function Get-HelpNetworkTestCases From 084ae755c6f154b8b2721c05ad16329fc913cedb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:58:53 -0800 Subject: [PATCH 233/378] Bump actions/upload-artifact from 5 to 6 (#26616) --- .github/workflows/macos-ci.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-packaging-reusable.yml | 2 +- .github/workflows/xunit-tests.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 60596c75ed7..8f15a2f3a6d 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -228,7 +228,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f6ca3ccac1c..1cc99ace9aa 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index f3a46cae908..bb4873adeb3 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -81,7 +81,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 940e1cb839c..5d225446cb7 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -46,7 +46,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: always() with: name: ${{ inputs.test_results_artifact_name }} From 4b2e8e00be4fb41f1e005aa45ff636479dd795fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:59:07 +0000 Subject: [PATCH 234/378] Bump github/codeql-action from 4.31.7 to 4.31.8 (#26615) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 55275cbcc3b..3271b534794 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 + uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 + uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 1cc99ace9aa..3d9ff2eba28 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3.29.5 + uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 with: sarif_file: results.sarif From 3f54d4af1f0cdd087cdfc0e5cddf06f83cfbb889 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:33:44 -0800 Subject: [PATCH 235/378] Update package references and build to use the .NET SDK 10.0.101 (#26595) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../BenchmarkDotNet.Extensions.csproj | 4 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- tools/cgmanifest.json | 108 +++++++++--------- 15 files changed, 80 insertions(+), 80 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 267f0bda7d6..1ae71bf0737 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100", + "sdkImageVersion": "10.0.101", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 376af49c07f..936a420a573 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100" + "version": "10.0.101" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index a338c175f14..f63196d3645 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index ef949508346..b2622f0517f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 1f9f342b259..b99139eb68e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + @@ -32,8 +32,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 45b4d8c0a0a..feea5665288 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 87f71daada9..d3446d28c98 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 48b4d8ff29c..178f0473f26 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 1e53a35f966..1099b2a3c11 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index e929166b20d..542fa8526ff 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 91566f64fb1..92c3f13d290 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index af3fc10ffce..c4831924845 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 15a6e49864c..03aa5697267 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 1dddf99ba5e..db2fde85955 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index d8165298b22..efbc103f25e 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -26,7 +26,7 @@ "Type": "nuget", "Nuget": { "Name": "Humanizer.Core", - "Version": "2.14.1" + "Version": "3.0.1" } }, "DevelopmentDependency": false @@ -36,7 +36,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.1.1" + "Version": "2.2.0" } }, "DevelopmentDependency": false @@ -46,7 +46,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "5.3.1" + "Version": "6.0.0" } }, "DevelopmentDependency": false @@ -66,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.43.0" + "Version": "0.44.0" } }, "DevelopmentDependency": false @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -106,7 +106,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.Common", - "Version": "4.14.0" + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -116,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.CSharp", - "Version": "4.14.0" + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -126,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -186,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -336,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -376,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -436,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -596,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -606,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -616,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -626,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -636,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -646,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -656,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -706,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -716,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -726,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -746,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false From cd0628641b2ab7c733c060386faf87f29439a833 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 16 Dec 2025 10:50:38 -0800 Subject: [PATCH 236/378] Update `Get-ChangeLog` to handle backport PRs and Copilot PRs correctly (#26610) --- tools/releaseTools.psm1 | 113 +++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index b034e2863dd..99edf93c08a 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -37,6 +37,7 @@ $Script:powershell_team = @( "dependabot-preview[bot]" "dependabot[bot]" "github-actions[bot]" + "Copilot" "Anam Navied" "Andrew Schwartzmeyer" "Jason Helmick" @@ -46,6 +47,27 @@ $Script:powershell_team = @( "Justin Chung" ) +# The powershell team members GitHub logins. We use them to decide if the original author of a backport PR is from the team. +$script:psteam_logins = @( + 'andyleejordan' + 'TravisEz13' + 'daxian-dbw' + 'adityapatwardhan' + 'SteveL-MSFT' + 'dependabot[bot]' + 'pwshBot' + 'jshigetomi' + 'SeeminglyScience' + 'anamnavi' + 'sdwheeler' + 'Copilot' + 'copilot-swe-agent' + 'app/copilot-swe-agent' + 'StevenBucher98' + 'alerickson' + 'tgauth' +) + # They are very active contributors, so we keep their email-login mappings here to save a few queries to Github. $Script:community_login_map = @{ "darpa@yandex.ru" = "iSazonov" @@ -54,11 +76,6 @@ $Script:community_login_map = @{ "info@powercode-consulting.se" = "powercode" } -# Ignore dependency bumping bot (Dependabot): -$Script:attribution_ignore_list = @( - 'dependabot[bot]@users.noreply.github.com' -) - ############################## #.SYNOPSIS #In the release workflow, the release branch will be merged back to master after the release is done, @@ -262,25 +279,76 @@ function Get-ChangeLog $clExperimental = @() foreach ($commit in $new_commits) { + $commitSubject = $commit.Subject + $prNumber = $commit.PullRequest + Write-Verbose "subject: $commitSubject" Write-Verbose "authorname: $($commit.AuthorName)" - if ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName -or $Script:attribution_ignore_list -contains $commit.AuthorEmail) { - $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commit.Subject) + + try { + $pr = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$prNumber" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false ## Always disable verbose to avoid noise when we debug this function. + } catch { + ## A commit may not have corresponding GitHub PRs. In that case, we will get status code 404 (Not Found). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 404) { + throw + } + } + + if ($commitSubject -match '^\[release/v\d\.\d\] ') { + ## The commit was from a backport PR. We need to get the real author in this case. + if (-not $pr) { + throw "The commit is from a backport PR (#$prNumber), but the PR cannot be found.`nPR Title: $commitSubject" + } + + $userPattern = 'Triggered by @.+ on behalf of @(.+)' + if ($pr.body -match $userPattern) { + $commit.AuthorGitHubLogin = ($Matches.1).Trim() + Write-Verbose "backport PR. real author login: $($commit.AuthorGitHubLogin)" + } else { + throw "The commit is from a backport PR (#$prNumber), but the PR description failed to match the pattern '$userPattern'. Was the template for backport PRs changed?`nPR Title: $commitSubject" + } + } + + if ($commit.AuthorGitHubLogin) { + if ($script:psteam_logins -contains $commit.AuthorGitHubLogin) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) + } else { + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) + $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) + } + } elseif ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) } else { if ($community_login_map.ContainsKey($commit.AuthorEmail)) { $commit.AuthorGitHubLogin = $community_login_map[$commit.AuthorEmail] } else { - $uri = "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" try{ - $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $header -ErrorAction Ignore - } catch{} + ## Always disable verbose to avoid noise when we debug this function. + $response = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false + } catch { + ## A commit could be available in ADO only. In that case, we will get status code 422 (UnprocessableEntity). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 422) { + throw + } + } + if($response) { - $content = ConvertFrom-Json -InputObject $response.Content - $commit.AuthorGitHubLogin = $content.author.login + $commit.AuthorGitHubLogin = $response.author.login $community_login_map[$commit.AuthorEmail] = $commit.AuthorGitHubLogin } } - $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commit.Subject), $commit.AuthorGitHubLogin) + + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) } @@ -289,16 +357,6 @@ function Get-ChangeLog } ## Get the labels for the PR - try { - $pr = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$($commit.PullRequest)" -Headers $header -ErrorAction SilentlyContinue - } - catch { - if ($_.Exception.Response.StatusCode -eq '404') { - $pr = $null - #continue - } - } - if($pr) { $clLabel = $pr.labels | Where-Object { $_.Name -match "^CL-"} @@ -328,7 +386,7 @@ function Get-ChangeLog "CL-Tools" { $clTools += $commit } "CL-Untagged" { $clUntagged += $commit } "CL-NotInBuild" { continue } - Default { throw "unknown tag '$cLabel' for PR: '$($commit.PullRequest)'" } + Default { throw "unknown tag '$cLabel' for PR: '$prNumber'" } } } } @@ -426,6 +484,9 @@ function Get-ChangeLogMessage '^Build\(deps\): ' { return $OriginalMessage.replace($Matches.0,'') } + '^\[release/v\d\.\d\] ' { + return $OriginalMessage.replace($Matches.0,'') + } default { return $OriginalMessage } @@ -867,8 +928,8 @@ function Invoke-PRBackport { ) $continue = $false while(!$continue) { - $input= Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") - switch($input) { + $value = Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") + switch($value) { 'yes' { $continue= $true } From b14cd0330c525f48fa12fa03b0ff02d4564c2984 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 16 Dec 2025 12:07:14 -0800 Subject: [PATCH 237/378] Fix the DSC test by skipping `AfterAll` cleanup if the initial setup in `BeforeAll` failed (#26621) --- .../dsc/dsc.profileresource.Tests.ps1 | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/powershell/dsc/dsc.profileresource.Tests.ps1 b/test/powershell/dsc/dsc.profileresource.Tests.ps1 index f361e67ea8e..cb357c7350b 100644 --- a/test/powershell/dsc/dsc.profileresource.Tests.ps1 +++ b/test/powershell/dsc/dsc.profileresource.Tests.ps1 @@ -4,8 +4,10 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { BeforeAll { $DSC_ROOT = $env:DSC_ROOT + $skipCleanup = $false if (-not (Test-Path -Path $DSC_ROOT)) { + $skipCleanup = $true throw "DSC_ROOT environment variable is not set or path does not exist." } @@ -40,6 +42,10 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { New-Item -Path $testProfilePathCurrentUserAllHosts -Value $testProfileContent -Force -ItemType File } AfterAll { + if ($skipCleanup) { + return + } + # Restore original profile $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost if (Test-Path "$TestDrive/currentuser-currenthost-profile.bak") { @@ -118,16 +124,19 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdminOnWindows', 'RequireSudoOnUnix' { BeforeAll { $DSC_ROOT = $env:DSC_ROOT + $skipCleanup = $false if (-not (Test-Path -Path $DSC_ROOT)) { + $skipCleanup = $true throw "DSC_ROOT environment variable is not set or path does not exist." } Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose - $pathSeparator = [System.IO.Path]::PathSeparator - $env:PATH += "$pathSeparator$DSC_ROOT" + $originalPath = $env:PATH + $pathSeparator = [System.IO.Path]::PathSeparator + $env:PATH += "$pathSeparator$DSC_ROOT" $env:PATH += "$pathSeparator$PSHome" Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose @@ -151,11 +160,12 @@ Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdm $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts Copy-Item -Path $testProfilePathAllUsersAllHosts -Destination "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue New-Item -Path $testProfilePathAllUsersAllHosts -Value $testProfileContent -Force -ItemType File - - $originalPath = $env:PATH - $env:PATH += "$pathSeparator$PSHome" } AfterAll { + if ($skipCleanup) { + return + } + $env:PATH = $originalPath $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost From d89da9b2fc4043a8b2fca84090b1b5e6d08bdddb Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 16 Dec 2025 15:58:36 -0800 Subject: [PATCH 238/378] Update changelog for the release v7.6.0-preview.6 (#26597) --- CHANGELOG/preview.md | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 3648f4cc121..f1c5f566289 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,76 @@ # Preview Changelog +## [7.6.0-preview.6] - 2025-12-11 + +### Engine Updates and Fixes + +- Properly Expand Aliases to their actual ResolvedCommand (#26571) (Thanks @kilasuit!) + +### General Cmdlet Updates and Fixes + +- Update `Microsoft.PowerShell.PSResourceGet` to `v1.2.0-preview5` (#26590) +- Make the experimental feature `PSFeedbackProvider` stable (#26502) +- Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26487) +- Add Delimiter parameter to `Get-Clipboard` (#26572) (Thanks @MartinGC94!) +- Close pipe client handles after creating the child ssh process (#26564) +- Make some experimental features stable (#26490) +- DSC v3 resource for PowerShell Profile (#26447) + +### Tools + +- Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26530) +- Add reusable get-changed-files action and refactor existing actions (#26529) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26494) + +### Tests + +- Fix merge conflict checker for empty file lists and filter *.cs files (#26556) +- Add markdown link verification for PRs (#26445) + +### Build and Packaging Improvements + +
    + + + +

    Expand to see details.

    + +
    + +
      +
    • Fix template path for rebuild branch check in package.yml (#26560)
    • +
    • Update the macos package name for preview releases to match the previous pattern (#26576)
    • +
    • Add rebuild branch support with conditional MSIX signing (#26573)
    • +
    • Update the WCF packages to the latest version that is compatible with v4.10.3 (#26503)
    • +
    • Improve ADO package build and validation across platforms (#26532)
    • +
    • Mirror .NET/runtime ICU version range in PowerShell (#26563) (Thanks @kasperk81!)
    • +
    • Update the macos package name for preview releases to match the previous pattern (#26562)
    • +
    • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26561)
    • +
    • Move package validation to package pipeline (#26558)
    • +
    • Optimize/split windows package signing (#26557)
    • +
    • Remove usage of fpm for DEB package generation (#26504)
    • +
    • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26524)
    • +
    • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501)
    • +
    • Replace fpm with native rpmbuild for RPM package generation (#26441)
    • +
    • Fix GitHub API rate limit errors in test actions (#26492)
    • +
    • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26493)
    • +
    • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26488)
    • +
    • Fix build to only enable ready-to-run for the Release configuration (#26481)
    • +
    • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26468)
    • +
    • Update outdated package references (#26471)
    • +
    • GitHub Workflow cleanup (#26439)
    • +
    • Update PSResourceGet package version to preview4 (#26438)
    • +
    • Update PSReadLine to v2.4.5 (#26446)
    • +
    • Add network isolation policy parameter to vPack pipeline (#26444)
    • +
    • Fix a couple more lint errors
    • +
    • Fix lint errors in preview.md
    • +
    • Make MSIX publish stage dependent on SetReleaseTagandContainerName stage
    • +
    + +
    + +[7.6.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.5...v7.6.0-preview.6 + ## [7.6.0-preview.5] - 2025-09-30 ### Engine Updates and Fixes From d0d39c03b12c9b485e739a448ae6a0eaa74d6384 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Wed, 17 Dec 2025 18:15:36 +0900 Subject: [PATCH 239/378] Fix Test-Json false positive errors when using oneOf or anyOf in schema (#26618) --- .../commands/utility/TestJsonCommand.cs | 39 +++- .../Test-Json.Tests.ps1 | 195 ++++++++++++++++++ 2 files changed, 224 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs index 32603f160f8..909cbff3c8f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/TestJsonCommand.cs @@ -264,19 +264,11 @@ protected override void ProcessRecord() if (_jschema != null) { - EvaluationResults evaluationResults = _jschema.Evaluate(parsedJson, new EvaluationOptions { OutputFormat = OutputFormat.List }); + EvaluationResults evaluationResults = _jschema.Evaluate(parsedJson, new EvaluationOptions { OutputFormat = OutputFormat.Hierarchical }); result = evaluationResults.IsValid; if (!result) { - HandleValidationErrors(evaluationResults); - - if (evaluationResults.HasDetails) - { - foreach (var nestedResult in evaluationResults.Details) - { - HandleValidationErrors(nestedResult); - } - } + ReportValidationErrors(evaluationResults); } } } @@ -298,6 +290,33 @@ protected override void ProcessRecord() WriteObject(result); } + /// + /// Recursively reports validation errors from hierarchical evaluation results. + /// Skips nodes (and their children) where IsValid is true to avoid false positives + /// from constructs like OneOf or AnyOf. + /// + /// The evaluation result to process. + private void ReportValidationErrors(EvaluationResults evaluationResult) + { + // Skip this node and all children if validation passed + if (evaluationResult.IsValid) + { + return; + } + + // Report errors at this level + HandleValidationErrors(evaluationResult); + + // Recursively process child results + if (evaluationResult.HasDetails) + { + foreach (var nestedResult in evaluationResult.Details) + { + ReportValidationErrors(nestedResult); + } + } + } + private void HandleValidationErrors(EvaluationResults evaluationResult) { if (!evaluationResult.HasErrors) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 index 32a6cf3ce63..7b1b58d8258 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json.Tests.ps1 @@ -86,6 +86,141 @@ Describe "Test-Json" -Tags "CI" { } '@ + # Schema using oneOf to allow either integer or string pattern for port items + $oneOfSchema = @' + { + "type": "object", + "properties": { + "ports": { + "type": "array", + "items": { + "oneOf": [ + { "type": "integer", "minimum": 0, "maximum": 65535 }, + { "type": "string", "pattern": "^\\d+-\\d+$" } + ] + } + } + } + } +'@ + + # Valid JSON where ports are integers (first oneOf choice matches) + $validOneOfJson = '{ "ports": [80, 443, 8080] }' + + # Invalid JSON where a port value matches neither oneOf choice + $invalidOneOfJson = '{ "ports": [80, "invalid-port", 8080] }' + + # Schema using oneOf to allow either smartphone or laptop device types + $oneOfDeviceSchema = @' + { + "type": "object", + "properties": { + "Devices": { + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { + "properties": { + "id": { "type": "string" }, + "deviceType": { "const": "smartphone" }, + "os": { "type": "string", "enum": ["iOS", "Android"] } + }, + "required": ["deviceType", "os"] + }, + { + "properties": { + "id": { "type": "string" }, + "deviceType": { "const": "laptop" }, + "arch": { "type": "string", "enum": ["x86", "x64", "arm64"] } + }, + "required": ["deviceType", "arch"] + } + ] + } + } + }, + "required": ["Devices"] + } +'@ + + # Valid JSON with mixed device types (all matching their respective oneOf choice) + $validOneOfDeviceJson = @' + { + "Devices": [ + { "id": "0", "deviceType": "laptop", "arch": "x64" }, + { "id": "1", "deviceType": "smartphone", "os": "iOS" }, + { "id": "2", "deviceType": "laptop", "arch": "arm64" }, + { "id": "3", "deviceType": "smartphone", "os": "Android" } + ] + } +'@ + + # Invalid JSON where only Devices/3 has an invalid os value + $invalidOneOfDeviceJson = @' + { + "Devices": [ + { "id": "0", "deviceType": "laptop", "arch": "x64" }, + { "id": "1", "deviceType": "smartphone", "os": "iOS" }, + { "id": "2", "deviceType": "laptop", "arch": "arm64" }, + { "id": "3", "deviceType": "smartphone", "os": "WindowsPhone" } + ] + } +'@ + + # Schema using anyOf to allow either smartphone or laptop device types + $anyOfDeviceSchema = @' + { + "type": "object", + "properties": { + "Devices": { + "type": "array", + "items": { + "type": "object", + "anyOf": [ + { + "properties": { + "deviceType": { "const": "smartphone" }, + "os": { "type": "string", "enum": ["iOS", "Android"] } + }, + "required": ["deviceType", "os"] + }, + { + "properties": { + "deviceType": { "const": "laptop" }, + "arch": { "type": "string", "enum": ["x86", "x64", "arm64"] } + }, + "required": ["deviceType", "arch"] + } + ] + } + } + }, + "required": ["Devices"] + } +'@ + + # Valid JSON with mixed device types (all matching their respective anyOf choice) + $validAnyOfDeviceJson = @' + { + "Devices": [ + { "deviceType": "laptop", "arch": "x64" }, + { "deviceType": "smartphone", "os": "iOS" } + ] + } +'@ + + # Invalid JSON where only Devices/2 has an invalid os value + $invalidAnyOfDeviceJson = @' + { + "Devices": [ + { "deviceType": "laptop", "arch": "x64" }, + { "deviceType": "smartphone", "os": "iOS" }, + { "deviceType": "smartphone", "os": "WindowsPhone" } + ] + } +'@ + $validJsonPath = Join-Path -Path $TestDrive -ChildPath 'validJson.json' $validLiteralJsonPath = Join-Path -Path $TestDrive -ChildPath "[valid]Json.json" $invalidNodeInJsonPath = Join-Path -Path $TestDrive -ChildPath 'invalidNodeInJson.json' @@ -343,4 +478,64 @@ Describe "Test-Json" -Tags "CI" { # With options should pass ($Json | Test-Json -Option $Options -ErrorAction SilentlyContinue) | Should -BeTrue } + + It "Test-Json does not report false positives for valid oneOf matches" { + $errorVar = $null + $result = Test-Json -Json $validOneOfJson -Schema $oneOfSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeTrue + $errorVar.Count | Should -Be 0 + } + + It "Test-Json reports only relevant errors for invalid oneOf values" { + $errorVar = $null + $result = Test-Json -Json $invalidOneOfJson -Schema $oneOfSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeFalse + # Should report error only for the invalid item, not for valid items + $errorVar.Count | Should -BeGreaterThan 0 + $errorVar[0].Exception.Message | Should -Match "/ports/1" + } + + It "Test-Json does not report false positives for valid oneOf device matches" { + $errorVar = $null + $result = Test-Json -Json $validOneOfDeviceJson -Schema $oneOfDeviceSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeTrue + $errorVar.Count | Should -Be 0 + } + + It "Test-Json reports errors only for the invalid device in oneOf schema" { + $errorVar = $null + $result = Test-Json -Json $invalidOneOfDeviceJson -Schema $oneOfDeviceSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeFalse + # Should not report errors for valid devices (Devices/0, /1, /2) + $falsePositives = $errorVar | Where-Object { $_.Exception.Message -match '/Devices/(0|1|2)' } + $falsePositives.Count | Should -Be 0 + # Should report errors only for the invalid device (Devices/3) + $relevantErrors = $errorVar | Where-Object { $_.Exception.Message -match '/Devices/3' } + $relevantErrors.Count | Should -BeGreaterThan 0 + } + + It "Test-Json does not report false positives for valid anyOf device matches" { + $errorVar = $null + $result = Test-Json -Json $validAnyOfDeviceJson -Schema $anyOfDeviceSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeTrue + $errorVar.Count | Should -Be 0 + } + + It "Test-Json reports errors only for the invalid device in anyOf schema" { + $errorVar = $null + $result = Test-Json -Json $invalidAnyOfDeviceJson -Schema $anyOfDeviceSchema -ErrorVariable errorVar -ErrorAction SilentlyContinue + + $result | Should -BeFalse + # Should not report errors for valid devices (Devices/0, /1) + $falsePositives = $errorVar | Where-Object { $_.Exception.Message -match '/Devices/(0|1)' } + $falsePositives.Count | Should -Be 0 + # Should report errors only for the invalid device (Devices/2) + $relevantErrors = $errorVar | Where-Object { $_.Exception.Message -match '/Devices/2' } + $relevantErrors.Count | Should -BeGreaterThan 0 + } } From 9ef5ec4734313193f248818c5fb4b43803e06c43 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:22:06 -0600 Subject: [PATCH 240/378] Bring release changes from the v7.6.0-preview.6 release branch (#26627) 1. Fix the conditions used in `release-MSIX-Publish.yml` 2. Update `build.psm1` to not install dotnet format tool for ADO build. --- .pipelines/templates/release-MSIX-Publish.yml | 4 ++-- build.psm1 | 22 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 1735cd9f710..2bf1e130103 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -100,7 +100,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' @@ -113,7 +113,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' diff --git a/build.psm1 b/build.psm1 index dd2cf0f351e..d09b7af925d 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2485,19 +2485,21 @@ function Start-PSBootstrap { Write-LogGroupEnd -Title "Install Windows Dependencies" } - if ($Scenario -in 'All', 'Tools') { - Write-LogGroupStart -Title "Install .NET Global Tools" - Write-Log -message "Installing .NET global tools" + # Ensure dotnet is available + Find-Dotnet - # Ensure dotnet is available - Find-Dotnet + if (-not $env:TF_BUILD) { + if ($Scenario -in 'All', 'Tools') { + Write-LogGroupStart -Title "Install .NET Global Tools" + Write-Log -message "Installing .NET global tools" - # Install dotnet-format - Write-Verbose -Verbose "Installing dotnet-format global tool" - Start-NativeExecution { - dotnet tool install --global dotnet-format + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + Write-LogGroupEnd -Title "Install .NET Global Tools" } - Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { From 1df30e0c6d12018f0a20064cd522400d182f01fc Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 5 Jan 2026 11:35:14 -0500 Subject: [PATCH 241/378] Update SECURITY.md to remove email reporting option (#26653) --- .github/SECURITY.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index f941d308b1f..797f7003851 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -12,9 +12,7 @@ If you believe you have found a security vulnerability in any Microsoft-owned re Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). +You should receive a response within 24 hours. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: From 867d799e6fadffa0d2676faa328ad37151904528 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 6 Jan 2026 10:27:45 -0500 Subject: [PATCH 242/378] Add default CODEOWNERS entry for maintainers (#26660) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6de13fd8daf..14569b81924 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,6 +3,9 @@ # Areas are not limited to the filters defined in this file # First, let's start with areas with no filters or paths +# Default +* @PowerShell/powershell-maintainers + # Area: Performance # @adityapatwardhan From 4838a8d5f6c95339d4b44c8b402165e69e6ff929 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 09:44:22 -0800 Subject: [PATCH 243/378] Bump github/codeql-action from 4.31.8 to 4.31.9 (#26623) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 3271b534794..07a63c2e348 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 + uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 + uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3d9ff2eba28..9b09c232801 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v3.29.5 + uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 with: sarif_file: results.sarif From 7ace9e0f5e998c02151b5264148dacc58de76f87 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Fri, 9 Jan 2026 17:48:37 -0600 Subject: [PATCH 244/378] Improve error message from `Start-NativeExecution` (#26500) --- tools/buildCommon/startNativeExecution.ps1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/buildCommon/startNativeExecution.ps1 b/tools/buildCommon/startNativeExecution.ps1 index ee7b00d04cd..2e44d86bd6a 100644 --- a/tools/buildCommon/startNativeExecution.ps1 +++ b/tools/buildCommon/startNativeExecution.ps1 @@ -16,6 +16,8 @@ function script:Start-NativeExecution { $ErrorActionPreference = "Continue" Write-Verbose "Executing: $ScriptBlock" try { + $cwd = Get-Location + if ($VerboseOutputOnError.IsPresent) { $output = & $ScriptBlock 2>&1 } else { @@ -36,10 +38,10 @@ function script:Start-NativeExecution { $callerFile = $callerLocationParts[0] $callerLine = $callerLocationParts[1] - $errorMessage = "Execution of {$ScriptBlock} by ${callerFile}: line $callerLine failed with exit code $LASTEXITCODE" + $errorMessage = "Execution of {$ScriptBlock} in '$cwd' by ${callerFile}: line $callerLine failed with exit code $LASTEXITCODE" throw $errorMessage } - throw "Execution of {$ScriptBlock} failed with exit code $LASTEXITCODE" + throw "Execution of {$ScriptBlock} in '$cwd' failed with exit code $LASTEXITCODE" } } finally { $ErrorActionPreference = $backupEAP From 5ebba3ca331be57baf8cdc0d7021e7f3ff3678d7 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 12 Jan 2026 13:05:19 -0500 Subject: [PATCH 245/378] Delete unused winget release script (#26683) --- tools/releaseToWinget.ps1 | 166 -------------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 tools/releaseToWinget.ps1 diff --git a/tools/releaseToWinget.ps1 b/tools/releaseToWinget.ps1 deleted file mode 100644 index e3c1af080e3..00000000000 --- a/tools/releaseToWinget.ps1 +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -param( - [Parameter(Mandatory)] - [semver] - $ReleaseVersion, - - [Parameter()] - [string] - $WingetRepoPath = "$PSScriptRoot/../../winget-pkgs", - - [Parameter()] - [string] - $FromRepository = 'rjmholt', - - [Parameter()] - [string] - $GitHubToken -) - -function GetMsiHash -{ - param( - [Parameter(Mandatory)] - [string] - $ReleaseVersion, - - [Parameter(Mandatory)] - $MsiName - ) - - $releaseParams = @{ - Tag = "v$ReleaseVersion" - OwnerName = 'PowerShell' - RepositoryName = 'PowerShell' - } - - if ($GitHubToken) { $releaseParams.AccessToken = $GitHubToken } - - $releaseDescription = (Get-GitHubRelease @releaseParams).body - - $regex = [regex]::new("powershell-$ReleaseVersion-win-x64.msi.*?([0-9A-F]{64})", 'SingleLine,IgnoreCase') - - return $regex.Match($releaseDescription).Groups[1].Value -} - -function GetThisScriptRepoUrl -{ - # Find the root of the repo - $prefix = $PSScriptRoot - while ($prefix) - { - if (Test-Path "$prefix/LICENSE.txt") - { - break - } - - $prefix = Split-Path $prefix - } - - $stem = $PSCommandPath.Substring($prefix.Length + 1).Replace('\', '/') - - return "https://github.com/PowerShell/PowerShell/blob/master/$stem" -} - -function Exec -{ - param([scriptblock]$sb) - - & $sb - - if ($LASTEXITCODE -ne 0) - { - throw "Invocation failed for '$sb'. See above errors for details" - } -} - -$ErrorActionPreference = 'Stop' - -$wingetPath = (Resolve-Path $WingetRepoPath).Path - -# Ensure we have git and PowerShellForGitHub installed -Import-Module -Name PowerShellForGitHub -$null = Get-Command git - -# Get the MSI hash from the release body -$msiName = "PowerShell-$ReleaseVersion-win-x64.msi" -$msiHash = GetMsiHash -ReleaseVersion $ReleaseVersion -MsiName $msiName - -$publisherName = 'Microsoft' - -# Create the manifest -$productName = if ($ReleaseVersion.PreReleaseLabel) -{ - 'PowerShell-Preview' -} -else -{ - 'PowerShell' -} - -$manifestDir = Join-Path $wingetPath 'manifests' 'm' $publisherName $productName $ReleaseVersion -$manifestPath = Join-Path $manifestDir "$publisherName.$productName.yaml" - -$manifestContent = @" -PackageIdentifier: $publisherName.$productName -PackageVersion: $ReleaseVersion -PackageName: $productName -Publisher: $publisherName -PackageUrl: https://microsoft.com/PowerShell -License: MIT -LicenseUrl: https://github.com/PowerShell/PowerShell/blob/master/LICENSE.txt -Moniker: $($productName.ToLower()) -ShortDescription: $publisherName.$productName -Description: PowerShell is a cross-platform (Windows, Linux, and macOS) automation and configuration tool/framework that works well with your existing tools and is optimized for dealing with structured data (e.g. JSON, CSV, XML, etc.), REST APIs, and object models. It includes a command-line shell, an associated scripting language and a framework for processing cmdlets. -Tags: -- powershell -- pwsh -Homepage: https://github.com/PowerShell/PowerShell -Installers: -- Architecture: x64 - InstallerUrl: https://github.com/PowerShell/PowerShell/releases/download/v$ReleaseVersion/$msiName - InstallerSha256: $msiHash - InstallerType: msi -PackageLocale: en-US -ManifestType: singleton -ManifestVersion: 1.0.0 - -"@ - -Push-Location $wingetPath -try -{ - $branch = "pwsh-$ReleaseVersion" - - Exec { git checkout master } - Exec { git checkout -b $branch } - - New-Item -Path $manifestDir -ItemType Directory - Set-Content -Path $manifestPath -Value $manifestContent -Encoding utf8NoBOM - - Exec { git add $manifestPath } - Exec { git commit -m "Add $productName $ReleaseVersion" } - Exec { git push origin $branch } - - $prParams = @{ - Title = "Add $productName $ReleaseVersion" - Body = "This pull request is automatically generated. See $(GetThisScriptRepoUrl)." - Head = $branch - HeadOwner = $FromRepository - Base = 'master' - Owner = 'Microsoft' - RepositoryName = 'winget-pkgs' - MaintainerCanModify = $true - } - - if ($GitHubToken) { $prParams.AccessToken = $GitHubToken } - - New-GitHubPullRequest @prParams -} -finally -{ - git checkout master - Pop-Location -} From bf03a14b6dcf6f399451f45b01460c6a7280de1d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 12 Jan 2026 10:44:55 -0800 Subject: [PATCH 246/378] Fix the CLR internal error and null ref exception when running `show-command` with PowerShell API (#26669) --- .../commandHelpers/ShowCommandHelper.cs | 3 ++- .../resources/HelpErrors.resx | 2 +- .../utils/GraphicalHostReflectionWrapper.cs | 13 +++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs b/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs index 32c68e961c6..10690b65dc7 100644 --- a/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs +++ b/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs @@ -679,7 +679,8 @@ internal static string SingleQuote(string str) /// The host window, if it is present or null if it is not. internal static Window GetHostWindow(PSCmdlet cmdlet) { - PSPropertyInfo windowProperty = cmdlet.Host.PrivateData.Properties["Window"]; + // The value of 'PrivateData' property may be null for the default host or a custom host. + PSPropertyInfo windowProperty = cmdlet.Host.PrivateData?.Properties["Window"]; if (windowProperty == null) { return null; diff --git a/src/System.Management.Automation/resources/HelpErrors.resx b/src/System.Management.Automation/resources/HelpErrors.resx index 27634de2995..ae797e8af12 100644 --- a/src/System.Management.Automation/resources/HelpErrors.resx +++ b/src/System.Management.Automation/resources/HelpErrors.resx @@ -179,7 +179,7 @@ To update these Help topics, start PowerShell by using the "Run as Administrator" command, and try running Update-Help again. - To use the {0}, install Windows PowerShell ISE by using Server Manager, and then restart this application. ({1}) + To use the {0}, make sure your application uses 'Microsoft.NET.Sdk.WindowsDesktop' as the project SDK and the corresponding assembly 'Microsoft.PowerShell.GraphicalHost' is available. ({1}) {0} does not work in a remote session. diff --git a/src/System.Management.Automation/utils/GraphicalHostReflectionWrapper.cs b/src/System.Management.Automation/utils/GraphicalHostReflectionWrapper.cs index a0b12f986de..ec780222345 100644 --- a/src/System.Management.Automation/utils/GraphicalHostReflectionWrapper.cs +++ b/src/System.Management.Automation/utils/GraphicalHostReflectionWrapper.cs @@ -55,7 +55,7 @@ private GraphicalHostReflectionWrapper() /// When it was not possible to load Microsoft.PowerShell.GraphicalHost.dlly. internal static GraphicalHostReflectionWrapper GetGraphicalHostReflectionWrapper(PSCmdlet parentCmdlet, string graphicalHostHelperTypeName) { - return GraphicalHostReflectionWrapper.GetGraphicalHostReflectionWrapper(parentCmdlet, graphicalHostHelperTypeName, parentCmdlet.CommandInfo.Name); + return GetGraphicalHostReflectionWrapper(parentCmdlet, graphicalHostHelperTypeName, parentCmdlet.CommandInfo.Name); } /// @@ -73,9 +73,9 @@ internal static GraphicalHostReflectionWrapper GetGraphicalHostReflectionWrapper [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Assembly.Load has been found to throw unadvertised exceptions")] internal static GraphicalHostReflectionWrapper GetGraphicalHostReflectionWrapper(PSCmdlet parentCmdlet, string graphicalHostHelperTypeName, string featureName) { - GraphicalHostReflectionWrapper returnValue = new GraphicalHostReflectionWrapper(); + GraphicalHostReflectionWrapper returnValue = new(); - if (GraphicalHostReflectionWrapper.IsInputFromRemoting(parentCmdlet)) + if (IsInputFromRemoting(parentCmdlet)) { ErrorRecord error = new ErrorRecord( new NotSupportedException(StringUtil.Format(HelpErrors.RemotingNotSupportedForFeature, featureName)), @@ -87,9 +87,10 @@ internal static GraphicalHostReflectionWrapper GetGraphicalHostReflectionWrapper } // Prepare the full assembly name. - AssemblyName graphicalHostAssemblyName = new AssemblyName(); + AssemblyName smaAssemblyName = typeof(PSObject).Assembly.GetName(); + AssemblyName graphicalHostAssemblyName = new(); graphicalHostAssemblyName.Name = "Microsoft.PowerShell.GraphicalHost"; - graphicalHostAssemblyName.Version = new Version(3, 0, 0, 0); + graphicalHostAssemblyName.Version = smaAssemblyName.Version; graphicalHostAssemblyName.CultureInfo = new CultureInfo(string.Empty); // Neutral culture graphicalHostAssemblyName.SetPublicKeyToken(new byte[] { 0x31, 0xbf, 0x38, 0x56, 0xad, 0x36, 0x4e, 0x35 }); @@ -124,7 +125,7 @@ internal static GraphicalHostReflectionWrapper GetGraphicalHostReflectionWrapper returnValue._graphicalHostHelperType = returnValue._graphicalHostAssembly.GetType(graphicalHostHelperTypeName); - Diagnostics.Assert(returnValue._graphicalHostHelperType != null, "the type exists in Microsoft.PowerShell.GraphicalHost"); + Diagnostics.Assert(returnValue._graphicalHostHelperType != null, "the type should exist in Microsoft.PowerShell.GraphicalHost"); ConstructorInfo constructor = returnValue._graphicalHostHelperType.GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance, null, From c792b3c0ba609776ce6eba308495f76601b2c04f Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 12 Jan 2026 10:45:41 -0800 Subject: [PATCH 247/378] Fix to use accurate message for validating a string argument is not null and not an empty string (#26668) --- .../CommandCompletion/CompletionResult.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionResult.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionResult.cs index ffb09e2a50d..0554a52ba17 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionResult.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionResult.cs @@ -168,26 +168,15 @@ internal static CompletionResult Null /// The text for the tooltip with details to be displayed about the object. public CompletionResult(string completionText, string listItemText, CompletionResultType resultType, string toolTip) { - if (string.IsNullOrEmpty(completionText)) - { - throw PSTraceSource.NewArgumentNullException(nameof(completionText)); - } - - if (string.IsNullOrEmpty(listItemText)) - { - throw PSTraceSource.NewArgumentNullException(nameof(listItemText)); - } + ArgumentException.ThrowIfNullOrEmpty(completionText); + ArgumentException.ThrowIfNullOrEmpty(listItemText); + ArgumentException.ThrowIfNullOrEmpty(toolTip); if (resultType < CompletionResultType.Text || resultType > CompletionResultType.DynamicKeyword) { throw PSTraceSource.NewArgumentOutOfRangeException(nameof(resultType), resultType); } - if (string.IsNullOrEmpty(toolTip)) - { - throw PSTraceSource.NewArgumentNullException(nameof(toolTip)); - } - _completionText = completionText; _listItemText = listItemText; _toolTip = toolTip; From 9bc47950e20d1d85710dbf424270e54a649fd3ac Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 12 Jan 2026 10:47:41 -0800 Subject: [PATCH 248/378] Add `ValidateNotNullOrEmpty` attribute to the `-Property` of `Format-Table/List/Custom` (#26552) --- .../FormatAndOutput/format-object/Format-Object.cs | 1 + .../common/BaseFormattingCommand.cs | 1 + test/powershell/engine/Formatting/BugFix.Tests.ps1 | 14 ++++++++++++++ 3 files changed, 16 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs index c2c16ff2cd1..693a799c809 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-object/Format-Object.cs @@ -32,6 +32,7 @@ public FormatCustomCommand() /// will be determined using property sets, etc. /// [Parameter(Position = 0)] + [ValidateNotNullOrEmpty] public object[] Property { get { return _props; } diff --git a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs index 683553a3b30..be31a1db9a8 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/BaseFormattingCommand.cs @@ -728,6 +728,7 @@ public class OuterFormatTableAndListBase : OuterFormatShapeCommandBase /// will be determined using property sets, etc. ///
    [Parameter(Position = 0)] + [ValidateNotNullOrEmpty] public object[] Property { get; set; } /// diff --git a/test/powershell/engine/Formatting/BugFix.Tests.ps1 b/test/powershell/engine/Formatting/BugFix.Tests.ps1 index 5be7797134c..8b1ecdaccd9 100644 --- a/test/powershell/engine/Formatting/BugFix.Tests.ps1 +++ b/test/powershell/engine/Formatting/BugFix.Tests.ps1 @@ -63,3 +63,17 @@ Describe "Hidden properties should not be returned by the 'FirstOrDefault' primi $outstring.Trim() | Should -BeExactly "Param$([System.Environment]::NewLine)-----$([System.Environment]::NewLine)Foo" } } + +Describe "'Format-Table/List/Custom -Property' should not throw NullRef exception" -Tag CI { + + It "' -Property' requires value to be not null and not empty" -TestCases @( + @{ Command = "Format-Table"; NameInErrorId = "FormatTableCommand" } + @{ Command = "Format-List"; NameInErrorId = "FormatListCommand" } + @{ Command = "Format-Custom"; NameInErrorId = "FormatCustomCommand" } + ) { + param($Command, $NameInErrorId) + + { Get-Process -Id $PID | & $Command -Property @() } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.$NameInErrorId" + { Get-Process -Id $PID | & $Command -Property $null } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.$NameInErrorId" + } +} From 20382c85654caa53d2403db17857952775cf7ecd Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 12 Jan 2026 10:50:04 -0800 Subject: [PATCH 249/378] Update outdated package references (#26656) --- test/xUnit/xUnit.tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 0863a23d441..de5b04b8c6c 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -24,12 +24,12 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + From 76bc34e08114639bf2640cc0a708fac900f1e160 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:26:44 -0800 Subject: [PATCH 250/378] Bump github/codeql-action from 4.31.9 to 4.31.10 (#26686) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 07a63c2e348..04c5b6cb58f 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 + uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 + uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 9b09c232801..87b593164a4 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 + uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 with: sarif_file: results.sarif From 1241ad2794cc84c18554e36ce658bfd86781cf8e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:58:38 -0500 Subject: [PATCH 251/378] Remove unused runCodesignValidationInjection variable from pipeline templates (#26412) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk (HE/HIM) --- .pipelines/templates/compliance/apiscan.yml | 2 -- .pipelines/templates/compliance/generateNotice.yml | 2 -- .pipelines/templates/linux-package-build.yml | 2 -- .pipelines/templates/linux.yml | 4 ---- .pipelines/templates/mac-package-build.yml | 2 -- .pipelines/templates/mac.yml | 2 -- .pipelines/templates/nupkg.yml | 2 -- .pipelines/templates/packaging/windows/package.yml | 2 -- .pipelines/templates/release-symbols.yml | 2 -- .pipelines/templates/release-upload-buildinfo.yml | 2 -- .pipelines/templates/testartifacts.yml | 4 ---- .pipelines/templates/uploadToAzure.yml | 2 -- .pipelines/templates/variable/release-shared.yml | 2 -- .pipelines/templates/windows-hosted-build.yml | 2 -- 14 files changed, 32 deletions(-) diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 5809af8e28c..b5a15699026 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -4,8 +4,6 @@ jobs: - job: APIScan variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ReleaseTagVar diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 7de316e8b49..0a38ed8f8e6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -10,8 +10,6 @@ parameters: jobs: - job: generateNotice variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ob_outputDirectory diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index bcf332b3778..ea49b9fea5d 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -13,8 +13,6 @@ jobs: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index aef0b53381f..97b594830b3 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -10,8 +10,6 @@ jobs: pool: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO @@ -139,8 +137,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 4e7040d4acc..def866173ac 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -15,8 +15,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index ff4787b9bcf..1699207c657 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -13,8 +13,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 3a2aa4f3172..3558c949402 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -6,8 +6,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 03673d61c7b..1f03d65ab21 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -9,8 +9,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: ob_sdl_codeSignValidation_enabled value: false # Skip signing validation in build-only stage - name: ob_signing_setup_enabled diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml index 1023dcf5259..a628f4d7127 100644 --- a/.pipelines/templates/release-symbols.yml +++ b/.pipelines/templates/release-symbols.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c18c96fc646..e32272c6306 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -14,8 +14,6 @@ jobs: demands: - ImageOverride -equals PSMMS2019-Secure variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 751c9d5a53b..3a6bec4a859 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -1,8 +1,6 @@ jobs: - job: build_testartifacts_win variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess @@ -73,8 +71,6 @@ jobs: - job: build_testartifacts_nonwin variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 20842de81cc..ce7f26131cc 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -7,8 +7,6 @@ jobs: variables: - name: ob_sdl_sbom_enabled value: true - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml index 325f72224f5..70d3dd2df97 100644 --- a/.pipelines/templates/variable/release-shared.yml +++ b/.pipelines/templates/variable/release-shared.yml @@ -17,8 +17,6 @@ variables: value: false - name: ob_sdl_sbom_enabled value: ${{ parameters.SBOM }} - - name: runCodesignValidationInjection - value: false - name: DOTNET_NOLOGO value: 1 - group: 'mscodehub-code-read-akv' diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 44b83ad20aa..83c6b32cdfd 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO From bd33c2d9878a46af65968da42fc4411bcd7bc46d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 14 Jan 2026 14:38:37 -0800 Subject: [PATCH 252/378] Update metadata.json to update the Latest attribute with a better name (#26380) --- .pipelines/templates/channelSelection.yml | 8 ++++---- .pipelines/templates/release-prep-for-ev2.yml | 8 ++++---- .pipelines/templates/release-upload-buildinfo.yml | 4 ++-- tools/metadata.json | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 9dd0f3fb216..d6ddb53256e 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,6 +2,10 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + + $LTS = $metadata.LTSRelease.PublishToChannels + $Stable = $metadata.StableRelease.PublishToChannels + $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' $releaseTag = '$(OutputReleaseTag.releaseTag)' # Rebuild branches should be treated as preview builds @@ -11,10 +15,6 @@ steps: # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' - $LTS = $metadata.LTSRelease.Latest - $Stable = $metadata.StableRelease.Latest - $isPreview = $releaseTag -match '-' - # If this is a rebuild branch, force preview mode and ignore LTS metadata if ($isRebuildBranch) { $IsLTS = $false diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index cf7982cd5e1..e644bece68f 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -33,7 +33,7 @@ stages: - template: release-SetReleaseTagandContainerName.yml parameters: restorePhase: true - + - pwsh: | $packageVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '^v','' $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" @@ -42,7 +42,7 @@ stages: displayName: Set Package version env: ob_restore_phase: true - + - pwsh: | $branch = 'mirror-target' $gitArgs = "clone", @@ -151,7 +151,7 @@ stages: $metadataHash = @{} $skipPublishValue = '${{ parameters.skipPublish }}' $metadataHash["ReleaseTag"] = '$(OutputReleaseTag.ReleaseTag)' - $metadataHash["LTS"] = $metadata.LTSRelease.Latest + $metadataHash["LTS"] = $metadata.LTSRelease.PublishToChannels $metadataHash["ForProduction"] = $true $metadataHash["SkipPublish"] = [System.Convert]::ToBoolean($skipPublishValue) @@ -222,7 +222,7 @@ stages: files_to_sign: '*.ps1' search_root: '$(repoRoot)/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run' displayName: Sign Run.ps1 - + - pwsh: | # folder to tar must have: Run.ps1, settings.toml, python_dl $srcPath = Join-Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'Shell' diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index e32272c6306..bcb2a43396f 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -56,8 +56,8 @@ jobs: $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableRelease = $metadata.StableRelease.Latest - $ltsRelease = $metadata.LTSRelease.Latest + $stableRelease = $metadata.StableRelease.PublishToChannels + $ltsRelease = $metadata.LTSRelease.PublishToChannels Write-Verbose -Verbose "Writing $jsonFile contents:" $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw diff --git a/tools/metadata.json b/tools/metadata.json index bbe64d0cefe..e0f4952c588 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -5,6 +5,6 @@ "ReleaseTag": "v7.5.4", "LTSReleaseTag" : ["v7.4.13"], "NextReleaseTag": "v7.6.0-preview.6", - "LTSRelease": { "Latest": false, "Package": false }, - "StableRelease": { "Latest": false, "Package": false } + "LTSRelease": { "PublishToChannels": false, "Package": false }, + "StableRelease": { "PublishToChannels": false, "Package": false } } From 5fdc2a023f9591bc467cdeff17dfaea6820f40bd Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:40:58 -0500 Subject: [PATCH 253/378] Fix macOS preview package identifier detection to use version string (#26690) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- test/packaging/packaging.tests.ps1 | 67 +++++++++++++++++++++++++++++ tools/packaging/packaging.psm1 | 69 ++++++++++++++++++++++-------- 2 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 test/packaging/packaging.tests.ps1 diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 new file mode 100644 index 00000000000..cc4bbe0d728 --- /dev/null +++ b/test/packaging/packaging.tests.ps1 @@ -0,0 +1,67 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Packaging Module Functions" { + BeforeAll { + Import-Module $PSScriptRoot/../../build.psm1 -Force + Import-Module $PSScriptRoot/../../tools/packaging/packaging.psm1 -Force + } + + Context "Test-IsPreview function" { + It "Should return True for preview versions" { + Test-IsPreview -Version "7.6.0-preview.6" | Should -Be $true + Test-IsPreview -Version "7.5.0-rc.1" | Should -Be $true + } + + It "Should return False for stable versions" { + Test-IsPreview -Version "7.6.0" | Should -Be $false + Test-IsPreview -Version "7.5.0" | Should -Be $false + } + + It "Should return False for LTS builds regardless of version string" { + Test-IsPreview -Version "7.6.0-preview.6" -IsLTS | Should -Be $false + Test-IsPreview -Version "7.5.0" -IsLTS | Should -Be $false + } + } + + Context "Get-MacOSPackageIdentifierInfo function (New-MacOSPackage logic)" { + It "Should detect preview builds and return preview identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + + $result.IsPreview | Should -Be $true + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + + It "Should detect stable builds and return stable identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0" -LTS:$false + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should treat LTS builds as stable even with preview version string" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.4.0-preview.1" -LTS:$true + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should NOT use package name for preview detection (bug fix verification)" { + # This test verifies the fix for issue #26673 + # The bug was using ($Name -like '*-preview') which always returned false + # because preview builds use Name="powershell" not "powershell-preview" + + $Version = "7.6.0-preview.6" + $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" + + # The INCORRECT logic (the bug): $Name -like '*-preview' + $incorrectCheck = $Name -like '*-preview' + $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" + + # The CORRECT logic (the fix): uses version string + $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false + $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + } +} diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8f9cec71790..cddde65aa9f 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1371,6 +1371,7 @@ function New-UnixPackage { AppsFolder = $AppsFolder HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation + LTS = $LTS } try { @@ -1515,7 +1516,12 @@ function New-MacOsDistributionPackage # Get package ID if not provided if (-not $PackageIdentifier) { - $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + if ($IsPreview.IsPresent) { + $PackageIdentifier = 'com.microsoft.powershell-preview' + } + else { + $PackageIdentifier = 'com.microsoft.powershell' + } } # Minimum OS version @@ -1984,7 +1990,9 @@ function New-MacOSPackage [Parameter(Mandatory)] [string]$HostArchitecture, - [string]$CurrentLocation = (Get-Location) + [string]$CurrentLocation = (Get-Location), + + [switch]$LTS ) Write-Log "Creating macOS package using pkgbuild and productbuild..." @@ -2059,8 +2067,10 @@ function New-MacOSPackage Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force } - # Build the component package using pkgbuild - $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + # Get package identifier info based on version and LTS flag + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $pkgIdentifier = $packageInfo.PackageIdentifier if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." @@ -2085,7 +2095,7 @@ function New-MacOSPackage -OutputDirectory $CurrentLocation ` -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` - -IsPreview:($Name -like '*-preview') + -IsPreview:$IsPreview return $distributionPackage } @@ -2292,20 +2302,44 @@ function New-ManGzip } } -# Returns the macOS Package Identifier -function Get-MacOSPackageId +<# + .SYNOPSIS + Determines the package identifier and preview status for macOS packages. + .DESCRIPTION + This function determines if a package is a preview build based on the version string + and LTS flag, then returns the appropriate package identifier. + .PARAMETER Version + The version string (e.g., "7.6.0-preview.6" or "7.6.0") + .PARAMETER LTS + Whether this is an LTS build + .OUTPUTS + Hashtable with IsPreview (boolean) and PackageIdentifier (string) properties + .EXAMPLE + Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + Returns @{ IsPreview = $true; PackageIdentifier = "com.microsoft.powershell-preview" } +#> +function Get-MacOSPackageIdentifierInfo { param( - [switch] - $IsPreview + [Parameter(Mandatory)] + [string]$Version, + + [switch]$LTS ) - if ($IsPreview.IsPresent) - { - return 'com.microsoft.powershell-preview' + + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # Determine package identifier based on preview status + if ($IsPreview) { + $PackageIdentifier = 'com.microsoft.powershell-preview' } - else - { - return 'com.microsoft.powershell' + else { + $PackageIdentifier = 'com.microsoft.powershell' + } + + return @{ + IsPreview = $IsPreview + PackageIdentifier = $PackageIdentifier } } @@ -2319,8 +2353,9 @@ function New-MacOSLauncher [switch]$LTS ) - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $packageId = $packageInfo.PackageIdentifier # Define folder for launcher application. $suffix = if ($IsPreview) { "-preview" } elseif ($LTS) { "-lts" } From 276989fa55e1e48279467719d873657e337f63a6 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 20 Jan 2026 14:36:04 -0500 Subject: [PATCH 254/378] Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc1 (#26691) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index b6e5506e0b0..cbc47ef200c 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 0931a75d3e4a177c2f1691e50d4124ca229f234b Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 20 Jan 2026 18:26:59 -0600 Subject: [PATCH 255/378] Fix `buildinfo.json` uploading for preview, LTS, and stable releases (#25571) --- .../templates/release-upload-buildinfo.yml | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index bcb2a43396f..c470af1fd6e 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -56,6 +56,9 @@ jobs: $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json + $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' + + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' $stableRelease = $metadata.StableRelease.PublishToChannels $ltsRelease = $metadata.LTSRelease.PublishToChannels @@ -65,40 +68,44 @@ jobs: $buildInfo = $buildInfoJsonContent | ConvertFrom-Json $buildInfo.ReleaseDate = $dateTime + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($stableRelease -or $fileName -eq "preview.json") { - Set-BuildVariable -Name CopyMainBuildInfo -Value YES + if ($fileName -eq "preview.json") { + Set-BuildVariable -Name UploadPreview -Value YES } else { - Set-BuildVariable -Name CopyMainBuildInfo -Value NO + Set-BuildVariable -Name UploadPreview -Value NO } - Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile - - ## Create 'lts.json' if it's the latest stable and also a LTS release. + Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile + ## Create 'lts.json' if marked as a LTS release. if ($fileName -eq "stable.json") { + [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force - Set-BuildVariable -Name LtsBuildInfoJsonFile -Value $ltsFile - Set-BuildVariable -Name CopyLTSBuildInfo -Value YES + Set-BuildVariable -Name LTSBuildInfoFile -Value $ltsFile + Set-BuildVariable -Name UploadLTS -Value YES } else { - Set-BuildVariable -Name CopyLTSBuildInfo -Value NO + Set-BuildVariable -Name UploadLTS -Value NO } - $releaseTag = $buildInfo.ReleaseTag - $version = $releaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version + ## Only update the stable.json if the current version is greater than the stable version. + if ($currentVersion -gt $stableVersion) { + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadStable -Value YES + } else { + Set-BuildVariable -Name UploadStable -Value NO + } - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($semVersion.Major)-$($semVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name VersionBuildInfoJsonFile -Value $versionFile - Set-BuildVariable -Name CopyVersionBuildInfo -Value YES } else { - Set-BuildVariable -Name CopyVersionBuildInfo -Value NO + Set-BuildVariable -Name UploadStable -Value NO } displayName: Create json files @@ -116,24 +123,27 @@ jobs: $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount - if ($env:CopyMainBuildInfo -eq 'YES') { - $jsonFile = "$env:BuildInfoJsonFile" + #preview + if ($env:UploadPreview -eq 'YES') { + $jsonFile = "$env:PreviewBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyLTSBuildInfo -eq 'YES') { - $jsonFile = "$env:LtsBuildInfoJsonFile" + #LTS + if ($env:UploadLTS -eq 'YES') { + $jsonFile = "$env:LTSBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyVersionBuildInfo -eq 'YES') { - $jsonFile = "$env:VersionBuildInfoJsonFile" + #stable + if ($env:UploadStable -eq 'YES') { + $jsonFile = "$env:StableBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) From dab346a6b7426e3b7bb4a074ac5b856129d4692d Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:50:23 -0800 Subject: [PATCH 256/378] Move PowerShell build to depend on .NET SDK 10.0.102 (#26697) Co-authored-by: Dongbo Wang --- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +-- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 102 +++++++++--------- 12 files changed, 71 insertions(+), 71 deletions(-) diff --git a/global.json b/global.json index 936a420a573..c2af57a3fe4 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.101" + "version": "10.0.102" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index f63196d3645..32e0d329886 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index b2622f0517f..7d9d61ede96 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index b99139eb68e..5ee999c2d9c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index feea5665288..78232a2f1af 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index d3446d28c98..161170355e6 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 178f0473f26..da5ea7ddd04 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 542fa8526ff..9b5e21811cf 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 03aa5697267..af62ecaacab 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index db2fde85955..cbb01a67da5 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index de5b04b8c6c..6ce2ee32ceb 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -29,7 +29,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index efbc103f25e..1001370ade7 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -46,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "6.0.0" + "Version": "6.0.1" } }, "DevelopmentDependency": false @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -126,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -166,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -176,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -186,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -226,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -336,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -376,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -436,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -446,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -456,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -476,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -536,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -616,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -626,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -646,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -716,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -726,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -746,10 +745,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From f5c290ccd6463d63968dda734a282c10a5b499ec Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 22 Jan 2026 04:52:08 +1000 Subject: [PATCH 257/378] Fix WSManInstance COM interface with ResourceURI (#26692) --- src/Microsoft.WSMan.Management/Interop.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.WSMan.Management/Interop.cs b/src/Microsoft.WSMan.Management/Interop.cs index e5dd462e2f7..3abb938a572 100644 --- a/src/Microsoft.WSMan.Management/Interop.cs +++ b/src/Microsoft.WSMan.Management/Interop.cs @@ -734,18 +734,19 @@ public interface IWSManResourceLocator [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] string ResourceUri { - // IDL: HRESULT resourceUri ([out, retval] BSTR* ReturnValue); + // IDL: HRESULT resourceUri (BSTR value); + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:PropertyAccessorsMustFollowOrder", Justification = "COM interface defines put_ before get_.")] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "resource")] [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] [DispId(1)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + set; - // IDL: HRESULT resourceUri (BSTR value); + // IDL: HRESULT resourceUri ([out, retval] BSTR* ReturnValue); [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "resource")] [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")] [DispId(1)] - set; + [return: MarshalAs(UnmanagedType.BStr)] + get; } /// AddSelector method of IWSManResourceLocator interface. Add selector to resource locator @@ -818,14 +819,16 @@ string FragmentDialect int MustUnderstandOptions { - // IDL: HRESULT MustUnderstandOptions ([out, retval] long* ReturnValue); - - [DispId(7)] - get; // IDL: HRESULT MustUnderstandOptions (long value); + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:PropertyAccessorsMustFollowOrder", Justification = "COM interface defines put_ before get_.")] [DispId(7)] set; + + // IDL: HRESULT MustUnderstandOptions ([out, retval] long* ReturnValue); + + [DispId(7)] + get; } /// ClearOptions method of IWSManResourceLocator interface. Clear all options From 7f9c7463f203393f06cbc82f4154d1d8420019bb Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 22 Jan 2026 04:55:42 +1000 Subject: [PATCH 258/378] Support TargetObject position in ParserErrors (#26649) --- .../PowerShellCore_format_ps1xml.cs | 29 ++ .../engine/Formatting/ErrorView.Tests.ps1 | 381 ++++++++++++++++++ 2 files changed, 410 insertions(+) diff --git a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs index ef0d506d122..24d99d4dd4b 100644 --- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs +++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs @@ -1190,8 +1190,37 @@ function Get-ConciseViewPositionMessage { $highlightLine = '' if ($useTargetObject) { $line = $_.TargetObject.LineText.Trim() + $offsetLength = 0 $offsetInLine = 0 + $startColumn = 0 + if ( + ([System.Collections.IDictionary]$_.TargetObject).Contains('StartColumn') -and + [System.Management.Automation.LanguagePrimitives]::TryConvertTo[int]($_.TargetObject.StartColumn, [ref]$startColumn) -and + $null -ne $startColumn -and + $startColumn -gt 0 -and + $startColumn -le $line.Length + ) { + $endColumn = 0 + if (-not ( + ([System.Collections.IDictionary]$_.TargetObject).Contains('EndColumn') -and + [System.Management.Automation.LanguagePrimitives]::TryConvertTo[int]($_.TargetObject.EndColumn, [ref]$endColumn) -and + $null -ne $endColumn -and + $endColumn -gt $startColumn -and + $endColumn -le ($line.Length + 1) + )) { + $endColumn = $line.Length + 1 + } + + # Input is expected to be 1-based index to match the extent positioning + # but we use 0-based indexing below. + $startColumn -= 1 + $endColumn -= 1 + + $highlightLine = "$(" " * $startColumn)$("~" * ($endColumn - $startColumn))" + $offsetLength = $endColumn - $startColumn + $offsetInLine = $startColumn + } } else { $positionMessage = $myinv.PositionMessage.Split($newline) diff --git a/test/powershell/engine/Formatting/ErrorView.Tests.ps1 b/test/powershell/engine/Formatting/ErrorView.Tests.ps1 index 519b9403b9e..6af2b5fb504 100644 --- a/test/powershell/engine/Formatting/ErrorView.Tests.ps1 +++ b/test/powershell/engine/Formatting/ErrorView.Tests.ps1 @@ -165,6 +165,387 @@ Describe 'Tests for $ErrorView' -Tag CI { $e | Out-String | Should -BeLike '*ParserError*' } + It 'Parser TargetObject shows Line information' { + $expected = (@( + ": " + "Line |" + " 1 | This is the line with the error" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + Line = 1 + LineText = 'This is the line with the error' + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject shows File information' { + $expected = (@( + ": MyFile.ps1" + "Line |" + " 1 | This is the line with the error" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + File = 'MyFile.ps1' + Line = 1 + LineText = 'This is the line with the error' + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject has StartColumn' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~~~~~~~~~~~~~~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = 18 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject has StartColumn and EndColumn' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~~~~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = 18 + EndColumn = 22 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject has StartColumn at end of the line' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = 31 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + + It 'Parser TargetObject has StartColumn at end of the line with EndColumn' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = 31 + EndColumn = 32 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject ignores EndColumn if no StartColumn' { + $expected = (@( + ": " + "Line |" + " 1 | This is the line with the error" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + Line = 1 + LineText = 'This is the line with the error' + EndColumn = 22 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject converts StartColumn and EndColumn from string' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~~~~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = "18" + EndColumn = "22" + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject ignores StartColumn if it cannot be converted' { + $expected = (@( + ": " + "Line |" + " 1 | This is the line with the error" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + Line = 1 + LineText = 'This is the line with the error' + StartColumn = 'abc' + EndColumn = 22 + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject ignores EndColumn if it cannot be converted' { + $expected = (@( + ": " + "Line |" + " 5 | This is the line with the error" + " | ~~~~~~~~~~~~~~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + + Line = 5 + LineText = 'This is the line with the error' + StartColumn = 18 + EndColumn = 'abc' + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject ignores StartColumn with invalid value ' -TestCases @( + @{ Value = -1 } + @{ Value = 0 } + @{ Value = 32 } # Beyond end of line + ) { + param ($Value) + + $expected = (@( + ": " + "Line |" + " 1 | This is the line with the error" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + Line = 1 + LineText = 'This is the line with the error' + StartColumn = $Value + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + + It 'Parser TargetObject ignores EndColumn with invalid value ' -TestCases @( + @{ Value = -1 } + @{ Value = 0 } + @{ Value = 17 } # Before StartColumn + @{ Value = 18 } # Equal to StartColumn + @{ Value = 33 } # Beyond end of line + 1 + ) { + param ($Value) + + $expected = (@( + ": " + "Line |" + " 1 | This is the line with the error" + " | ~~~~~~~~~~~~~~" + " | Test Parser Error" + ) -join ([Environment]::NewLine)).TrimEnd() + $e = { + [CmdletBinding()] + param () + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Test Parser Error'), + 'ParserErrorText', + [System.Management.Automation.ErrorCategory]::ParserError, + @{ + Line = 1 + LineText = 'This is the line with the error' + StartColumn = 18 + EndColumn = $Value + } + ) + ) + } | Should -Throw -PassThru + + $actual = ($e | Out-String).TrimEnd() + $actual | Should -BeExactly $expected + } + It 'Exception thrown from Enumerator.MoveNext in a pipeline shows information' { $e = { $l = [System.Collections.Generic.List[string]] @('one', 'two') From f57643fb9f9dab8e0a6afdad8dc0f5921375cc85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:10:48 -0500 Subject: [PATCH 259/378] Bump github/codeql-action from 4.31.10 to 4.32.0 (#26726) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 04c5b6cb58f..44000b71d5f 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 + uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 + uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 87b593164a4..f2c806750a6 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 + uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 with: sarif_file: results.sarif From b3a38645af47133e2b19d8a5bdf535c9f2333b64 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:02:48 -0800 Subject: [PATCH 260/378] Add policy to restrict the `Approved-LowRisk` label (#26728) --- .../policies/labelAdded.approvedLowRisk.yml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/policies/labelAdded.approvedLowRisk.yml diff --git a/.github/policies/labelAdded.approvedLowRisk.yml b/.github/policies/labelAdded.approvedLowRisk.yml new file mode 100644 index 00000000000..bdeea5265a0 --- /dev/null +++ b/.github/policies/labelAdded.approvedLowRisk.yml @@ -0,0 +1,48 @@ +id: labelAdded.approvedLowRisk +name: GitOps.PullRequestIssueManagement +description: Remove Approved-LowRisk if applied by an unauthorized user +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: Remove Approved-LowRisk if label was added by someone not authorized + if: + - payloadType: Pull_Request + - isOpen + - labelAdded: + label: Approved-LowRisk + # Unauthorized = NOT admin AND NOT in explicit allowlist + - not: + or: + - activitySenderHasPermission: + permission: Admin + + # Allowlist (enabled) + - isActivitySender: + user: iSazonov + issueAuthor: False + - isActivitySender: + user: daxian-dbw + issueAuthor: False + + # Allowlist (commented out for now) + # - isActivitySender: + # user: TravisEz13 + # issueAuthor: False + # - isActivitySender: + # user: adityapatwardhan + # issueAuthor: False + # - isActivitySender: + # user: jshigetomi + # issueAuthor: False + then: + - removeLabel: + label: Approved-LowRisk + - addReply: + reply: >- + The `Approved-LowRisk` label is restricted to authorized maintainers and was removed. +onFailure: +onSuccess: From 8489f8fc34669170c5099d0aacd9d3fc8b3ea255 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Thu, 29 Jan 2026 07:06:15 +0900 Subject: [PATCH 261/378] Mark `-NoTypeInformation` as obsolete no-op and evaluate `-IncludeTypeInformation` on by value on Csv cmdlets (#26719) --- .../commands/utility/CsvCommands.cs | 22 +++++-------------- .../resources/CsvCommandStrings.resx | 3 --- .../ConvertTo-Csv.Tests.ps1 | 5 ----- .../Export-Csv.Tests.ps1 | 5 ----- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index e84a79b99b6..cb455417531 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -45,17 +45,19 @@ public abstract class BaseCsvWritingCommand : PSCmdlet public abstract PSObject InputObject { get; set; } /// - /// IncludeTypeInformation : The #TYPE line should be generated. Default is false. Cannot specify with NoTypeInformation. + /// IncludeTypeInformation : The #TYPE line should be generated. Default is false. /// [Parameter] [Alias("ITI")] public SwitchParameter IncludeTypeInformation { get; set; } /// - /// NoTypeInformation : The #TYPE line should not be generated. Default is true. Cannot specify with IncludeTypeInformation. + /// Gets or sets a value indicating whether to suppress the #TYPE line. + /// This parameter is obsolete and has no effect. It is retained for backward compatibility only. /// [Parameter(DontShow = true)] [Alias("NTI")] + [Obsolete("This parameter is obsolete and has no effect. The default behavior is to not include type information. Use -IncludeTypeInformation to include type information.")] public SwitchParameter NoTypeInformation { get; set; } = true; /// @@ -120,18 +122,6 @@ protected override void BeginProcessing() this.ThrowTerminatingError(errorRecord); } - if (this.MyInvocation.BoundParameters.ContainsKey(nameof(IncludeTypeInformation)) && this.MyInvocation.BoundParameters.ContainsKey(nameof(NoTypeInformation))) - { - InvalidOperationException exception = new(CsvCommandStrings.CannotSpecifyIncludeTypeInformationAndNoTypeInformation); - ErrorRecord errorRecord = new(exception, "CannotSpecifyIncludeTypeInformationAndNoTypeInformation", ErrorCategory.InvalidData, null); - this.ThrowTerminatingError(errorRecord); - } - - if (this.MyInvocation.BoundParameters.ContainsKey(nameof(IncludeTypeInformation))) - { - NoTypeInformation = !IncludeTypeInformation; - } - Delimiter = ImportExportCSVHelper.SetDelimiter(this, ParameterSetName, Delimiter, UseCulture); } } @@ -317,7 +307,7 @@ protected override void ProcessRecord() // write headers (row1: typename + row2: column names) if (!_isActuallyAppending && !NoHeader.IsPresent) { - if (NoTypeInformation == false) + if (IncludeTypeInformation) { WriteCsvLine(ExportCsvHelper.GetTypeString(InputObject)); } @@ -742,7 +732,7 @@ protected override void ProcessRecord() if (!NoHeader.IsPresent) { - if (NoTypeInformation == false) + if (IncludeTypeInformation) { WriteCsvLine(ExportCsvHelper.GetTypeString(InputObject)); } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx index 8c5ded13465..dde1be6ab49 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx @@ -130,9 +130,6 @@ You must specify either the -UseQuotes or -QuoteFields parameters, but not both. - - You must specify either the -IncludeTypeInformation or -NoTypeInformation parameters, but not both. - You must specify either the -Path or -LiteralPath parameters, but not both. diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 index 298b8140468..bfba7718272 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 @@ -101,11 +101,6 @@ Describe "ConvertTo-Csv" -Tags "CI" { Should -Throw -ErrorId "CannotSpecifyQuoteFieldsAndUseQuotes,Microsoft.PowerShell.Commands.ConvertToCsvCommand" } - It "Does not support -IncludeTypeInformation and -NoTypeInformation at the same time" { - { $testObject | ConvertTo-Csv -IncludeTypeInformation -NoTypeInformation } | - Should -Throw -ErrorId "CannotSpecifyIncludeTypeInformationAndNoTypeInformation,Microsoft.PowerShell.Commands.ConvertToCsvCommand" - } - Context "QuoteFields parameter" { It "QuoteFields" { # Use 'FiRstCoLumn' to test case insensitivity diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 index ea05d66d392..aae457f2f82 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 @@ -91,11 +91,6 @@ Describe "Export-Csv" -Tags "CI" { $results[0] | Should -BeExactly "#TYPE System.String" } - It "Does not support -IncludeTypeInformation and -NoTypeInformation at the same time" { - { $testObject | Export-Csv -Path $testCsv -IncludeTypeInformation -NoTypeInformation } | - Should -Throw -ErrorId "CannotSpecifyIncludeTypeInformationAndNoTypeInformation,Microsoft.PowerShell.Commands.ExportCsvCommand" - } - It "Should support -LiteralPath parameter" { $testObject | Export-Csv -LiteralPath $testCsv $results = Import-Csv -Path $testCsv From 34f6e267a4a779616f0f441ee034dbf4747c482b Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 2 Feb 2026 19:45:16 -0500 Subject: [PATCH 262/378] Add CodeQL suppressions for NativeCommandProcessor (#26729) --- .../engine/NativeCommandProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 75e3b468814..145fe968fda 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -831,6 +831,7 @@ private void InitNativeProcess() bool useSpecialArgumentPassing = UseSpecialArgumentPassing(oldFileName); if (useSpecialArgumentPassing) { + // codeql[cs/microsoft/command-line-injection] - This is expected PowerShell behavior where user inputted paths are supported for the context of this method and the path portion of the argument is escaped. The user assumes trust for the file path specified on the user's system to start process for, and in the case of remoting, restricted remoting security guidelines should be used. startInfo.Arguments = "\"" + oldFileName + "\" " + startInfo.Arguments; } else @@ -855,7 +856,7 @@ private void InitNativeProcess() startInfo.ArgumentList.RemoveAt(0); } - // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected PowerShell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. startInfo.FileName = oldFileName; } } @@ -1607,7 +1608,7 @@ private ProcessStartInfo GetProcessStartInfo( { var startInfo = new ProcessStartInfo { - // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. + // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected PowerShell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified on the user's system to retrieve process info for, and in the case of remoting, restricted remoting security guidelines should be used. FileName = this.Path }; From 467059c9cbe3e40fb1026312b8c3f9711260938f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:46:51 -0500 Subject: [PATCH 263/378] Bump github/codeql-action from 4.32.0 to 4.32.1 (#26741) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 44000b71d5f..b56d2d6635c 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 + uses: github/codeql-action/init@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 + uses: github/codeql-action/analyze@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f2c806750a6..d1d974f8efa 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5 + uses: github/codeql-action/upload-sarif@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 with: sarif_file: results.sarif From d54977441f96cebb2b93fbb2364010d02fb00ffa Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 4 Feb 2026 11:38:48 -0800 Subject: [PATCH 264/378] Update `Microsoft.PowerShell.Native` package version (#26746) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 9b5e21811cf..8c77c770a8f 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -40,7 +40,7 @@ - + From dd4f2fecfaf2e9dc1fbb8831fa47c8b0907c03a3 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Fri, 6 Feb 2026 08:51:22 +0900 Subject: [PATCH 265/378] Add comprehensive scalar type tests for `ConvertTo-Json` (#26736) --- .../ConvertTo-Json.Tests.ps1 | 429 ++++++++++++++++++ 1 file changed, 429 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index 1f2abe05c68..4ac0818faf4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -156,4 +156,433 @@ Describe 'ConvertTo-Json' -tags "CI" { $actual = ConvertTo-Json -Compress -InputObject $obj $actual | Should -Be '{"Positive":18446744073709551615,"Negative":-18446744073709551615}' } + #region Comprehensive Scalar Type Tests (Phase 1) + # Test coverage for ConvertTo-Json scalar serialization + # Covers: Pipeline vs InputObject, ETS vs no ETS, all primitive and special types + + Context 'Primitive scalar types' { + It 'Should serialize value correctly via Pipeline and InputObject' -TestCases @( + # Byte types + @{ TypeName = 'byte'; Value = [byte]0; Expected = '0' } + @{ TypeName = 'byte'; Value = [byte]255; Expected = '255' } + @{ TypeName = 'sbyte'; Value = [sbyte]-128; Expected = '-128' } + @{ TypeName = 'sbyte'; Value = [sbyte]127; Expected = '127' } + # Short types + @{ TypeName = 'short'; Value = [short]-32768; Expected = '-32768' } + @{ TypeName = 'short'; Value = [short]32767; Expected = '32767' } + @{ TypeName = 'ushort'; Value = [ushort]0; Expected = '0' } + @{ TypeName = 'ushort'; Value = [ushort]65535; Expected = '65535' } + # Integer types + @{ TypeName = 'int'; Value = 42; Expected = '42' } + @{ TypeName = 'int'; Value = -42; Expected = '-42' } + @{ TypeName = 'int'; Value = 0; Expected = '0' } + @{ TypeName = 'int'; Value = [int]::MaxValue; Expected = '2147483647' } + @{ TypeName = 'int'; Value = [int]::MinValue; Expected = '-2147483648' } + @{ TypeName = 'uint'; Value = [uint]0; Expected = '0' } + @{ TypeName = 'uint'; Value = [uint]::MaxValue; Expected = '4294967295' } + # Long types + @{ TypeName = 'long'; Value = [long]::MaxValue; Expected = '9223372036854775807' } + @{ TypeName = 'long'; Value = [long]::MinValue; Expected = '-9223372036854775808' } + @{ TypeName = 'ulong'; Value = [ulong]0; Expected = '0' } + @{ TypeName = 'ulong'; Value = [ulong]::MaxValue; Expected = '18446744073709551615' } + # Floating-point types + @{ TypeName = 'float'; Value = [float]3.14; Expected = '3.14' } + @{ TypeName = 'float'; Value = [float]::NaN; Expected = '"NaN"' } + @{ TypeName = 'float'; Value = [float]::PositiveInfinity; Expected = '"Infinity"' } + @{ TypeName = 'float'; Value = [float]::NegativeInfinity; Expected = '"-Infinity"' } + @{ TypeName = 'double'; Value = 3.14159; Expected = '3.14159' } + @{ TypeName = 'double'; Value = -3.14159; Expected = '-3.14159' } + @{ TypeName = 'double'; Value = 0.0; Expected = '0.0' } + @{ TypeName = 'double'; Value = [double]::NaN; Expected = '"NaN"' } + @{ TypeName = 'double'; Value = [double]::PositiveInfinity; Expected = '"Infinity"' } + @{ TypeName = 'double'; Value = [double]::NegativeInfinity; Expected = '"-Infinity"' } + @{ TypeName = 'decimal'; Value = 123.456d; Expected = '123.456' } + # BigInteger + @{ TypeName = 'BigInteger'; Value = 18446744073709551615n; Expected = '18446744073709551615' } + # Boolean + @{ TypeName = 'bool'; Value = $true; Expected = 'true' } + @{ TypeName = 'bool'; Value = $false; Expected = 'false' } + # Null + @{ TypeName = 'null'; Value = $null; Expected = 'null' } + ) { + param($TypeName, $Value, $Expected) + $jsonPipeline = $Value | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $Value -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + It 'Should include ETS properties on ' -TestCases @( + @{ TypeName = 'int'; Value = 42; Expected = '{"value":42,"MyProp":"test"}' } + @{ TypeName = 'double'; Value = 3.14; Expected = '{"value":3.14,"MyProp":"test"}' } + ) { + param($TypeName, $Value, $Expected) + $valueWithEts = Add-Member -InputObject $Value -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $valueWithEts | ConvertTo-Json -Compress + $json | Should -BeExactly $Expected + } + } + + Context 'String scalar types' { + It 'Should serialize string correctly via Pipeline and InputObject' -TestCases @( + @{ Description = 'regular'; Value = 'hello'; Expected = '"hello"' } + @{ Description = 'empty'; Value = ''; Expected = '""' } + @{ Description = 'with spaces'; Value = 'hello world'; Expected = '"hello world"' } + @{ Description = 'with newline'; Value = "line1`nline2"; Expected = '"line1\nline2"' } + @{ Description = 'with tab'; Value = "col1`tcol2"; Expected = '"col1\tcol2"' } + @{ Description = 'with quotes'; Value = 'say "hello"'; Expected = '"say \"hello\""' } + @{ Description = 'with backslash'; Value = 'c:\path'; Expected = '"c:\\path"' } + @{ Description = 'unicode'; Value = '???'; Expected = '"???"' } + @{ Description = 'emoji'; Value = '??'; Expected = '"??"' } + ) { + param($Description, $Value, $Expected) + $jsonPipeline = $Value | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $Value -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + It 'Should ignore ETS properties on string' { + $str = Add-Member -InputObject 'hello' -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $str | ConvertTo-Json -Compress + $json | Should -BeExactly '"hello"' + } + } + + Context 'DateTime and related types' { + It 'Should serialize DateTime with UTC kind via Pipeline and InputObject' { + $dt = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Utc) + $jsonPipeline = $dt | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $dt -Compress + $jsonPipeline | Should -BeExactly '"2024-06-15T10:30:00Z"' + $jsonInputObject | Should -BeExactly '"2024-06-15T10:30:00Z"' + } + + It 'Should serialize DateTime with Local kind' { + $dt = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Local) + $json = $dt | ConvertTo-Json -Compress + $offset = $dt.ToString('zzz') + $expected = '"2024-06-15T10:30:00' + $offset + '"' + $json | Should -BeExactly $expected + } + + It 'Should serialize DateTime with Unspecified kind via Pipeline and InputObject' { + $dt = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Unspecified) + $jsonPipeline = $dt | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $dt -Compress + $jsonPipeline | Should -BeExactly '"2024-06-15T10:30:00"' + $jsonInputObject | Should -BeExactly '"2024-06-15T10:30:00"' + } + + It 'Should serialize DateTimeOffset correctly via Pipeline and InputObject' { + $dto = [DateTimeOffset]::new(2024, 6, 15, 10, 30, 0, [TimeSpan]::FromHours(9)) + $jsonPipeline = $dto | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $dto -Compress + $jsonPipeline | Should -BeExactly '"2024-06-15T10:30:00+09:00"' + $jsonInputObject | Should -BeExactly '"2024-06-15T10:30:00+09:00"' + } + + It 'Should serialize DateOnly as object with properties' { + $d = [DateOnly]::new(2024, 6, 15) + $json = $d | ConvertTo-Json -Compress + $json | Should -BeExactly '{"Year":2024,"Month":6,"Day":15,"DayOfWeek":6,"DayOfYear":167,"DayNumber":739051}' + } + + It 'Should serialize TimeOnly as object with properties' { + $t = [TimeOnly]::new(10, 30, 45) + $json = $t | ConvertTo-Json -Compress + $json | Should -BeExactly '{"Hour":10,"Minute":30,"Second":45,"Millisecond":0,"Microsecond":0,"Nanosecond":0,"Ticks":378450000000}' + } + + It 'Should serialize TimeSpan as object with properties' { + $ts = [TimeSpan]::new(1, 2, 3, 4, 5) + $json = $ts | ConvertTo-Json -Compress + $json | Should -BeExactly '{"Ticks":937840050000,"Days":1,"Hours":2,"Milliseconds":5,"Microseconds":0,"Nanoseconds":0,"Minutes":3,"Seconds":4,"TotalDays":1.0854630208333333,"TotalHours":26.0511125,"TotalMilliseconds":93784005.0,"TotalMicroseconds":93784005000.0,"TotalNanoseconds":93784005000000.0,"TotalMinutes":1563.06675,"TotalSeconds":93784.005}' + } + + It 'Should ignore ETS properties on DateTime' { + $dt = [DateTime]::new(2024, 6, 15, 0, 0, 0, [DateTimeKind]::Utc) + $dt = Add-Member -InputObject $dt -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $dt | ConvertTo-Json -Compress + $json | Should -BeExactly '"2024-06-15T00:00:00Z"' + } + + It 'Should include ETS properties on DateTimeOffset' { + $dto = [DateTimeOffset]::new(2024, 6, 15, 10, 30, 0, [TimeSpan]::Zero) + $dto = Add-Member -InputObject $dto -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $dto | ConvertTo-Json -Compress + $json | Should -BeExactly '{"value":"2024-06-15T10:30:00+00:00","MyProp":"test"}' + } + + It 'Should include ETS properties on DateOnly' { + $d = [DateOnly]::new(2024, 6, 15) + $d = Add-Member -InputObject $d -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $d | ConvertTo-Json -Compress + $json | Should -BeExactly '{"Year":2024,"Month":6,"Day":15,"DayOfWeek":6,"DayOfYear":167,"DayNumber":739051,"MyProp":"test"}' + } + + It 'Should include ETS properties on TimeOnly' { + $t = [TimeOnly]::new(10, 30, 45) + $t = Add-Member -InputObject $t -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $t | ConvertTo-Json -Compress + $json | Should -BeExactly '{"Hour":10,"Minute":30,"Second":45,"Millisecond":0,"Microsecond":0,"Nanosecond":0,"Ticks":378450000000,"MyProp":"test"}' + } + } + + Context 'Guid type' { + It 'Should serialize Guid as string via InputObject' { + $guid = [Guid]::new('12345678-1234-1234-1234-123456789abc') + $json = ConvertTo-Json -InputObject $guid -Compress + $json | Should -BeExactly '"12345678-1234-1234-1234-123456789abc"' + } + + It 'Should serialize Guid with Extended properties via Pipeline' { + $guid = [Guid]::new('12345678-1234-1234-1234-123456789abc') + $json = $guid | ConvertTo-Json -Compress + $json | Should -BeExactly '{"value":"12345678-1234-1234-1234-123456789abc","Guid":"12345678-1234-1234-1234-123456789abc"}' + } + + It 'Should serialize empty Guid correctly via InputObject' { + $json = ConvertTo-Json -InputObject ([Guid]::Empty) -Compress + $json | Should -BeExactly '"00000000-0000-0000-0000-000000000000"' + } + + It 'Should include ETS properties on Guid via Pipeline' { + $guid = [Guid]::new('12345678-1234-1234-1234-123456789abc') + $guid = Add-Member -InputObject $guid -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $guid | ConvertTo-Json -Compress + $json | Should -BeExactly '{"value":"12345678-1234-1234-1234-123456789abc","MyProp":"test","Guid":"12345678-1234-1234-1234-123456789abc"}' + } + } + + Context 'Uri type' { + It 'Should serialize Uri correctly via Pipeline and InputObject' -TestCases @( + @{ Description = 'http'; UriString = 'http://example.com'; Expected = '"http://example.com"' } + @{ Description = 'https with path'; UriString = 'https://example.com/path'; Expected = '"https://example.com/path"' } + @{ Description = 'with query'; UriString = 'https://example.com/search?q=test'; Expected = '"https://example.com/search?q=test"' } + @{ Description = 'file'; UriString = 'file:///c:/temp/file.txt'; Expected = '"file:///c:/temp/file.txt"' } + ) { + param($Description, $UriString, $Expected) + $uri = [Uri]$UriString + $jsonPipeline = $uri | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $uri -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + It 'Should include ETS properties on Uri' { + $uri = [Uri]'https://example.com' + $uri = Add-Member -InputObject $uri -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $uri | ConvertTo-Json -Compress + $json | Should -BeExactly '{"value":"https://example.com","MyProp":"test"}' + } + } + + Context 'Enum types' { + It 'Should serialize enum :: as via Pipeline and InputObject' -TestCases @( + @{ EnumType = 'System.DayOfWeek'; Value = 'Sunday'; Expected = '0' } + @{ EnumType = 'System.DayOfWeek'; Value = 'Monday'; Expected = '1' } + @{ EnumType = 'System.DayOfWeek'; Value = 'Saturday'; Expected = '6' } + @{ EnumType = 'System.ConsoleColor'; Value = 'Red'; Expected = '12' } + @{ EnumType = 'System.IO.FileAttributes'; Value = 'ReadOnly'; Expected = '1' } + @{ EnumType = 'System.IO.FileAttributes'; Value = 'Hidden'; Expected = '2' } + ) { + param($EnumType, $Value, $Expected) + $enumValue = [Enum]::Parse($EnumType, $Value) + $jsonPipeline = $enumValue | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $enumValue -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + It 'Should serialize enum as "" with -EnumsAsStrings' -TestCases @( + @{ EnumType = 'System.DayOfWeek'; Value = 'Sunday'; Expected = 'Sunday' } + @{ EnumType = 'System.DayOfWeek'; Value = 'Monday'; Expected = 'Monday' } + @{ EnumType = 'System.ConsoleColor'; Value = 'Red'; Expected = 'Red' } + ) { + param($EnumType, $Value, $Expected) + $enumValue = [Enum]::Parse($EnumType, $Value) + $json = $enumValue | ConvertTo-Json -Compress -EnumsAsStrings + $json | Should -BeExactly "`"$Expected`"" + } + + It 'Should serialize flags enum correctly via Pipeline and InputObject' { + $flags = [System.IO.FileAttributes]::ReadOnly -bor [System.IO.FileAttributes]::Hidden + $jsonPipeline = $flags | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $flags -Compress + $jsonPipeline | Should -BeExactly '3' + $jsonInputObject | Should -BeExactly '3' + } + + It 'Should serialize flags enum as string with -EnumsAsStrings' { + $flags = [System.IO.FileAttributes]::ReadOnly -bor [System.IO.FileAttributes]::Hidden + $json = $flags | ConvertTo-Json -Compress -EnumsAsStrings + $json | Should -BeExactly '"ReadOnly, Hidden"' + } + + It 'Should include ETS properties on Enum' { + $enum = Add-Member -InputObject ([DayOfWeek]::Monday) -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $enum | ConvertTo-Json -Compress + $json | Should -BeExactly '{"value":1,"MyProp":"test"}' + } + } + + Context 'IPAddress type' { + It 'Should serialize IPAddress v4 correctly via InputObject' { + $ip = [System.Net.IPAddress]::Parse('192.168.1.1') + $json = ConvertTo-Json -InputObject $ip -Compress + $json | Should -BeExactly '{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952}' + } + + It 'Should serialize IPAddress v4 correctly via Pipeline' { + $ip = [System.Net.IPAddress]::Parse('192.168.1.1') + $json = $ip | ConvertTo-Json -Compress + $json | Should -BeExactly '{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952,"IPAddressToString":"192.168.1.1"}' + } + + It 'Should serialize IPAddress v6 correctly via InputObject' { + $ip = [System.Net.IPAddress]::Parse('::1') + $json = ConvertTo-Json -InputObject $ip -Compress + $json | Should -BeExactly '{"AddressFamily":23,"ScopeId":0,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":null}' + } + + It 'Should serialize IPAddress v6 correctly via Pipeline' { + $ip = [System.Net.IPAddress]::Parse('::1') + $json = $ip | ConvertTo-Json -Compress + $json | Should -BeExactly '{"AddressFamily":23,"ScopeId":0,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":null,"IPAddressToString":"::1"}' + } + + It 'Should include ETS properties on IPAddress' { + $ip = [System.Net.IPAddress]::Parse('192.168.1.1') + $ip = Add-Member -InputObject $ip -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = $ip | ConvertTo-Json -Compress + $json | Should -BeExactly '{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952,"MyProp":"test","IPAddressToString":"192.168.1.1"}' + } + } + + Context 'Scalars as elements of arrays' { + It 'Should serialize array of correctly via Pipeline and InputObject' -TestCases @( + @{ TypeName = 'int'; Values = @(1, 2, 3); Expected = '[1,2,3]' } + @{ TypeName = 'string'; Values = @('a', 'b', 'c'); Expected = '["a","b","c"]' } + @{ TypeName = 'double'; Values = @(1.1, 2.2, 3.3); Expected = '[1.1,2.2,3.3]' } + ) { + param($TypeName, $Values, $Expected) + $jsonPipeline = $Values | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $Values -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + # Note: bool array test uses InputObject only because $true/$false are singletons + # and ETS properties added in other tests would affect Pipeline serialization + It 'Should serialize array of bool correctly via InputObject' { + $bools = @($true, $false, $true) + $json = ConvertTo-Json -InputObject $bools -Compress + $json | Should -BeExactly '[true,false,true]' + } + + It 'Should serialize array of Guid with Extended properties via Pipeline' { + $guids = @( + [Guid]'11111111-1111-1111-1111-111111111111', + [Guid]'22222222-2222-2222-2222-222222222222' + ) + $json = $guids | ConvertTo-Json -Compress + $json | Should -BeExactly '[{"value":"11111111-1111-1111-1111-111111111111","Guid":"11111111-1111-1111-1111-111111111111"},{"value":"22222222-2222-2222-2222-222222222222","Guid":"22222222-2222-2222-2222-222222222222"}]' + } + + It 'Should serialize array of enum correctly via Pipeline and InputObject' { + $enums = @([DayOfWeek]::Monday, [DayOfWeek]::Wednesday, [DayOfWeek]::Friday) + $jsonPipeline = $enums | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $enums -Compress + $jsonPipeline | Should -BeExactly '[1,3,5]' + $jsonInputObject | Should -BeExactly '[1,3,5]' + } + + It 'Should serialize array of enum as strings with -EnumsAsStrings' { + $enums = @([DayOfWeek]::Monday, [DayOfWeek]::Wednesday, [DayOfWeek]::Friday) + $json = $enums | ConvertTo-Json -Compress -EnumsAsStrings + $json | Should -BeExactly '["Monday","Wednesday","Friday"]' + } + + # Note: mixed array test uses InputObject only due to $true singleton issue + It 'Should serialize mixed type array correctly via InputObject' { + $mixed = @(1, 'two', $true, 3.14) + $json = ConvertTo-Json -InputObject $mixed -Compress + $json | Should -BeExactly '[1,"two",true,3.14]' + } + + It 'Should serialize array with null elements correctly' { + $arr = @(1, $null, 'three') + $json = $arr | ConvertTo-Json -Compress + $json | Should -BeExactly '[1,null,"three"]' + } + + It 'Should include ETS properties on array via InputObject' { + $arr = @(1, 2, 3) + $arr = Add-Member -InputObject $arr -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = ConvertTo-Json -InputObject $arr -Compress + $json | Should -BeExactly '{"value":[1,2,3],"MyProp":"test"}' + } + } + + Context 'Scalars as values in hashtables and PSCustomObject' { + It 'Should serialize hashtable with scalar values correctly via Pipeline and InputObject' { + $hash = [ordered]@{ + intVal = 42 + strVal = 'hello' + boolVal = $true + doubleVal = 3.14 + nullVal = $null + } + $expected = '{"intVal":42,"strVal":"hello","boolVal":true,"doubleVal":3.14,"nullVal":null}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with scalar values correctly via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + intVal = 42 + strVal = 'hello' + boolVal = $true + doubleVal = 3.14 + } + $expected = '{"intVal":42,"strVal":"hello","boolVal":true,"doubleVal":3.14}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize hashtable with value correctly' -TestCases @( + @{ TypeName = 'DateTime'; Value = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Utc); Expected = '{"val":"2024-06-15T10:30:00Z"}' } + @{ TypeName = 'Guid'; Value = [Guid]'12345678-1234-1234-1234-123456789abc'; Expected = '{"val":"12345678-1234-1234-1234-123456789abc"}' } + @{ TypeName = 'Enum'; Value = [DayOfWeek]::Monday; Expected = '{"val":1}' } + @{ TypeName = 'Uri'; Value = [Uri]'https://example.com'; Expected = '{"val":"https://example.com"}' } + @{ TypeName = 'BigInteger'; Value = 18446744073709551615n; Expected = '{"val":18446744073709551615}' } + ) { + param($TypeName, $Value, $Expected) + $hash = @{ val = $Value } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $Expected + $jsonInputObject | Should -BeExactly $Expected + } + + It 'Should serialize hashtable with enum as string correctly' { + $hash = @{ day = [DayOfWeek]::Monday } + $json = $hash | ConvertTo-Json -Compress -EnumsAsStrings + $json | Should -BeExactly '{"day":"Monday"}' + } + + It 'Should include ETS properties on hashtable via InputObject' { + $hash = @{ a = 1 } + $hash = Add-Member -InputObject $hash -MemberType NoteProperty -Name MyProp -Value 'test' -PassThru + $json = ConvertTo-Json -InputObject $hash -Compress + $json | Should -BeExactly '{"a":1,"MyProp":"test"}' + } + } + + #endregion Comprehensive Scalar Type Tests (Phase 1) } From 438254412760ff24cdfebeed09bfeb3a24882866 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Sat, 7 Feb 2026 02:41:03 +0900 Subject: [PATCH 266/378] Add comprehensive array and dictionary tests for `ConvertTo-Json` (#26742) --- .../ConvertTo-Json.Tests.ps1 | 457 ++++++++++++++++++ 1 file changed, 457 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index 4ac0818faf4..d3686953336 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -585,4 +585,461 @@ Describe 'ConvertTo-Json' -tags "CI" { } #endregion Comprehensive Scalar Type Tests (Phase 1) + + #region Comprehensive Array and Dictionary Tests (Phase 2) + # Test coverage for ConvertTo-Json array and dictionary serialization + # Covers: Pipeline vs InputObject, ETS vs no ETS, nested structures + + Context 'Array basic serialization' { + It 'Should serialize empty array correctly via Pipeline and InputObject' { + $arr = @() + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[]' + $jsonInputObject | Should -BeExactly '[]' + } + + It 'Should serialize single element array correctly via Pipeline and InputObject' { + $arr = @(42) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[42]' + $jsonInputObject | Should -BeExactly '[42]' + } + + It 'Should serialize multi-element array correctly via Pipeline and InputObject' { + $arr = @(1, 2, 3, 4, 5) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[1,2,3,4,5]' + $jsonInputObject | Should -BeExactly '[1,2,3,4,5]' + } + + It 'Should serialize string array correctly via Pipeline and InputObject' { + $arr = @('apple', 'banana', 'cherry') + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '["apple","banana","cherry"]' + $jsonInputObject | Should -BeExactly '["apple","banana","cherry"]' + } + + It 'Should serialize typed array correctly via Pipeline and InputObject' { + [int[]]$arr = @(10, 20, 30) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[10,20,30]' + $jsonInputObject | Should -BeExactly '[10,20,30]' + } + + It 'Should serialize array with single null element correctly via Pipeline and InputObject' { + $arr = @($null) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[null]' + $jsonInputObject | Should -BeExactly '[null]' + } + + It 'Should serialize array with multiple null elements correctly via Pipeline and InputObject' { + $arr = @($null, $null, $null) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[null,null,null]' + $jsonInputObject | Should -BeExactly '[null,null,null]' + } + } + + Context 'Nested arrays' { + It 'Should serialize 2D array correctly via Pipeline and InputObject' { + $arr = @(@(1, 2), @(3, 4)) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[[1,2],[3,4]]' + $jsonInputObject | Should -BeExactly '[[1,2],[3,4]]' + } + + It 'Should serialize 3D array correctly via Pipeline and InputObject' { + $arr = @(@(@(1, 2), @(3, 4)), @(@(5, 6), @(7, 8))) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[[[1,2],[3,4]],[[5,6],[7,8]]]' + $jsonInputObject | Should -BeExactly '[[[1,2],[3,4]],[[5,6],[7,8]]]' + } + + It 'Should serialize jagged array correctly via Pipeline and InputObject' { + $arr = @(@(1), @(2, 3), @(4, 5, 6)) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[[1],[2,3],[4,5,6]]' + $jsonInputObject | Should -BeExactly '[[1],[2,3],[4,5,6]]' + } + + It 'Should serialize array containing empty arrays correctly via Pipeline and InputObject' { + $arr = @(@(), @(1), @()) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[[],[1],[]]' + $jsonInputObject | Should -BeExactly '[[],[1],[]]' + } + + It 'Should serialize deeply nested array with Depth limit using ToString via Pipeline and InputObject' { + $ip = [System.Net.IPAddress]::Parse('192.168.1.1') + $arr = ,(,(,(,($ip)))) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress -Depth 2 + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress -Depth 2 + $jsonPipeline | Should -BeExactly '[[["192.168.1.1"]]]' + $jsonInputObject | Should -BeExactly '[[["192.168.1.1"]]]' + } + + It 'Should serialize deeply nested array with sufficient Depth as full object via Pipeline and InputObject' { + $ip = [System.Net.IPAddress]::Parse('192.168.1.1') + $arr = ,(,(,(,($ip)))) + $expected = '[[[[{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952}]]]]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress -Depth 10 + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress -Depth 10 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Array with mixed content types' { + It 'Should serialize array with mixed scalars correctly via Pipeline and InputObject' { + $arr = @(1, 'two', 3.14, $true, $null) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[1,"two",3.14,true,null]' + $jsonInputObject | Should -BeExactly '[1,"two",3.14,true,null]' + } + + It 'Should serialize array with nested array and scalars correctly via Pipeline and InputObject' { + $arr = @(1, @(2, 3), 4) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[1,[2,3],4]' + $jsonInputObject | Should -BeExactly '[1,[2,3],4]' + } + + It 'Should serialize array with PSCustomObject elements correctly via Pipeline and InputObject' { + $arr = @([PSCustomObject]@{x = 1}, [PSCustomObject]@{y = 2}) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[{"x":1},{"y":2}]' + $jsonInputObject | Should -BeExactly '[{"x":1},{"y":2}]' + } + + It 'Should serialize array with DateTime elements correctly via Pipeline and InputObject' { + $date1 = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Utc) + $date2 = [DateTime]::new(2024, 12, 25, 0, 0, 0, [DateTimeKind]::Utc) + $arr = @($date1, $date2) + $expected = '["2024-06-15T10:30:00Z","2024-12-25T00:00:00Z"]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize array with Guid elements correctly via Pipeline and InputObject' { + $guid1 = [Guid]'12345678-1234-1234-1234-123456789abc' + $guid2 = [Guid]'87654321-4321-4321-4321-cba987654321' + $arr = @($guid1, $guid2) + $expected = '["12345678-1234-1234-1234-123456789abc","87654321-4321-4321-4321-cba987654321"]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize array with enum elements correctly via Pipeline and InputObject' { + $arr = @([DayOfWeek]::Monday, [DayOfWeek]::Friday) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '[1,5]' + $jsonInputObject | Should -BeExactly '[1,5]' + } + + It 'Should serialize array with enum as string correctly via Pipeline and InputObject' { + $arr = @([DayOfWeek]::Monday, [DayOfWeek]::Friday) + $jsonPipeline = ,$arr | ConvertTo-Json -Compress -EnumsAsStrings + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress -EnumsAsStrings + $jsonPipeline | Should -BeExactly '["Monday","Friday"]' + $jsonInputObject | Should -BeExactly '["Monday","Friday"]' + } + } + + Context 'Array ETS properties' { + It 'Should include ETS properties on array via Pipeline and InputObject' { + $arr = @(1, 2, 3) + $arr = Add-Member -InputObject $arr -MemberType NoteProperty -Name ArrayName -Value 'MyArray' -PassThru + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '{"value":[1,2,3],"ArrayName":"MyArray"}' + $jsonInputObject | Should -BeExactly '{"value":[1,2,3],"ArrayName":"MyArray"}' + } + + It 'Should include multiple ETS properties on array via Pipeline and InputObject' { + $arr = @('a', 'b') + $arr = Add-Member -InputObject $arr -MemberType NoteProperty -Name Prop1 -Value 'val1' -PassThru + $arr = Add-Member -InputObject $arr -MemberType NoteProperty -Name Prop2 -Value 'val2' -PassThru + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly '{"value":["a","b"],"Prop1":"val1","Prop2":"val2"}' + $jsonInputObject | Should -BeExactly '{"value":["a","b"],"Prop1":"val1","Prop2":"val2"}' + } + } + + Context 'Hashtable basic serialization' { + It 'Should serialize empty hashtable correctly via Pipeline and InputObject' { + $hash = @{} + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{}' + $jsonInputObject | Should -BeExactly '{}' + } + + It 'Should serialize single key hashtable correctly via Pipeline and InputObject' { + $hash = @{ key = 'value' } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"key":"value"}' + $jsonInputObject | Should -BeExactly '{"key":"value"}' + } + + It 'Should serialize hashtable with null value correctly via Pipeline and InputObject' { + $hash = @{ nullKey = $null } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"nullKey":null}' + $jsonInputObject | Should -BeExactly '{"nullKey":null}' + } + + It 'Should serialize hashtable with various scalar types correctly via Pipeline and InputObject' { + $hash = [ordered]@{ + intKey = 42 + strKey = 'hello' + boolKey = $true + doubleKey = 3.14 + } + $expected = '{"intKey":42,"strKey":"hello","boolKey":true,"doubleKey":3.14}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'OrderedDictionary serialization' { + It 'Should preserve order in OrderedDictionary via Pipeline and InputObject' { + $ordered = [ordered]@{ + z = 1 + a = 2 + m = 3 + } + $expected = '{"z":1,"a":2,"m":3}' + $jsonPipeline = $ordered | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $ordered -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize large OrderedDictionary preserving order via Pipeline and InputObject' { + $ordered = [ordered]@{} + 1..5 | ForEach-Object { $ordered["key$_"] = $_ } + $expected = '{"key1":1,"key2":2,"key3":3,"key4":4,"key5":5}' + $jsonPipeline = $ordered | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $ordered -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Nested dictionaries' { + It 'Should serialize nested hashtable correctly via Pipeline and InputObject' { + $hash = @{ + outer = @{ + inner = 'value' + } + } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"outer":{"inner":"value"}}' + $jsonInputObject | Should -BeExactly '{"outer":{"inner":"value"}}' + } + + It 'Should serialize deeply nested hashtable correctly via Pipeline and InputObject' { + $hash = @{ + level1 = @{ + level2 = @{ + level3 = 'deep' + } + } + } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"level1":{"level2":{"level3":"deep"}}}' + $jsonInputObject | Should -BeExactly '{"level1":{"level2":{"level3":"deep"}}}' + } + + It 'Should serialize nested hashtable with Depth limit via Pipeline and InputObject' { + $hash = @{ + level1 = @{ + level2 = @{ + level3 = 'deep' + } + } + } + $jsonPipeline = $hash | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress -Depth 1 + $jsonPipeline | Should -BeExactly '{"level1":{"level2":"System.Collections.Hashtable"}}' + $jsonInputObject | Should -BeExactly '{"level1":{"level2":"System.Collections.Hashtable"}}' + } + + It 'Should serialize hashtable with array value correctly via Pipeline and InputObject' { + $hash = @{ arr = @(1, 2, 3) } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"arr":[1,2,3]}' + $jsonInputObject | Should -BeExactly '{"arr":[1,2,3]}' + } + + It 'Should serialize hashtable with nested array of hashtables correctly via Pipeline and InputObject' { + $hash = @{ + items = @( + @{ id = 1 }, + @{ id = 2 } + ) + } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"items":[{"id":1},{"id":2}]}' + $jsonInputObject | Should -BeExactly '{"items":[{"id":1},{"id":2}]}' + } + } + + Context 'Dictionary key types' { + It 'Should serialize hashtable with string keys correctly via Pipeline and InputObject' { + $hash = @{ 'string-key' = 'value' } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"string-key":"value"}' + $jsonInputObject | Should -BeExactly '{"string-key":"value"}' + } + + It 'Should serialize hashtable with special character keys correctly via Pipeline and InputObject' { + $hash = [ordered]@{ + 'key with space' = 1 + 'key-with-dash' = 2 + 'key_with_underscore' = 3 + } + $expected = '{"key with space":1,"key-with-dash":2,"key_with_underscore":3}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize hashtable with unicode keys correctly via Pipeline and InputObject' { + $hash = @{ "`u{65E5}`u{672C}`u{8A9E}" = 'Japanese' } + $expected = "{`"`u{65E5}`u{672C}`u{8A9E}`":`"Japanese`"}" + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize hashtable with empty string key correctly via Pipeline and InputObject' { + $hash = @{ '' = 'empty key' } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"":"empty key"}' + $jsonInputObject | Should -BeExactly '{"":"empty key"}' + } + } + + Context 'Dictionary with complex values' { + It 'Should serialize hashtable with DateTime value correctly via Pipeline and InputObject' { + $hash = @{ date = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Utc) } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"date":"2024-06-15T10:30:00Z"}' + $jsonInputObject | Should -BeExactly '{"date":"2024-06-15T10:30:00Z"}' + } + + It 'Should serialize hashtable with Guid value correctly via Pipeline and InputObject' { + $hash = @{ guid = [Guid]'12345678-1234-1234-1234-123456789abc' } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"guid":"12345678-1234-1234-1234-123456789abc"}' + $jsonInputObject | Should -BeExactly '{"guid":"12345678-1234-1234-1234-123456789abc"}' + } + + It 'Should serialize hashtable with enum value correctly via Pipeline and InputObject' { + $hash = @{ day = [DayOfWeek]::Monday } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"day":1}' + $jsonInputObject | Should -BeExactly '{"day":1}' + } + + It 'Should serialize hashtable with enum as string correctly via Pipeline and InputObject' { + $hash = @{ day = [DayOfWeek]::Monday } + $jsonPipeline = $hash | ConvertTo-Json -Compress -EnumsAsStrings + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress -EnumsAsStrings + $jsonPipeline | Should -BeExactly '{"day":"Monday"}' + $jsonInputObject | Should -BeExactly '{"day":"Monday"}' + } + + It 'Should serialize hashtable with PSCustomObject value correctly via Pipeline and InputObject' { + $hash = @{ obj = [PSCustomObject]@{ prop = 'value' } } + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"obj":{"prop":"value"}}' + $jsonInputObject | Should -BeExactly '{"obj":{"prop":"value"}}' + } + } + + Context 'Dictionary ETS properties' { + It 'Should include ETS properties on hashtable via Pipeline and InputObject' { + $hash = @{ a = 1 } + $hash = Add-Member -InputObject $hash -MemberType NoteProperty -Name ETSProp -Value 'ets' -PassThru + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly '{"a":1,"ETSProp":"ets"}' + $jsonInputObject | Should -BeExactly '{"a":1,"ETSProp":"ets"}' + } + + It 'Should include ETS properties on OrderedDictionary via Pipeline and InputObject' { + $ordered = [ordered]@{ a = 1 } + $ordered = Add-Member -InputObject $ordered -MemberType NoteProperty -Name ETSProp -Value 'ets' -PassThru + $jsonPipeline = $ordered | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $ordered -Compress + $jsonPipeline | Should -BeExactly '{"a":1,"ETSProp":"ets"}' + $jsonInputObject | Should -BeExactly '{"a":1,"ETSProp":"ets"}' + } + } + + Context 'Generic Dictionary types' { + It 'Should serialize Generic Dictionary correctly via Pipeline and InputObject' { + $dict = [System.Collections.Generic.Dictionary[string,int]]::new() + $dict['one'] = 1 + $dict['two'] = 2 + $jsonPipeline = $dict | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $dict -Compress + $jsonPipeline | Should -Match '"one":1' + $jsonPipeline | Should -Match '"two":2' + $jsonInputObject | Should -Match '"one":1' + $jsonInputObject | Should -Match '"two":2' + } + + It 'Should serialize SortedDictionary correctly via Pipeline and InputObject' { + $dict = [System.Collections.Generic.SortedDictionary[string,int]]::new() + $dict['b'] = 2 + $dict['a'] = 1 + $dict['c'] = 3 + $jsonPipeline = $dict | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $dict -Compress + $jsonPipeline | Should -BeExactly '{"a":1,"b":2,"c":3}' + $jsonInputObject | Should -BeExactly '{"a":1,"b":2,"c":3}' + } + } + + #endregion Comprehensive Array and Dictionary Tests (Phase 2) } From e58d395dbb84f783dc7fbc9dd74e444e8a455de3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 6 Feb 2026 18:11:18 -0500 Subject: [PATCH 267/378] Create es-metadata (#26759) Co-authored-by: MerlinBot --- es-metadata.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 es-metadata.yml diff --git a/es-metadata.yml b/es-metadata.yml new file mode 100644 index 00000000000..24da115c114 --- /dev/null +++ b/es-metadata.yml @@ -0,0 +1,12 @@ +schemaVersion: 1.0.0 +providers: +- provider: InventoryAsCode + version: 1.0.0 + metadata: + isProduction: true + accountableOwners: + service: cef1de07-99d6-45df-b907-77d0066032ec + routing: + defaultAreaPath: + org: msazure + path: One\MGMT\Compute\Powershell\Powershell\Powershell Core\pwsh From 012529a967f6f4a0b2e874c2d98dc6efe79506cb Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 9 Feb 2026 13:13:17 -0500 Subject: [PATCH 268/378] Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26753) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index cbc47ef200c..7008fe6a08d 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 664ac75f4fe8ef4008d40e11965b0df90180f022 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Tue, 10 Feb 2026 09:43:02 +0900 Subject: [PATCH 269/378] Add comprehensive depth and multilevel composition tests for `ConvertTo-Json` (#26744) --- .../ConvertTo-Json.Tests.ps1 | 452 ++++++++++++++++++ 1 file changed, 452 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index d3686953336..4fe4b0d59b6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -1042,4 +1042,456 @@ Describe 'ConvertTo-Json' -tags "CI" { } #endregion Comprehensive Array and Dictionary Tests (Phase 2) + + #region Comprehensive Depth Truncation and Multilevel Composition Tests (Phase 4) + # Test coverage for ConvertTo-Json depth truncation and complex nested structures + # Covers: -Depth parameter behavior, multilevel type compositions + + Context 'Depth parameter basic behavior' { + It 'Should use default depth of 2 via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = [PSCustomObject]@{ + L1 = [PSCustomObject]@{ + L2 = [PSCustomObject]@{ + L3 = 'deep' + } + } + } + } + $expected = '{"L0":{"L1":{"L2":"@{L3=deep}"}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should truncate at Depth 0 via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = [PSCustomObject]@{ L1 = 1 } + } + $expected = '{"L0":"@{L1=1}"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 0 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 0 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should truncate at Depth 1 via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = [PSCustomObject]@{ + L1 = [PSCustomObject]@{ + L2 = 'deep' + } + } + } + $expected = '{"L0":{"L1":"@{L2=deep}"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 1 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize fully with sufficient Depth via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = [PSCustomObject]@{ + L1 = [PSCustomObject]@{ + L2 = [PSCustomObject]@{ + L3 = 'very deep' + } + } + } + } + $expected = '{"L0":{"L1":{"L2":{"L3":"very deep"}}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 10 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 10 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should handle Depth 100 for deeply nested structures via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ L0 = [PSCustomObject]@{ L1 = [PSCustomObject]@{ L2 = [PSCustomObject]@{ L3 = [PSCustomObject]@{ L4 = 'deep' } } } } } + $expected = '{"L0":{"L1":{"L2":{"L3":{"L4":"deep"}}}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 100 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 100 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should throw on Depth 101 exceeding maximum via Pipeline and InputObject' { + { [PSCustomObject]@{ L0 = 1 } | ConvertTo-Json -Depth 101 } | Should -Throw -ErrorId 'ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ConvertToJsonCommand' + { ConvertTo-Json -InputObject ([PSCustomObject]@{ L0 = 1 }) -Depth 101 } | Should -Throw -ErrorId 'ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ConvertToJsonCommand' + } + } + + Context 'Depth truncation with arrays' { + It 'Should truncate nested array at Depth limit via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Arr = ,(,(1, 2, 3)) + } + $expected = '{"Arr":["System.Object[]"]}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 1 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested array fully with sufficient Depth via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Arr = ,(,(1, 2, 3)) + } + $expected = '{"Arr":[[[1,2,3]]]}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 10 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 10 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should truncate array of objects at Depth limit via Pipeline and InputObject' { + $arr = @( + [PSCustomObject]@{ Inner = [PSCustomObject]@{ Value = 1 } } + ) + $expected = '[{"Inner":"@{Value=1}"}]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress -Depth 1 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Depth truncation with hashtables' { + It 'Should truncate nested hashtable at Depth limit via Pipeline and InputObject' { + $hash = @{ + L0 = @{ + L1 = @{ + L2 = 'deep' + } + } + } + $expected = '{"L0":{"L1":"System.Collections.Hashtable"}}' + $jsonPipeline = $hash | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress -Depth 1 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested hashtable fully with sufficient Depth via Pipeline and InputObject' { + $hash = @{ + L0 = @{ + L1 = @{ + L2 = 'deep' + } + } + } + $expected = '{"L0":{"L1":{"L2":"deep"}}}' + $jsonPipeline = $hash | ConvertTo-Json -Compress -Depth 10 + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress -Depth 10 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Depth truncation string representation' { + It 'Should convert PSCustomObject to @{...} string when truncated via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Child = [PSCustomObject]@{ A = 1; B = 2 } + } + $expected = '{"Child":"@{A=1; B=2}"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 0 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 0 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should convert Hashtable to type name when truncated via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Child = @{ Key = 'Value' } + } + $expected = '{"Child":"System.Collections.Hashtable"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 0 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 0 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should convert Array to space-separated string when truncated via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Child = @(1, 2, 3) + } + $expected = '{"Child":"1 2 3"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 0 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 0 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Multilevel composition: Array containing Dictionary' { + It 'Should serialize array of hashtables correctly via Pipeline and InputObject' { + $arr = @(@{ a = 1 }, @{ b = 2 }, @{ c = 3 }) + $expected = '[{"a":1},{"b":2},{"c":3}]' + $jsonPipeline = $arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize array of ordered dictionaries correctly via Pipeline and InputObject' { + $arr = @( + [ordered]@{ x = 1; y = 2 }, + [ordered]@{ x = 3; y = 4 } + ) + $expected = '[{"x":1,"y":2},{"x":3,"y":4}]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested array of hashtables correctly via Pipeline and InputObject' { + $arr = @( + @{ + Items = @( + @{ Value = 1 }, + @{ Value = 2 } + ) + } + ) + $expected = '[{"Items":[{"Value":1},{"Value":2}]}]' + $jsonPipeline = ,$arr | ConvertTo-Json -Compress -Depth 3 + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress -Depth 3 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Multilevel composition: Dictionary containing Array' { + It 'Should serialize dictionary with array values correctly via Pipeline and InputObject' { + $hash = [ordered]@{ + numbers = @(1, 2, 3) + strings = @('a', 'b', 'c') + } + $expected = '{"numbers":[1,2,3],"strings":["a","b","c"]}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize dictionary with nested array values correctly via Pipeline and InputObject' { + $hash = @{ + matrix = @(@(1, 2), @(3, 4)) + } + $expected = '{"matrix":[[1,2],[3,4]]}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize dictionary with empty array value correctly via Pipeline and InputObject' { + $hash = @{ empty = @() } + $expected = '{"empty":[]}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize dictionary with array of dictionaries correctly via Pipeline and InputObject' { + $hash = @{ + Items = @( + @{ X = 1 }, + @{ X = 2 } + ) + } + $expected = '{"Items":[{"X":1},{"X":2}]}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Multilevel composition: PSCustomObject with mixed types' { + It 'Should serialize PSCustomObject with array and hashtable properties via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + List = @(1, 2, 3) + Config = @{ Key = 'Value' } + Name = 'Test' + } + $expected = '{"List":[1,2,3],"Config":{"Key":"Value"},"Name":"Test"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with nested PSCustomObject and array via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Child = [PSCustomObject]@{ + Items = @(1, 2, 3) + } + } + $expected = '{"Child":{"Items":[1,2,3]}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize array of PSCustomObject with mixed properties via Pipeline and InputObject' { + $arr = @( + [PSCustomObject]@{ Type = 'A'; Data = @(1, 2) }, + [PSCustomObject]@{ Type = 'B'; Data = @{ Key = 'Val' } } + ) + $expected = '[{"Type":"A","Data":[1,2]},{"Type":"B","Data":{"Key":"Val"}}]' + $jsonPipeline = $arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Multilevel composition: PowerShell class in complex structures' { + BeforeAll { + class ItemClass { + [int]$Id + [string]$Name + } + + class ContainerClass { + [string]$Type + [ItemClass]$Item + } + } + + It 'Should serialize array of PowerShell class correctly via Pipeline and InputObject' { + $arr = @( + [ItemClass]@{ Id = 1; Name = 'First' }, + [ItemClass]@{ Id = 2; Name = 'Second' } + ) + $expected = '[{"Id":1,"Name":"First"},{"Id":2,"Name":"Second"}]' + $jsonPipeline = $arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize hashtable containing PowerShell class correctly via Pipeline and InputObject' { + $item = [ItemClass]@{ Id = 1; Name = 'Test' } + $hash = @{ Item = $item } + $expected = '{"Item":{"Id":1,"Name":"Test"}}' + $jsonPipeline = $hash | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested PowerShell classes correctly via Pipeline and InputObject' { + $item = [ItemClass]@{ Id = 1; Name = 'Inner' } + $container = [ContainerClass]@{ Type = 'Outer'; Item = $item } + $expected = '{"Type":"Outer","Item":{"Id":1,"Name":"Inner"}}' + $jsonPipeline = $container | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $container -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject containing PowerShell class correctly via Pipeline and InputObject' { + $item = [ItemClass]@{ Id = 1; Name = 'Test' } + $obj = [PSCustomObject]@{ + Label = 'Container' + Content = $item + } + $expected = '{"Label":"Container","Content":{"Id":1,"Name":"Test"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should truncate nested PowerShell class at Depth limit via Pipeline and InputObject' { + $item = [ItemClass]@{ Id = 1; Name = 'Test' } + $container = [ContainerClass]@{ Type = 'Outer'; Item = $item } + $itemString = $item.ToString() + $expected = "{`"Type`":`"Outer`",`"Item`":`"$itemString`"}" + $jsonPipeline = $container | ConvertTo-Json -Compress -Depth 0 + $jsonInputObject = ConvertTo-Json -InputObject $container -Compress -Depth 0 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Complex multilevel compositions' { + It 'Should serialize 3-level mixed composition correctly via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Users = @( + [PSCustomObject]@{ + Name = 'Alice' + Roles = @('Admin', 'User') + }, + [PSCustomObject]@{ + Name = 'Bob' + Roles = @('User') + } + ) + } + $expected = '{"Users":[{"Name":"Alice","Roles":["Admin","User"]},{"Name":"Bob","Roles":["User"]}]}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 3 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 3 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize dictionary with nested mixed types correctly via Pipeline and InputObject' { + $hash = [ordered]@{ + Meta = [PSCustomObject]@{ Version = '1.0' } + Data = @( + ([ordered]@{ Key = 'A'; Values = @(1, 2) }), + ([ordered]@{ Key = 'B'; Values = @(3, 4) }) + ) + } + $expected = '{"Meta":{"Version":"1.0"},"Data":[{"Key":"A","Values":[1,2]},{"Key":"B","Values":[3,4]}]}' + $jsonPipeline = $hash | ConvertTo-Json -Compress -Depth 3 + $jsonInputObject = ConvertTo-Json -InputObject $hash -Compress -Depth 3 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should handle deeply nested mixed types with sufficient Depth via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = @{ + L1 = [PSCustomObject]@{ + L2 = @( + [PSCustomObject]@{ L3 = 'deep' } + ) + } + } + } + $expected = '{"L0":{"L1":{"L2":[{"L3":"deep"}]}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 10 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 10 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should truncate deeply nested mixed types at Depth limit via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + L0 = @{ + L1 = [PSCustomObject]@{ + L2 = @( + [PSCustomObject]@{ L3 = 'deep' } + ) + } + } + } + $expected = '{"L0":{"L1":{"L2":""}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 2 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 2 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + #endregion Comprehensive Depth Truncation and Multilevel Composition Tests (Phase 4) } From 42371b881c8189e871761e11d584e35acb139f64 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:10:50 -0800 Subject: [PATCH 270/378] Add `SubjectAlternativeName` property to the `Signature` object returned from `Get-AuthenticodeSignature` (#26252) --- .../security/MshSignature.cs | 37 +++++++ .../security/SecuritySupport.cs | 1 + .../engine/Security/FileSignature.Tests.ps1 | 101 ++++++++++++++++++ 3 files changed, 139 insertions(+) diff --git a/src/System.Management.Automation/security/MshSignature.cs b/src/System.Management.Automation/security/MshSignature.cs index fd8dd4f67ef..7cbaf98d3a5 100644 --- a/src/System.Management.Automation/security/MshSignature.cs +++ b/src/System.Management.Automation/security/MshSignature.cs @@ -185,6 +185,11 @@ public string Path /// public bool IsOSBinary { get; internal set; } + /// + /// Gets the Subject Alternative Name from the signer certificate. + /// + public string[] SubjectAlternativeName { get; private set; } + /// /// Constructor for class Signature /// @@ -277,6 +282,9 @@ private void Init(string filePath, _statusMessage = GetSignatureStatusMessage(isc, error, filePath); + + // Extract Subject Alternative Name from the signer certificate + SubjectAlternativeName = GetSubjectAlternativeName(signer); } private static SignatureStatus GetSignatureStatusFromWin32Error(DWORD error) @@ -389,5 +397,34 @@ private static string GetSignatureStatusMessage(SignatureStatus status, return message; } + + /// + /// Extracts the Subject Alternative Name from the certificate. + /// + /// The certificate to extract SAN from. + /// Array of SAN entries or null if not found. + private static string[] GetSubjectAlternativeName(X509Certificate2 certificate) + { + if (certificate == null) + { + return null; + } + + foreach (X509Extension extension in certificate.Extensions) + { + if (extension.Oid != null && extension.Oid.Value == CertificateFilterInfo.SubjectAlternativeNameOid) + { + string formatted = extension.Format(multiLine: true); + if (string.IsNullOrEmpty(formatted)) + { + return null; + } + + return formatted.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return null; + } } } diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index e6a6f10416b..12e03d85174 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -815,6 +815,7 @@ internal DateTime Expiring // The OID arc 1.3.6.1.4.1.311.80 is assigned to PowerShell. If we need // new OIDs, we can assign them under this branch. internal const string DocumentEncryptionOid = "1.3.6.1.4.1.311.80.1"; + internal const string SubjectAlternativeNameOid = "2.5.29.17"; } } diff --git a/test/powershell/engine/Security/FileSignature.Tests.ps1 b/test/powershell/engine/Security/FileSignature.Tests.ps1 index 9dd26f98aed..f2815fad4ff 100644 --- a/test/powershell/engine/Security/FileSignature.Tests.ps1 +++ b/test/powershell/engine/Security/FileSignature.Tests.ps1 @@ -18,6 +18,9 @@ Describe "Windows platform file signatures" -Tags 'Feature' { $signature | Should -Not -BeNullOrEmpty $signature.Status | Should -BeExactly 'Valid' $signature.SignatureType | Should -BeExactly 'Catalog' + + # Verify that SubjectAlternativeName property exists + $signature.PSObject.Properties.Name | Should -Contain 'SubjectAlternativeName' } } @@ -186,4 +189,102 @@ Describe "Windows file content signatures" -Tags @('Feature', 'RequireAdminOnWin $actual.SignerCertificate.Thumbprint | Should -Be $certificate.Thumbprint $actual.Status | Should -Be 'Valid' } + + It "Verifies SubjectAlternativeName is populated for certificate with SAN" { + $session = New-PSSession -UseWindowsPowerShell + try { + $sanThumbprint = Invoke-Command -Session $session -ScriptBlock { + $testPrefix = 'SelfSignedTestSAN' + + $enhancedKeyUsage = [Security.Cryptography.OidCollection]::new() + $null = $enhancedKeyUsage.Add('1.3.6.1.5.5.7.3.3') + + $caParams = @{ + Extension = @( + [Security.Cryptography.X509Certificates.X509BasicConstraintsExtension]::new($true, $false, 0, $true), + [Security.Cryptography.X509Certificates.X509KeyUsageExtension]::new('KeyCertSign', $false), + [Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]::new($enhancedKeyUsage, $false) + ) + CertStoreLocation = 'Cert:\CurrentUser\My' + NotAfter = (Get-Date).AddDays(1) + Type = 'Custom' + } + $sanCA = PKI\New-SelfSignedCertificate @caParams -Subject "CN=$testPrefix-CA" + + $rootStore = Get-Item -Path Cert:\LocalMachine\Root + $rootStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) + try { + $rootStore.Add([System.Security.Cryptography.X509Certificates.X509Certificate2]::new($sanCA.RawData)) + } finally { + $rootStore.Close() + } + + $certParams = @{ + CertStoreLocation = 'Cert:\CurrentUser\My' + KeyUsage = 'DigitalSignature' + TextExtension = @( + "2.5.29.37={text}1.3.6.1.5.5.7.3.3", + "2.5.29.19={text}", + "2.5.29.17={text}DNS=test.example.com&DNS=*.example.com" + ) + Type = 'Custom' + } + $sanCert = PKI\New-SelfSignedCertificate @certParams -Subject "CN=$testPrefix-Signed" -Signer $sanCA + + $publisherStore = Get-Item -Path Cert:\LocalMachine\TrustedPublisher + $publisherStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) + try { + $publisherStore.Add([System.Security.Cryptography.X509Certificates.X509Certificate2]::new($sanCert.RawData)) + } finally { + $publisherStore.Close() + } + + $sanCA | Remove-Item + $sanCA.Thumbprint, $sanCert.Thumbprint + } + } finally { + $session | Remove-PSSession + } + + $sanCARootThumbprint = $sanThumbprint[0] + $sanCertThumbprint = $sanThumbprint[1] + $sanCertificate = Get-Item -Path Cert:\CurrentUser\My\$sanCertThumbprint + + try { + Set-Content -Path testdrive:\test.ps1 -Value 'Write-Output "Test SAN"' -Encoding UTF8NoBOM + + $scriptPath = Join-Path $TestDrive test.ps1 + $status = Set-AuthenticodeSignature -FilePath $scriptPath -Certificate $sanCertificate + $status.Status | Should -Be 'Valid' + + $actual = Get-AuthenticodeSignature -FilePath $scriptPath + $actual.SubjectAlternativeName | Should -Not -BeNullOrEmpty + ,$actual.SubjectAlternativeName | Should -BeOfType [string[]] + $actual.SubjectAlternativeName.Count | Should -Be 2 + $actual.SubjectAlternativeName[0] | Should -BeExactly 'DNS Name=test.example.com' + $actual.SubjectAlternativeName[1] | Should -BeExactly 'DNS Name=*.example.com' + } finally { + Remove-Item -Path "Cert:\LocalMachine\Root\$sanCARootThumbprint" -Force -ErrorAction Ignore + Remove-Item -Path "Cert:\LocalMachine\TrustedPublisher\$sanCertThumbprint" -Force -ErrorAction Ignore + Remove-Item -Path "Cert:\CurrentUser\My\$sanCertThumbprint" -Force -ErrorAction Ignore + } + } + + It "Verifies SubjectAlternativeName is null when certificate has no SAN" { + Set-Content -Path testdrive:\test.ps1 -Value 'Write-Output "Test No SAN"' -Encoding UTF8NoBOM + + $scriptPath = Join-Path $TestDrive test.ps1 + $status = Set-AuthenticodeSignature -FilePath $scriptPath -Certificate $certificate + $status.Status | Should -Be 'Valid' + + $actual = Get-AuthenticodeSignature -FilePath $scriptPath + $actual.SignerCertificate.Thumbprint | Should -Be $certificate.Thumbprint + $actual.Status | Should -Be 'Valid' + + # Verify that SubjectAlternativeName property exists + $actual.PSObject.Properties.Name | Should -Contain 'SubjectAlternativeName' + + # Verify the content is null when certificate has no SAN extension + $actual.SubjectAlternativeName | Should -BeNullOrEmpty + } } From 9f9f8b93a39f1051f854561532d9651a2e07d269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:27:36 +0000 Subject: [PATCH 271/378] Bump github/codeql-action from 4.32.1 to 4.32.2 (#26755) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index b56d2d6635c..c5a0b9ff985 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 + uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 + uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d1d974f8efa..a5d05091555 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5 + uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 with: sarif_file: results.sarif From 439c42f232fd3e6793425be65aabc942f044cdce Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:02:44 -0800 Subject: [PATCH 272/378] Update outdated package references (#26771) --- .../Microsoft.PowerShell.Commands.Utility.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 6 +++--- .../ResultsComparer/ResultsComparer.csproj | 2 +- tools/cgmanifest.json | 16 ++++++++-------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 5ee999c2d9c..eed0722b4d5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 161170355e6..0f827aab553 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -24,9 +24,9 @@ - - - + + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index c4831924845..5cbc66081a3 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,6 +10,6 @@ - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 1001370ade7..2334f070852 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -25,7 +25,7 @@ "Type": "nuget", "Nuget": { "Name": "Humanizer.Core", - "Version": "3.0.1" + "Version": "2.14.1" } }, "DevelopmentDependency": false @@ -35,7 +35,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.2.0" + "Version": "2.1.1" } }, "DevelopmentDependency": false @@ -45,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "6.0.1" + "Version": "5.3.1" } }, "DevelopmentDependency": false @@ -65,7 +65,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.44.0" + "Version": "0.45.0" } }, "DevelopmentDependency": false @@ -665,7 +665,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Http", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -675,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetFramingBase", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -685,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetTcp", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -695,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Primitives", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false From 2e26e4b69076a22173ccf8d0ebd6f2c1d590578a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Feb 2026 08:50:16 -0800 Subject: [PATCH 273/378] Update the `Update-Help` tests to use `-Force` to remove read-only files (#26780) --- test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 593a2ee89d7..e871a8d1603 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -215,7 +215,7 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) From 4db414ca3345dd78232096233226584a5fda9895 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:45:17 +0000 Subject: [PATCH 274/378] Add GitHub Actions annotations for Pester test failures (#26789) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk --- .../process-pester-results.ps1 | 56 +++++++++++++++++ build.psm1 | 63 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/.github/actions/test/process-pester-results/process-pester-results.ps1 b/.github/actions/test/process-pester-results/process-pester-results.ps1 index 523de3bebaa..5804bec9a94 100644 --- a/.github/actions/test/process-pester-results/process-pester-results.ps1 +++ b/.github/actions/test/process-pester-results/process-pester-results.ps1 @@ -24,6 +24,7 @@ $testIgnoredCount = 0 $testSkippedCount = 0 $testInvalidCount = 0 +# Process test results and generate annotations for failures Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $results = [xml] (get-content $_.FullName) @@ -35,6 +36,61 @@ Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $testIgnoredCount += [int]$results.'test-results'.ignored $testSkippedCount += [int]$results.'test-results'.skipped $testInvalidCount += [int]$results.'test-results'.invalid + + # Generate GitHub Actions annotations for test failures + # Select failed test cases + if ("System.Xml.XmlDocumentXPathExtensions" -as [Type]) { + $failures = [System.Xml.XmlDocumentXPathExtensions]::SelectNodes($results.'test-results', './/test-case[@result = "Failure"]') + } + else { + $failures = $results.SelectNodes('.//test-case[@result = "Failure"]') + } + + foreach ($testfail in $failures) { + $description = $testfail.description + $testName = $testfail.name + $message = $testfail.failure.message + $stack_trace = $testfail.failure.'stack-trace' + + # Parse stack trace to get file and line info + $fileInfo = Get-PesterFailureFileInfo -StackTraceString $stack_trace + + if ($fileInfo.File) { + # Convert absolute path to relative path for GitHub Actions + $filePath = $fileInfo.File + + # GitHub Actions expects paths relative to the workspace root + if ($env:GITHUB_WORKSPACE) { + $workspacePath = $env:GITHUB_WORKSPACE + if ($filePath.StartsWith($workspacePath)) { + $filePath = $filePath.Substring($workspacePath.Length).TrimStart('/', '\') + # Normalize to forward slashes for consistency + $filePath = $filePath -replace '\\', '/' + } + } + + # Create annotation title + $annotationTitle = "Test Failure: $description / $testName" + + # Build the annotation message + $annotationMessage = $message -replace "`n", "%0A" -replace "`r" + + # Build and output the workflow command + $workflowCommand = "::error file=$filePath" + if ($fileInfo.Line) { + $workflowCommand += ",line=$($fileInfo.Line)" + } + $workflowCommand += ",title=$annotationTitle::$annotationMessage" + + Write-Host $workflowCommand + + # Output a link to the test run + if ($env:GITHUB_SERVER_URL -and $env:GITHUB_REPOSITORY -and $env:GITHUB_RUN_ID) { + $logUrl = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)" + Write-Host "Test logs: $logUrl" + } + } + } } @" diff --git a/build.psm1 b/build.psm1 index d09b7af925d..bf175c5f7c2 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1864,6 +1864,69 @@ $stack_trace } +function Get-PesterFailureFileInfo +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string]$StackTraceString + ) + + # Parse stack trace to extract file path and line number + # Common patterns: + # "at line: 123 in C:\path\to\file.ps1" (Pester 4) + # "at C:\path\to\file.ps1:123" + # "at , C:\path\to\file.ps1: line 123" + # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) + # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) + + $result = @{ + File = $null + Line = $null + } + + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { + return $result + } + + # Try pattern: "at line: 123 in " (Pester 4) + if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { + $result.Line = $matches[1] + $result.File = $matches[2].Trim() + return $result + } + + # Try pattern: ", :123" (Pester 5 format) + # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) + if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: "at :123" (without comma) + # Handle both absolute Unix and Windows paths + if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: ": line 123" + if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try to extract just the file path if no line number found + if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { + $result.File = $matches[1].Trim() + } + + return $result +} + function Test-XUnitTestResults { param( From 6b8d724b030d1ced7bf772c502279d694c72bf47 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 03:57:33 +0000 Subject: [PATCH 275/378] Mark flaky Update-Help web tests as pending to unblock CI (#26796) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- ...ester-set-itresult-pattern.instructions.md | 198 ++++++++++++++++++ .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 35 +++- 2 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 .github/instructions/pester-set-itresult-pattern.instructions.md diff --git a/.github/instructions/pester-set-itresult-pattern.instructions.md b/.github/instructions/pester-set-itresult-pattern.instructions.md new file mode 100644 index 00000000000..33a73ca081d --- /dev/null +++ b/.github/instructions/pester-set-itresult-pattern.instructions.md @@ -0,0 +1,198 @@ +--- +applyTo: + - "**/*.Tests.ps1" +--- + +# Pester Set-ItResult Pattern for Pending and Skipped Tests + +## Purpose + +This instruction explains when and how to use `Set-ItResult` in Pester tests to mark tests as Pending or Skipped dynamically within test execution. + +## When to Use Set-ItResult + +Use `Set-ItResult` when you need to conditionally mark a test as Pending or Skipped based on runtime conditions that can't be determined at test definition time. + +### Pending vs Skipped + +**Pending**: Use for tests that should be enabled but temporarily can't run due to: +- Intermittent external service failures (network, APIs) +- Known bugs being fixed +- Missing features being implemented +- Environmental issues that are being resolved + +**Skipped**: Use for tests that aren't applicable to the current environment: +- Platform-specific tests running on wrong platform +- Tests requiring specific hardware/configuration not present +- Tests requiring elevated permissions when not available +- Feature-specific tests when feature is disabled + +## Pattern + +### Basic Usage + +```powershell +It "Test description" { + if ($shouldBePending) { + Set-ItResult -Pending -Because "Explanation of why test is pending" + return + } + + if ($shouldBeSkipped) { + Set-ItResult -Skipped -Because "Explanation of why test is skipped" + return + } + + # Test code here +} +``` + +### Important: Always Return After Set-ItResult + +After calling `Set-ItResult`, you **must** return from the test to prevent further execution: + +```powershell +It "Test that checks environment" { + if ($env:SKIP_TESTS -eq 'true') { + Set-ItResult -Skipped -Because "SKIP_TESTS environment variable is set" + return # This is required! + } + + # Test assertions + $result | Should -Be $expected +} +``` + +**Why?** Without `return`, the test continues executing and may fail with errors unrelated to the pending/skipped condition. + +## Examples from the Codebase + +### Example 1: Pending for Intermittent Network Issues + +```powershell +It "Validate Update-Help for module" { + if ($markAsPending) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + + Update-Help -Module $moduleName -Force + # validation code... +} +``` + +### Example 2: Skipped for Missing Environment + +```powershell +It "Test requires CI environment" { + if (-not $env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + return + } + + Install-CIPester -ErrorAction Stop +} +``` + +### Example 3: Pending for Platform-Specific Issue + +```powershell +It "Clear-Host works correctly" { + if ($IsARM64) { + Set-ItResult -Pending -Because "ARM64 runs in non-interactively mode and Clear-Host does not work." + return + } + + & { Clear-Host; 'hi' } | Should -BeExactly 'hi' +} +``` + +### Example 4: Skipped for Missing Feature + +```powershell +It "Test ACR authentication" { + if ($env:ACRTESTS -ne 'true') { + Set-ItResult -Skipped -Because "The tests require the ACRTESTS environment variable to be set to 'true' for ACR authentication." + return + } + + $psgetModuleInfo = Find-PSResource -Name $ACRTestModule -Repository $ACRRepositoryName + # test assertions... +} +``` + +## Alternative: Static -Skip and -Pending Parameters + +For conditions that can be determined at test definition time, use the static parameters instead: + +```powershell +# Static skip - condition known at definition time +It "Windows-only test" -Skip:(-not $IsWindows) { + # test code +} + +# Static pending - always pending +It "Test for feature being implemented" -Pending { + # test code that will fail until feature is done +} +``` + +**Use Set-ItResult when**: +- Condition depends on runtime state +- Condition is determined inside a helper function +- Need to check multiple conditions sequentially + +**Use static parameters when**: +- Condition is known at test definition +- Condition doesn't change during test run +- Want Pester to show the condition in test discovery + +## Best Practices + +1. **Always include -Because parameter** with a clear explanation +2. **Always return after Set-ItResult** to prevent further execution +3. **Reference issues or documentation** when relevant (e.g., "See issue #1234") +4. **Be specific in the reason** - explain what's wrong and what's needed +5. **Use Pending sparingly** - it indicates a problem that should be fixed +6. **Prefer Skipped over Pending** when test truly isn't applicable + +## Common Mistakes + +### ❌ Mistake 1: Forgetting to Return + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Reason" + # Missing return - test code will still execute! + } + $value | Should -Be $expected # This runs and fails +} +``` + +### ❌ Mistake 2: Vague Reason + +```powershell +Set-ItResult -Pending -Because "Doesn't work" # Too vague +``` + +### ✅ Correct: + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Update-Help has intermittent network timeouts. See issue #2807." + return + } + $value | Should -Be $expected +} +``` + +## See Also + +- [Pester Documentation: Set-ItResult](https://pester.dev/docs/commands/Set-ItResult) +- [Pester Documentation: It](https://pester.dev/docs/commands/It) +- Examples in the codebase: + - `test/powershell/Host/ConsoleHost.Tests.ps1` + - `test/infrastructure/ciModule.Tests.ps1` + - `tools/packaging/releaseTests/sbom.tests.ps1` diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index e871a8d1603..6bf82d21af1 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -191,7 +191,8 @@ function RunUpdateHelpTests param ( [string]$tag = "CI", [switch]$useSourcePath, - [switch]$userscope + [switch]$userscope, + [switch]$markAsPending ) foreach ($moduleName in $modulesInBox) @@ -214,8 +215,15 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { + if ($markAsPending) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + if ($moduleHelpPath) { + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + } [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) @@ -246,8 +254,15 @@ function RunSaveHelpTests { try { - $saveHelpFolder = Join-Path $TestDrive (Get-Random).ToString() - New-Item $saveHelpFolder -Force -ItemType Directory > $null + $saveHelpFolder = if ($TestDrive) { + Join-Path $TestDrive (Get-Random).ToString() + } else { + $null + } + + if ($saveHelpFolder) { + New-Item $saveHelpFolder -Force -ItemType Directory > $null + } ## Save help has intermittent connectivity issues for downloading PackageManagement help content. ## Hence the test has been marked as Pending. @@ -283,7 +298,9 @@ function RunSaveHelpTests } finally { - Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + if ($saveHelpFolder) { + Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + } } } } @@ -316,7 +333,9 @@ Describe "Validate Update-Help from the Web for one PowerShell module." -Tags @( $ProgressPreference = $SavedProgressPreference } - RunUpdateHelpTests -Tag "CI" + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. + RunUpdateHelpTests -Tag "CI" -MarkAsPending } Describe "Validate Update-Help from the Web for one PowerShell module for user scope." -Tags @('CI', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { @@ -328,7 +347,9 @@ Describe "Validate Update-Help from the Web for one PowerShell module for user s $ProgressPreference = $SavedProgressPreference } - RunUpdateHelpTests -Tag "CI" -UserScope + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. + RunUpdateHelpTests -Tag "CI" -UserScope -MarkAsPending } Describe "Validate Update-Help from the Web for all PowerShell modules." -Tags @('Feature', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { From 08b13f24e6d359877b2cdbe650f7c8fc5ca20135 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 13 Feb 2026 14:43:16 -0500 Subject: [PATCH 276/378] Add Pester CI Analysis Skill (#26806) --- ...status-and-working-meaning.instructions.md | 299 ++++++++++ .../skills/analyze-pester-failures/SKILL.md | 524 ++++++++++++++++++ .../references/stack-trace-parsing.md | 163 ++++++ .../scripts/analyze-pr-test-failures.ps1 | 456 +++++++++++++++ .gitignore | 3 + 5 files changed, 1445 insertions(+) create mode 100644 .github/instructions/pester-test-status-and-working-meaning.instructions.md create mode 100644 .github/skills/analyze-pester-failures/SKILL.md create mode 100644 .github/skills/analyze-pester-failures/references/stack-trace-parsing.md create mode 100644 .github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 diff --git a/.github/instructions/pester-test-status-and-working-meaning.instructions.md b/.github/instructions/pester-test-status-and-working-meaning.instructions.md new file mode 100644 index 00000000000..d2b28a05f18 --- /dev/null +++ b/.github/instructions/pester-test-status-and-working-meaning.instructions.md @@ -0,0 +1,299 @@ +--- +applyTo: "**/*.Tests.ps1" +--- + +# Pester Test Status Meanings and Working Tests + +## Purpose + +This guide clarifies Pester test outcomes and what it means for a test to be "working" - which requires both **passing** AND **actually validating functionality**. + +## Test Statuses in Pester + +### Passed ✓ +**Status Code**: `Passed` +**Exit Result**: Test ran successfully, all assertions passed + +**What it means**: +- Test executed without errors +- All `Should` statements evaluated to true +- Test setup and teardown completed without issues +- Test is **validating** the intended functionality + +**What it does NOT mean**: +- The feature is working (assertions could be wrong) +- The test is meaningful (could be testing wrong thing) +- The test exercises all code paths + +### Failed ✗ +**Status Code**: `Failed` +**Exit Result**: Test ran but assertions failed + +**What it means**: +- Test executed but an assertion returned false +- Expected value did not match actual value +- Test detected a problem with the functionality + +**Examples**: +``` +Expected $true but got $false +Expected 5 items but got 3 +Expected no error but got: Cannot find parameter +``` + +### Error ⚠ +**Status Code**: `Error` +**Exit Result**: Test crashed with an exception + +**What it means**: +- Test failed to complete +- An exception was thrown during test execution +- Could be in test setup, test body, or test cleanup +- Often indicates environmental issue, not code functional issue + +**Examples**: +``` +Cannot bind argument to parameter 'Path' because it is null +File not found: C:\expected\config.json +Access denied writing to registry +``` + +### Pending ⏳ +**Status Code**: `Pending` +**Exit Result**: Test ran but never completed assertions + +**What it means**: +- Test was explicitly marked as not ready to run +- `Set-ItResult -Pending` was called +- Used to indicate: known bugs, missing features, environmental issues + +**When to use Pending**: +- Test for feature in development +- Test disabled due to known bug (issue #1234) +- Test disabled due to intermittent failures being fixed +- Platform-specific issues being resolved + +**⚠️ WARNING**: Pending tests are NOT validating functionality. They hide problems. + +### Skipped ⊘ +**Status Code**: `Skipped` +**Exit Result**: Test did not run (detected at start) + +**What it means**: +- Test was intentionally not executed +- `-Skip` parameter or `It -Skip:$condition` was used +- Environment doesn't support this test + +**When to use Skip**: +- Test not applicable to current platform (Windows-only test on Linux) +- Test requires feature that's not available (admin privileges) +- Test requires specific configuration not present + +**Difference from Pending**: +- **Skip**: "This test shouldn't run here" (known upfront) +- **Pending**: "This test should eventually run but can't now" + +### Ignored ✛ +**Status Code**: `Ignored` +**Exit Result**: Test marked as not applicable + +**What it means**: +- Test has `[Ignore("reason")]` attribute +- Test is permanently disabled in this location +- Not the same as Skipped (which is conditional) + +**When to use Ignore**: +- Test for deprecated feature +- Test for bug that won't be fixed +- Test moved to different test file + +--- + +## What Does "Working" Actually Mean? + +A test is **working** when it meets BOTH criteria: + +### 1. **Test Status is PASSED** ✓ +```powershell +It "Test name" { + # Test executes + # All assertions pass + # Returns Passed status +} +``` + +### 2. **Test Actually Validates Functionality** +```powershell +# ✓ GOOD: Tests actual functionality +It "Get-Item returns files from directory" -Tags @('Unit') { + $testDir = New-Item -ItemType Directory -Force + New-Item -Path $testDir -Name "file.txt" -ItemType File | Out-Null + + $result = Get-Item -Path "$testDir\file.txt" + + $result.Name | Should -Be "file.txt" + $result | Should -Exist + + Remove-Item $testDir -Recurse -Force +} + +# ✗ BAD: Returns Passed but doesn't validate functionality +It "Get-Item returns files from directory" -Tags @('Unit') { + $result = Get-Item -Path somepath # May not exist, may not actually test + $result | Should -Not -BeNullOrEmpty # Too vague +} + +# ✗ BAD: Test marked Pending - validation is hidden +It "Get-Item returns files from directory" -Tags @('Unit') { + Set-ItResult -Pending -Because "File system not working" + return + # No validation happens at all +} +``` + +--- + +## The Problem with Pending Tests + +### Why Pending Tests Hide Problems + +```powershell +# BAD: Test marked Pending - looks like "working" status but validation is skipped +It "Download help from web" { + Set-ItResult -Pending -Because "Web connectivity issues" + return + + # This code never runs: + Update-Help -Module PackageManagement -Force -ErrorAction Stop + Get-Help Get-Package | Should -Not -BeNullOrEmpty +} +``` + +**Result**: +- ✗ Feature is broken (Update-Help fails) +- ✓ Test shows "Pending" (looks acceptable) +- ✗ Problem is hidden and never fixed + +### The Right Approach + +**Option A: Fix the root cause** +```powershell +It "Download help from web" { + # Use local assets that are guaranteed to work + Update-Help -Module PackageManagement -SourcePath ./assets -Force -ErrorAction Stop + + Get-Help Get-Package | Should -Not -BeNullOrEmpty +} +``` + +**Option B: Gracefully skip when unavailable** +```powershell +It "Download help from web" -Skip:$(-not $hasInternet) { + Update-Help -Module PackageManagement -Force -ErrorAction Stop + Get-Help Get-Package | Should -Not -BeNullOrEmpty +} +``` + +**Option C: Add retry logic for intermittent issues** +```powershell +It "Download help from web" { + $maxRetries = 3 + $attempt = 0 + + while ($attempt -lt $maxRetries) { + try { + Update-Help -Module PackageManagement -Force -ErrorAction Stop + break + } + catch { + $attempt++ + if ($attempt -ge $maxRetries) { throw } + Start-Sleep -Seconds 2 + } + } + + Get-Help Get-Package | Should -Not -BeNullOrEmpty +} +``` + +--- + +## Test Status Summary Table + +| Status | Passed? | Validates? | Counts as "Working"? | Use When | +|--------|---------|------------|----------------------|----------| +| **Passed** | ✓ | ✓ | **YES** | Feature is working and test proves it | +| **Failed** | ✗ | ✓ | NO | Feature is broken or test has wrong expectation | +| **Error** | ✗ | ✗ | NO | Test infrastructure broken, can't validate | +| **Pending** | - | ✗ | **NO** ⚠️ | Temporary - test should eventually pass | +| **Skipped** | - | ✗ | NO | Test not applicable to this environment | +| **Ignored** | - | ✗ | NO | Test permanently disabled | + +--- + +## Recommended Patterns + +### Pattern 1: Resilient Test with Fallback +```powershell +It "Feature works with web or local source" { + $useLocal = $false + + try { + Update-Help -Module Package -Force -ErrorAction Stop + } + catch { + $useLocal = $true + Update-Help -Module Package -SourcePath ./assets -Force -ErrorAction Stop + } + + # Validate functionality regardless of source + Get-Help Get-Package | Should -Not -BeNullOrEmpty +} +``` + +### Pattern 2: Conditional Skip with Clear Reason +```powershell +Describe "Update-Help from Web" -Skip $(-not (Test-InternetConnectivity)) { + It "Downloads help successfully" { + Update-Help -Module PackageManagement -Force -ErrorAction Stop + Get-Help Get-Package | Should -Not -BeNullOrEmpty + } +} +``` + +### Pattern 3: Separate Suites by Dependency +```powershell +Describe "Help Content Tests - Web" { + # Tests that require internet - can be skipped if unavailable + It "Downloads from web" { ... } +} + +Describe "Help Content Tests - Local" { + # Tests with local assets - should always pass + It "Loads from local assets" { + Update-Help -Module Package -SourcePath ./assets -Force + Get-Help Get-Package | Should -Not -BeNullOrEmpty + } +} +``` + +--- + +## Checklist: Is Your Test "Working"? + +- [ ] Test status is **Passed** (not Pending, not Skipped, not Failed) +- [ ] Test actually **executes** the feature being tested +- [ ] Test has **specific assertions** (not just `Should -Not -BeNullOrEmpty`) +- [ ] Test includes **cleanup** (removes temp files, restores state) +- [ ] Test can run **multiple times** without side effects +- [ ] Test failure **indicates a real problem** (not flaky assertions) +- [ ] Test success **proves the feature works** (not just "didn't crash") + +If any of these is false, your test may be passing but not "working" properly. + +--- + +## See Also + +- [Pester Documentation](https://pester.dev/) +- [Set-ItResult Documentation](https://pester.dev/docs/commands/Set-ItResult) diff --git a/.github/skills/analyze-pester-failures/SKILL.md b/.github/skills/analyze-pester-failures/SKILL.md new file mode 100644 index 00000000000..ec1b0fe82ec --- /dev/null +++ b/.github/skills/analyze-pester-failures/SKILL.md @@ -0,0 +1,524 @@ +--- +name: analyze-pester-failures +description: Troubleshooting guide for analyzing and investigating Pester test failures in PowerShell CI jobs. Help agents understand why tests are failing, interpret test output, navigate test result artifacts, and provide actionable recommendations for fixing test issues. +--- + +# Analyze Pester Test Failures + +Investigate and troubleshoot Pester test failures in GitHub Actions workflows. Understand what tests are failing, why they're failing, and provide recommendations for test fixes. + +| Skill | When to Use | +|-------|-----------| +| analyze-pester-failures | When investigating why Pester tests are failing in a CI job. Use when a test job shows failures and you need to understand what test failed, why it failed, what the error message means, and what might need to be fixed. Also use when asked: "why did this test fail?", "what's the test error?", "test is broken", "test failure analysis", "debug test failure", or given test failure logs and stack traces. | + +## When to Use This Skill + +Use this skill when you need to: + +- Understand why a specific Pester test is failing +- Interpret test failure messages and error output +- Analyze test result data from CI workflow runs (XML, logs, stack traces) +- Identify the root cause of test failures (test logic, assertion failure, exception, timeout, skip/ignore reason) +- Provide recommendations for fixing failing tests +- Compare expected vs. actual test behavior +- Debug test environment issues (missing dependencies, configuration problems) +- Understand test skip/ignored/inconclusive status reasons + +**Do not use this skill for:** +- General PowerShell debugging unrelated to tests +- Test infrastructure/CI setup issues (except as they affect test failure interpretation) +- Performance analysis or benchmarking (that's a different investigation) + +## Quick Start + +### ⚠️ CRITICAL: The Workflow Must Be Followed IN ORDER + +This skill describes a **sequential 6-step analysis workflow**. Skipping steps or jumping around leads to **incomplete analysis and incorrect conclusions**. + +**The Problem**: It's easy to skip to Step 4 or 5 without doing Steps 1-2, resulting in missing data and bad conclusions. + +**The Solution**: Use the automated analysis script to enforce the workflow: + +```powershell +# Automatically runs Steps 1-6 in order, preventing skipping +./.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 -PR + +# Example: +./.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 -PR 26800 +``` + +This script: +1. ✓ Fetches PR status automatically +2. ✓ Downloads artifacts (can't skip, depends on Step 1) +3. ✓ Extracts failures (can't skip, depends on Step 2) +4. ✓ Analyzes error messages +5. ✓ Documents context +6. ✓ Generates recommendations + +**Only use the manual commands below if you fully understand the workflow.** + +### Manual Workflow (for reference) + +```powershell +# Step 1: Identify the failing job +gh pr view --json 'statusCheckRollup' | ConvertFrom-Json | Where-Object { $_.conclusion -eq 'FAILURE' } + +# Step 2: Download artifacts (extract RUN_ID from Step 1) +gh run download --dir ./artifacts +gh run view --log > test-logs.txt + +# Step 3-6: Extract, analyze, and interpret +# (See Analysis Workflow section below) +``` + +## Common Test Failure Analysis Approaches + +### 1. **Interpreting Assertion Failures** +The most common test failure is when an assertion doesn't match expectations. + +**Example:** +``` +Expected $true but got $false at /path/to/test.ps1:42 +Assertion failed: Should -Be "expected" but was "actual" +``` + +**How to analyze:** +- Read the assertion message: what was expected vs. what was actual? +- Check the test logic: is the expectation correct? +- Look for mock/stub issues: are dependencies configured correctly? +- Check parameter values: what inputs were passed to the function under test? + +### 2. **Exception Failures** +Tests fail when PowerShell throws an exception instead of successful completion. + +**Example:** +``` +Command: Write-Host $null +Error: Cannot bind argument to parameter 'Object' because it is null. +``` + +**How to analyze:** +- Read the exception message: what operation failed? +- Check the stack trace: where in the test or tested code did it throw? +- Verify preconditions: does the test setup provide required values/mocks? +- Look for environmental issues: missing modules, permissions, file system state? + +### 3. **Timeout Failures** +A test takes longer than the allowed timeout to complete. + +**Example:** +``` +Test 'Should complete in reasonable time' timed out after 30 seconds +``` + +**How to analyze:** +- Is the timeout appropriate for this test type? (network tests need more time) +- Is there an infinite loop in the test or tested code? +- Are there resource contention issues on the CI runner? +- Does the test hang waiting for something (file lock, network, process)? + +### 4. **Skip/Ignored Reason Analysis** +Tests marked as skipped or ignored provide clues about test environment. + +**Example:** +``` +Test marked [Skip("Only runs on Windows")] - running on Linux +Test marked [Ignore("Known issue #12345")] +``` + +**How to analyze:** +- Read the skip/ignore reason: is it still valid? +- Check if environment has changed: platform, module versions, etc. +- Verify issue status: is the known issue still open? Has it been fixed? +- Determine if skip should be removed or if test needs environment changes + +### 5. **Flaky/Intermittent Failures** +Tests that sometimes pass, sometimes fail indicate race conditions or environment sensitivity. + +**Example:** +- Test passes locally but fails on CI +- Test passes first run of suite, fails on second run +- Test passes on Windows but fails on Linux + +**How to analyze:** +- Look for timeout races: is timing involved in the test? +- Check for test isolation issues: does one test affect another? +- Verify environment differences: CI vs. local paths, permissions, versions +- Look for external dependencies: network calls, file I/O, process interactions + +## Key Artifacts and Locations + +| Item | Purpose | Location | +|------|---------|----------| +| Test result XML | Pester output with test cases, failures, errors | Workflow artifacts: `junit-pester-*.xml` | +| Job logs | Full job output including test execution and errors | GitHub Actions run logs or `gh run download` | +| Stack traces | Error location information from failed assertions | Within job logs and XML failure messages | +| Test files | The actual Pester test code (`.ps1` files) | `test/` directory in repository | + +## Analysis Workflow + +### ⚠️ Important: These Steps MUST Be Followed In Order + +Each step depends on the previous one. Skipping or re-ordering steps causes incomplete analysis: + +- **Step 1** (identify jobs) → You get the RUN_ID needed for Step 2 +- **Step 2** (download) → You get the artifacts needed for Step 3 +- **Step 3** (extract) → You discover what failures exist for Step 4 +- **Step 4** (read messages) → You understand the errors to analyze in Step 5 +- **Step 5** (context) → You gather information to make recommendations in Step 6 +- **Step 6** (interpret) → You use all above to recommend fixes + +**Real Problem We Had**: +- ❌ Jumped to Step 3 without Step 1-2 +- ❌ Used random test data from context instead of downloading PR artifacts +- ❌ Skipped Steps 5-6 entirely +- ❌ Made recommendations without full context + +**Result**: Wrong analysis and recommendations that didn't actually fix the problem. + +### Recommended: Use the Automated Script + +```powershell +./.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 -PR +``` + +This enforces the workflow and prevents skipping. + +### Step 2: Get Test Results + +Fetch the test result artifacts and job logs: + +```powershell +# Download artifacts including test XML results +gh run download --dir ./artifacts + +# Get job logs +gh run view --log > test-logs.txt + +# Inspect test XML +$xml = [xml](Get-Content ./artifacts/junit-pester-*.xml) +$xml.'test-results' | Select-Object total, failures, errors, ignored, inconclusive +``` + +### Step 3: Extract Specific Failures + +Find the failing test cases in the XML: + +```powershell +# Get all failed test cases +$xml = [xml](Get-Content ./artifacts/junit-pester-*.xml) +$failures = $xml.SelectNodes('.//test-case[@result = "Failure"]') + +# For each failure, display key info +$failures | ForEach-Object { + [PSCustomObject]@{ + Name = $_.name + Description = $_.description + Message = $_.failure.message + StackTrace = $_.failure.'stack-trace' + } +} +``` + +### Step 4: Read the Error Message + +The error message tells you what went wrong: + +**Assertion failures:** +``` +Expected $true but got $false +Expected "value1" but got "value2" +Expression should have failed with exception, but didn't +``` + +**Exceptions:** +``` +Cannot find a parameter with name 'Name' +Property 'Property' does not exist on 'Object' +Cannot bind argument to parameter because it is null +``` + +**Timeouts:** +``` +Test timed out after 30 seconds +Test is taking too long to complete +``` + +### Step 5: Understand the Context + +Look at the test file to understand what was being tested: + +```powershell +# Find the test file mentioned in the stack trace +# Example: /path/to/test/Feature.Tests.ps1:42 + +# Read the test code around that line +code : + +# Understand: +# - What assertion is on that line? +# - What is the test trying to verify? +# - What are the setup/mock/before conditions? +# - Are there recent changes to the function being tested? +``` + +### Step 6: Interpret the Failure + +Determine the root cause category: + +**Test issue (needs code fix):** +- Assertion logic is wrong +- Test expectations don't match actual behavior +- Test setup is incomplete +- Mock/stub configuration missing + +**Environmental issue (needs environment change):** +- Test assumes a specific file or registry entry exists +- Test requires Windows/Linux specifically +- Test requires specific PowerShell version +- Test requires specific module version +- Timing-sensitive test affected by CI load + +**Data issue (needs input data change):** +- Test data no longer valid +- External API changed format +- Configuration file has changed structure + +**Flakiness (needs test hardening):** +- Race condition in test +- Timing assumptions too tight +- Resource contention on CI runner +- Non-deterministic behavior in tested code + +## Common Test Failure Patterns + +| Pattern | What It Means | Example | Next Step | +|---------|---------------|---------|-----------| +| `Expected $true but got $false` | Assertion on boolean result failed | Test expects function returns true, but it returns false | Check function logic for bug or test logic for wrong expectation | +| `Cannot find path` | File or directory doesn't exist | Test tries to read config file that's not present | Verify file path, check test setup, ensure CI environment has file | +| `Cannot bind argument to parameter 'X'` | Required parameter value is null or wrong type | Function called with $null where object expected | Check test mock setup, verify parameter types | +| `Test timed out after X seconds` | Test exceeded time limit | Network call or loop takes too long | Increase timeout for slow test, find infinite loop, mock network calls | +| `Expression should have failed but didn't` | Exception wasn't thrown when expected | Test expects error but function succeeds | Check if function behavior changed, update test expectation | +| `Could not find parameter 'X'` | Function doesn't have parameter | Test calls function with parameter that doesn't exist | Check PowerShell version, verify function signature, update test | +| `This platform is not supported` | Test skipped on current OS | Windows-only test running on Linux | Add platform check, update test environment, or mark as platform-specific | +| `Test marked [Ignore]` | Test explicitly disabled | Test has `[Ignore("reason")]` attribute | Check if reason still valid, remove if issue fixed | + +## Interpreting Test Results + +### Test Result Counts + +Pester test outcomes are categorized as: + +| Count | Meaning | Notes | +|-------|---------|-------| +| `total` | Total number of test cases executed | Should match: passed + failed + errors + skipped + ignored | +| `failures` | Test assertions that failed | `Expected X but got Y` type failures | +| `errors` | Tests that threw exceptions | Unhandled PowerShell exceptions during test | +| `skipped` | Tests explicitly skipped (marked with `-Skip`) | Test code recognizes condition and skips | +| `ignored` | Tests marked as ignored (marked with `-Ignore`) | Test disabled intentionally, usually notes reason | +| `inconclusive` | Tests with unclear result | Rare; usually means test framework issue | +| `passed` | Tests with passing assertions | `total - failures - errors - skipped - ignored` | + +### Stack Trace Interpretation + +A stack trace shows where the failure occurred: + +``` +at /home/runner/work/PowerShell/test/Feature.Tests.ps1:42 + +Means: +- File: /home/runner/work/PowerShell/test/Feature.Tests.ps1 +- Line: 42 +- Look at that line to see which assertion failed +``` + +### Understanding Skipped Tests + +When XML shows `result="Ignored"` or `result="Skipped"`: + +```xml + + Only runs on Windows + +``` + +The reason explains why test didn't run. Not a failure, but important for understanding test coverage. + +## Providing Test Failure Analysis + +### Investigation Questions + +After gathering test output, ask yourself: + +1. **Is the test code correct?** + - Does the test assertion match the expected behavior? + - Are test expectations still valid? + - Has the function being tested changed? + +2. **Is the test setup correct?** + - Are mocks/stubs configured properly? + - Does the test environment have required files/configuration? + - Are preconditions (database, files, services) met? + +3. **Is this a code bug or test issue?** + - Does the tested function have a logic error? + - Or does the test have incorrect expectations? + +4. **Is this environment-specific?** + - Only fails on Windows/Linux? + - Only fails on CI but passes locally? + - Timing-dependent or resource-dependent? + +5. **Is this a known/expected failure?** + - Is there already an issue tracking this failure? + - Is the test marked as flaky or expected to fail? + - Does the skip/ignore reason still apply? + +### Recommendation Framework + +Based on your analysis: + +| Finding | Recommendation | +|---------|-----------------| +| Test logic is wrong | "Test assertion on line X is incorrect. Test expects Y but function correctly returns Z. Update test expectation." | +| Tested code has bug | "Function at file.ps1#L42 has logic error. When X happens, returns Y instead of Z. Fix the condition." | +| Missing test setup | "Test setup incomplete. Mock for dependency Y is not configured. Add `Mock Get-Y -MockWith { ... }`" | +| Environment issue | "Test is Windows-specific but running on Linux. Either add platform check or skip on non-Windows." | +| Flaky test | "Test is timing-sensitive (sleep 1 second). Increase timeout or use better synchronization." | +| Test should be skipped | "Test is marked Ignored for good reason. Keep it disabled until issue #12345 is fixed." | + +### Tone and Structure + +Provide analysis as: + +1. **Summary** (1 sentence): What test is failing and general category +2. **Failure Details** (2-3 sentences): What the test output says +3. **Root Cause** (1-2 sentences): Why it's failing (test bug vs. code bug vs. environment) +4. **Recommendation** (actionable): What should be done to fix it +5. **Context** (optional): Link to related code, issues, or recent changes + +## Examples + +### Example 1: Assertion Failure Due to Code Bug + +**Test Output:** +``` +Expected 5 but got 3 at /path/to/Test.ps1:42 +``` + +**Investigation:** +1. Look at line 42: `$result | Should -Be 5` +2. Check the test: It expects function to return 5 items +3. Check the function: It returns `$items | Where-Object {$_.Status -eq "Active"}` but the filter is wrong +4. Root cause: Function has logic error, not test error + +**Recommendation:** +``` +Test failure is due to a code bug: + +The test Set-Configuration should return 5 items but returns 3. + +Looking at the tested function at [module.ps1#L42](module.ps1#L42): + $activeItems = $items | Where-Object {$_.Status -eq "Active"} + +The issue is the filter condition. It's currently filtering by "Active" status, +but should include "Pending" status as well. + +Fix: Change line 42 to: + $activeItems = $items | Where-Object {$_.Status -ne "Disabled"} + +Then re-run the test to verify it now returns 5 items as expected. +``` + +### Example 2: Test Setup Issue + +**Test Output:** +``` +Cannot find path '/expected/config.json' because it does not exist at /path/to/Test.ps1:15 +``` + +**Investigation:** +1. Line 15 tries to read a config file +2. The test setup doesn't create this file +3. Works locally but fails on CI because CI doesn't have the same file + +**Recommendation:** +``` +Test setup is incomplete: + +The test Initialize-Config fails because it expects /expected/config.json but the test doesn't create this file. + +The test needs to ensure the config file exists. Currently line 12-14 doesn't set up the file: + + # Before: + # (no setup of config file) + + # After: + @{ setting1 = "value1"; setting2 = "value2" } | ConvertTo-Json | + Out-File $testConfigPath + +Alternatively, the test function should accept a parameter for the config path and use a temporary file: + param([string]$ConfigPath = (New-TemporaryFile)) + +Re-run the test to verify the config file is properly available. +``` + +### Example 3: Platform-Specific Test Failure + +**Test Output:** +``` +Test 'should read Windows Registry' failed on Linux runner +Cannot find path 'HKEY_LOCAL_MACHINE:\...' +``` + +**Investigation:** +1. Test assumes Windows Registry exists (Windows-only) +2. Running on Linux runner doesn't have Registry +3. Test should skip on non-Windows platforms + +**Recommendation:** +``` +Test is platform-specific but running on wrong platform: + +The test "should read Windows Registry" assumes Windows Registry exists but is running on Linux. + +Add a platform check to skip this test on non-Windows systems: + + It "should read Windows Registry" -Skip:$(-not $IsWindows) { + # test code here + } + +Or group Windows-only tests in a separate Describe block with platform check: + + Describe "Windows Registry Tests" -Skip:$(-not $IsWindows) { + # all Windows-specific tests here + } + +This allows the test to be skipped on Linux/Mac while still running on Windows CI. +``` + +## References + +- [Pester Testing Framework](https://pester.dev/) — Official documentation, best practices for test writing +- [Test Files](../../../test/) — PowerShell test suite in repository +- [GitHub Actions Documentation](https://docs.github.com/en/actions) — Understanding workflow runs and logs +- [PowerShell Documentation](https://learn.microsoft.com/en-us/powershell/) — Language reference for understanding test code + +## Tips + +1. **Read the error message first:** The error message is usually the most direct clue to the problem +2. **Check test vs. code blame:** Is the test wrong or is the code wrong? Look at both sides +3. **Verify test isolation:** Does one test failure affect others? Check for shared state or test ordering dependencies +4. **Test locally first:** Try running the failing test locally to reproduce and understand it better +5. **Check for environmental assumptions:** Windows-specific paths, module versions, file locations may differ on CI +6. **Look for skip/ignore patterns:** If a test is consistently ignored, check if the reason is still valid +7. **Compare passing vs. failing:** If test passes locally but fails on CI, the difference is usually environment-related +8. **Check recent changes:** Did a recent PR change the tested code or test itself? +9. **Understand Pester output format:** Different Pester versions, different `-ErrorAction`, `-WarningAction` produce different test results +10. **Don't assume CI is wrong:** Failures on CI often reveal real issues that local testing missed (network, file permissions, parallelization, etc.) + +## Additional Links + +- [PowerShell Repository](https://github.com/PowerShell/PowerShell) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [Pester Testing Framework](https://github.com/Pester/Pester) diff --git a/.github/skills/analyze-pester-failures/references/stack-trace-parsing.md b/.github/skills/analyze-pester-failures/references/stack-trace-parsing.md new file mode 100644 index 00000000000..707f45560a9 --- /dev/null +++ b/.github/skills/analyze-pester-failures/references/stack-trace-parsing.md @@ -0,0 +1,163 @@ +# Understanding Pester Test Failures + +This reference explains how to interpret Pester test output and understand failure messages. + +## Supported Formats + +### Pester 4 Format +``` +at line: 123 in C:\path\to\file.ps1 +``` + +**Regex Pattern:** +```powershell +if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { + $result.Line = $matches[1] + $result.File = $matches[2].Trim() + return $result +} +``` + +### Pester 5 Format (Common) +``` +at 1 | Should -Be 2, C:\path\to\file.ps1:123 +at 1 | Should -Be 2, /home/runner/work/PowerShell/PowerShell/test/file.ps1:123 +``` + +**Regex Pattern:** +```powershell +if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result +} +``` + +### Alternative Format +``` +at C:\path\to\file.ps1:123 +at /path/to/file.ps1:123 +``` + +**Regex Pattern:** +```powershell +if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result +} +``` + +## Troubleshooting Parsing Failures + +### Issue: Line Number Extracted But File Path Is Null + +**Cause:** Stack trace matches line-with-path pattern but file extraction doesn't work + +**Solution:** +1. Check if file path exists as expected in filesystem +2. Verify regex doesn't have too-greedy bounds (check use of `.+?` vs `.+`) +3. Test regex against actual stack trace string: + ```powershell + $trace = "at line: 42 in C:\path\to\test.ps1" + if ($trace -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { + Write-Host "File: $($matches[2])" # Should be "C:\path\to\test.ps1" + } + ``` + +### Issue: Special Characters in File Path Break Regex + +**Cause:** Characters like parens `()`, brackets `[]`, pipes `|` have special meaning in regex + +**Solution:** +1. Escape special chars in regex: `[Regex]::Escape($path)` +2. Use character class `[\/\\]` instead of alternation for path separators +3. Test with files containing problematic names: + ```powershell + $traces = @( + "at line: 1 in C:\path\(with)\parens\test.ps1", + "at /home/user/[brackets]/test.ps1:5", + "at C:\path\with spaces\test.ps1:10" + ) + # Test each against all patterns + ``` + +### Issue: Regex Matches But Extracts Wrong Values + +**Symptom:** $matches[1] is file instead of line, or vice versa + +**Debug Steps:** +1. Print all captured groups: `$matches.Values | Format-Table -AutoSize` +2. Verify group order in regex matches expectations +3. Test with sample Pester output: + ```powershell + $sampleTrace = @" + at 1 | Should -Be 2, /home/runner/work/PowerShell/test/file.ps1:42 + "@ + + if ($sampleTrace -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + Write-Host "Match 1: $($matches[1])" # Should be file path + Write-Host "Match 2: $($matches[2])" # Should be line number + } + ``` + +## Testing the Parser + +Use this PowerShell script to validate `Get-PesterFailureFileInfo`: + +```powershell +# Import the function +. ./build.psm1 + +$testCases = @( + @{ + Input = "at line: 42 in C:\path\to\test.ps1" + Expected = @{ File = "C:\path\to\test.ps1"; Line = "42" } + }, + @{ + Input = "at /home/runner/work/test.ps1:123" + Expected = @{ File = "/home/runner/work/test.ps1"; Line = "123" } + }, + @{ + Input = "at 1 | Should -Be 2, /path/to/file.ps1:99" + Expected = @{ File = "/path/to/file.ps1"; Line = "99" } + } +) + +foreach ($test in $testCases) { + $result = Get-PesterFailureFileInfo -StackTraceString $test.Input + + $fileMatch = $result.File -eq $test.Expected.File + $lineMatch = $result.Line -eq $test.Expected.Line + $status = if ($fileMatch -and $lineMatch) { "✓ PASS" } else { "✗ FAIL" } + + Write-Host "$status : $($test.Input)" + if (-not $fileMatch) { Write-Host " Expected file: $($test.Expected.File), got: $($result.File)" } + if (-not $lineMatch) { Write-Host " Expected line: $($test.Expected.Line), got: $($result.Line)" } +} +``` + +## Adding Support for New Formats + +When Pester changes its output format: + +1. **Capture sample output** from failing tests +2. **Identify the pattern** (e.g., "file path always after comma followed by colon") +3. **Write regex** to match pattern without over-matching +4. **Add to `Get-PesterFailureFileInfo`** before existing patterns (order matters for fallback) +5. **Test with samples** containing special characters, long paths, and edge cases + +Example: Adding a new format at the top of the function: + +```powershell +# Try pattern: "at , :" (Pester 5.1 hypothetical) +if ($StackTraceString -match 'at .+?, ((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result +} + +# Try existing patterns... +``` + +Place new patterns **first** so they take precedence over fallback patterns. diff --git a/.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 b/.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 new file mode 100644 index 00000000000..12486596071 --- /dev/null +++ b/.github/skills/analyze-pester-failures/scripts/analyze-pr-test-failures.ps1 @@ -0,0 +1,456 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Automated Pester test failure analysis workflow for GitHub PRs. + +.DESCRIPTION + This script automates the complete analysis workflow defined in the analyze-pester-failures + skill. It performs all steps in order: + 1. Identify failing test jobs in the PR + 2. Download test artifacts and logs + 3. Extract specific test failures + 4. Parse error messages + 5. Search logs for error markers and generate recommendations + + By automating the workflow, this ensures analysis steps are followed in order + and nothing is skipped. + +.PARAMETER PR + The GitHub PR number to analyze (e.g., 26800) + +.PARAMETER Owner + Repository owner (default: PowerShell) + +.PARAMETER Repo + Repository name (default: PowerShell) + +.PARAMETER OutputDir + Directory to store analysis results (default: ./pester-analysis-PR) + +.PARAMETER Interactive + Prompt for recommendations after analysis (default: non-interactive) + +.PARAMETER ForceDownload + Force re-download of artifacts and logs, even if they already exist + +.EXAMPLE + .\.github\skills\analyze-pester-failures\scripts\analyze-pr-test-failures.ps1 -PR 26800 + Analyzes PR #26800 and saves results to ./pester-analysis-PR26800 + +.EXAMPLE + .\.github\skills\analyze-pester-failures\scripts\analyze-pr-test-failures.ps1 -PR 26800 -Interactive + Interactive mode: shows failures and prompts for next steps + +.EXAMPLE + .\.github\skills\analyze-pester-failures\scripts\analyze-pr-test-failures.ps1 -PR 26800 -ForceDownload + Re-download all logs and artifacts, skipping the cache + +.NOTES + Requires: GitHub CLI (gh) configured and authenticated + This script enforces the workflow defined in .github/skills/analyze-pester-failures/SKILL.md +#> + +param( + [Parameter(Mandatory)] + [int]$PR, + + [string]$Owner = 'PowerShell', + [string]$Repo = 'PowerShell', + [string]$OutputDir, + [switch]$Interactive, + [switch]$ForceDownload +) + +$ErrorActionPreference = 'Stop' + +if (-not $OutputDir) { + $OutputDir = "./pester-analysis-PR$PR" +} + +# Colors for output +$colors = @{ + Step = [ConsoleColor]::Cyan + Success = [ConsoleColor]::Green + Warning = [ConsoleColor]::Yellow + Error = [ConsoleColor]::Red + Info = [ConsoleColor]::Gray +} + +function Write-Step { + param([string]$text, [int]$number) + Write-Host "`n[$number/6] $text" -ForegroundColor $colors.Step -BackgroundColor Black +} + +function Write-Result { + param([string]$text, [ValidateSet('Success','Warning','Error','Info')]$type = 'Info') + Write-Host $text -ForegroundColor $colors[$type] +} + +Write-Host "`n=== Pester Test Failure Analysis ===" -ForegroundColor $colors.Step +Write-Host "PR: $Owner/$Repo#$PR" -ForegroundColor $colors.Info +Write-Host "Output Directory: $OutputDir" -ForegroundColor $colors.Info + +# Ensure output directory exists +if (-not (Test-Path $OutputDir)) { + New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null +} + +# STEP 1: Identify the Failing Test Job +Write-Step "Identify failing test jobs" 1 + +Write-Result "Fetching PR status checks..." Info +$prResponse = gh pr view $PR --repo "$Owner/$Repo" --json 'statusCheckRollup' | ConvertFrom-Json +$allChecks = $prResponse.statusCheckRollup + +$failedJobs = $allChecks | Where-Object { $_.conclusion -eq 'FAILURE' } + +if (-not $failedJobs) { + Write-Result "✓ No failed jobs found" Success + Write-Host " Total checks: $($allChecks.Count)" + $allChecks | Where-Object { $_ } | ForEach-Object { + Write-Host " - $($_.name): $($_.conclusion)" -ForegroundColor $colors.Info + } + exit 0 +} + +Write-Result "✓ Found $($failedJobs.Count) failing job(s)" Warning + +$failedJobs | Where-Object { $_.conclusion -eq 'FAILURE' } | ForEach-Object { + Write-Host " ✗ $($_.name) - $($_.conclusion)" -ForegroundColor $colors.Error + if ($_.detailsUrl) { + Write-Host " URL: $($_.detailsUrl)" -ForegroundColor $colors.Info + } +} + +if ($Interactive) { + Write-Host "`nPress Enter to continue to Step 2..." + Read-Host | Out-Null +} + +# STEP 2: Get Test Results +Write-Step "Download test artifacts and logs" 2 + +# Extract unique run IDs from failing jobs +$uniqueRuns = @() +foreach ($failedJob in $failedJobs) { + if ($failedJob.detailsUrl -match 'runs/(\d+)') { + $runId = $matches[1] + if ($runId -notin $uniqueRuns) { + $uniqueRuns += $runId + } + } +} + +if ($uniqueRuns.Count -eq 0) { + Write-Result "✗ Could not extract run IDs from failing jobs" Error + exit 1 +} + +Write-Result "Found $($uniqueRuns.Count) run(s): $($uniqueRuns -join ', ')" Info + +$artifactDir = Join-Path $OutputDir artifacts + +# Check if artifacts already exist +$existingArtifacts = Get-ChildItem $artifactDir -Recurse -File -ErrorAction SilentlyContinue + +if ($existingArtifacts -and -not $ForceDownload) { + Write-Result "✓ Artifacts already downloaded" Success + $existingArtifacts | ForEach-Object { + Write-Host " - $($_.FullName)" -ForegroundColor $colors.Info + } +} else { + Write-Result "Downloading artifacts from run $($uniqueRuns[0])..." Info + gh run download $uniqueRuns[0] --dir $artifactDir --repo "$Owner/$Repo" 2>&1 | Out-Null + + if (Test-Path $artifactDir) { + Write-Result "✓ Artifacts downloaded" Success + Get-ChildItem $artifactDir -Recurse -File | ForEach-Object { + Write-Host " - $($_.FullName)" -ForegroundColor $colors.Info + } + } else { + Write-Result "✗ Failed to download artifacts" Error + exit 1 + } +} + +# Download individual job logs for failing jobs +Write-Result "Downloading individual job logs..." Info + +$logsDir = Join-Path $OutputDir "logs" +if (-not (Test-Path $logsDir)) { + New-Item -ItemType Directory -Path $logsDir -Force | Out-Null +} + +# Check if logs already exist +$existingLogs = Get-ChildItem $logsDir -Filter "*.txt" -ErrorAction SilentlyContinue + +if ($existingLogs -and -not $ForceDownload) { + Write-Result "✓ Job logs already downloaded" Success + $existingLogs | ForEach-Object { + Write-Host " - $($_.Name)" -ForegroundColor $colors.Info + } +} else { + # Process each run and get its jobs + $failedJobIds = @() + foreach ($runId in $uniqueRuns) { + $runJobs = gh run view $runId --repo "$Owner/$Repo" --json jobs | ConvertFrom-Json + + foreach ($failedJob in $failedJobs) { + # Check if this failed job belongs to this run + if ($failedJob.detailsUrl -match "runs/$runId/") { + $jobMatch = $runJobs.jobs | Where-Object { $_.name -eq $failedJob.name } | Select-Object -First 1 + if ($jobMatch) { + $failedJobIds += @{ + name = $failedJob.name + id = $jobMatch.databaseId + runId = $runId + } + } + } + } + } + + # Download logs for all failed jobs + foreach ($jobInfo in $failedJobIds) { + $logFile = Join-Path $logsDir ("log-{0}.txt" -f ($jobInfo.name -replace '[^a-zA-Z0-9-]', '_')) + Write-Result " Downloading: $($jobInfo.name) (Run $($jobInfo.runId))" Info + gh run view $jobInfo.runId --log --job $jobInfo.id --repo "$Owner/$Repo" > $logFile 2>&1 + } + + Write-Result "✓ Job logs downloaded" Success + Get-ChildItem $logsDir -Filter "*.txt" | ForEach-Object { + Write-Host " - $($_.Name)" -ForegroundColor $colors.Info + } +} + +if ($Interactive) { + Write-Host "`nPress Enter to continue to Step 3..." + Read-Host | Out-Null +} + +# STEP 3: Extract Specific Failures +Write-Step "Extract test failures from XML" 3 + +$xmlFiles = Get-ChildItem $artifactDir -Filter "*.xml" -Recurse +if (-not $xmlFiles) { + Write-Result "✗ No test result XML files found" Error + exit 1 +} + +Write-Result "✓ Found $($xmlFiles.Count) test result file(s)" Success + +$allFailures = @() + +foreach ($xmlFile in $xmlFiles) { + Write-Result "`nParsing: $($xmlFile.Name)" Info + + try { + [xml]$xml = Get-Content $xmlFile + $testResults = $xml.'test-results' + + Write-Host " Total: $($testResults.total)" -ForegroundColor $colors.Info + Write-Host " Passed: $($testResults.passed)" -ForegroundColor $colors.Success + if ($testResults.failures -gt 0) { + Write-Host " Failed: $($testResults.failures)" -ForegroundColor $colors.Error + } + if ($testResults.errors -gt 0) { + Write-Host " Errors: $($testResults.errors)" -ForegroundColor $colors.Error + } + if ($testResults.skipped -gt 0) { + Write-Host " Skipped: $($testResults.skipped)" -ForegroundColor $colors.Warning + } + if ($testResults.ignored -gt 0) { + Write-Host " Ignored: $($testResults.ignored)" -ForegroundColor $colors.Warning + } + + # Extract failures + $failures = $xml.SelectNodes('.//test-case[@result = "Failure"]') + + foreach ($failure in $failures) { + $allFailures += @{ + Name = $failure.name + File = $xmlFile.Name + Message = $failure.failure.message + StackTrace = $failure.failure.'stack-trace' + } + } + } catch { + Write-Result "✗ Error parsing XML: $_" Error + } +} + +Write-Result "`n✓ Extracted $($allFailures.Count) failures total" Success + +# Save failures to JSON for later analysis +$allFailures | ConvertTo-Json -Depth 10 | Out-File (Join-Path $OutputDir "failures.json") + +if ($Interactive) { + Write-Host "`nPress Enter to continue to Step 4..." + Read-Host | Out-Null +} + +# STEP 4: Read Error Messages +Write-Step "Analyze error messages" 4 + +$failuresByType = @{} + +foreach ($failure in $allFailures) { + $message = $failure.Message -split "`n" | Select-Object -First 1 + + # Categorize failure + $type = 'Other' + if ($message -match 'Expected .* but got') { $type = 'Assertion' } + elseif ($message -match 'Cannot (find|bind)') { $type = 'Exception' } + elseif ($message -match 'timed out') { $type = 'Timeout' } + + if (-not $failuresByType[$type]) { + $failuresByType[$type] = @() + } + $failuresByType[$type] += $failure +} + +Write-Result "Failure breakdown:" Info +$failuresByType.GetEnumerator() | ForEach-Object { + Write-Host " $($_.Key): $($_.Value.Count)" -ForegroundColor $colors.Warning +} + +Write-Result "`nTop failure messages:" Info +$allFailures | Group-Object Message | Sort-Object Count -Descending | Select-Object -First 3 | ForEach-Object { + Write-Host " [$($_.Count)x] $($_.Name -split "`n" | Select-Object -First 1)" -ForegroundColor $colors.Info +} + +# Save analysis +$analysis = @{ + FailuresByType = @{} + TopMessages = @() +} + +$failuresByType.GetEnumerator() | ForEach-Object { + $analysis.FailuresByType[$_.Key] = $_.Value.Count +} + +$allFailures | Group-Object Message | Sort-Object Count -Descending | Select-Object -First 5 | ForEach-Object { + $analysis.TopMessages += @{ + Count = $_.Count + Message = ($_.Name -split "`n" | Select-Object -First 1) + } +} + +$analysis | ConvertTo-Json | Out-File (Join-Path $OutputDir "analysis.json") + +if ($Interactive) { + Write-Host "`nPress Enter to continue to Step 5..." + Read-Host | Out-Null +} + +# STEP 5: Search Logs for Error Markers +Write-Step "Search logs for error markers" 5 + +$logsDir = Join-Path $OutputDir "logs" +if (-not (Test-Path $logsDir)) { + Write-Result "⚠ Logs directory not found" Warning +} else { + $logFiles = Get-ChildItem $logsDir -Filter "*.txt" -ErrorAction SilentlyContinue + if (-not $logFiles) { + Write-Result "⚠ No log files found in logs directory" Warning + } else { + Write-Result "Searching $($logFiles.Count) job log(s) for error markers ([-])" Info + Write-Result "Format: [JobName] [LineNumber] Content" Info + Write-Host "" + + $allErrorLines = @() + + foreach ($logFile in $logFiles) { + $jobName = $logFile.BaseName -replace '^log-', '' + $logLines = @(Get-Content $logFile) + + for ($i = 0; $i -lt $logLines.Count; $i++) { + $line = $logLines[$i] + if ($line -match '\s\[-\]\s') { + $allErrorLines += @{ + JobName = $jobName + LineNumber = $i + 1 + Content = $line + } + } + } + } + + if ($allErrorLines.Count -gt 0) { + Write-Result "✓ Found $($allErrorLines.Count) error marker line(s)" Warning + + $allErrorLines | ForEach-Object { + Write-Host " [$($_.JobName)] [$($_.LineNumber)] $($_.Content)" -ForegroundColor $colors.Error + } + + # Save to file + $allErrorLines | ConvertTo-Json | Out-File (Join-Path $OutputDir "error-markers.json") + Write-Result "✓ Error markers saved to error-markers.json" Success + } else { + Write-Result "✓ No error markers found in logs" Success + } + } +} + +if ($Interactive) { + Write-Host "`nPress Enter to continue to Step 6..." + Read-Host | Out-Null +} + +# STEP 6: Generate Recommendations +Write-Step "Generate recommendations" 6 + +$recommendations = @() + +# Analyze patterns +if ($failuresByType['Assertion']) { + $recommendations += "Multiple assertion failures detected. These indicate test expectations don't match actual behavior." +} + +if ($failuresByType['Exception']) { + $recommendations += "Exception errors found. Check test setup and prerequisites - may indicate missing files, modules, or permissions." +} + +if ($failuresByType['Timeout']) { + $recommendations += "Timeout failures suggest slow or hanging operations. Consider network issues or resource constraints on CI." +} + +# Check for patterns in failure messages +$failureMessages = $allFailures.Message -join "`n" +if ($failureMessages -match 'PackageManagement') { + $recommendations += "PackageManagement module issues detected. Verify module availability and help repository access." +} + +if ($failureMessages -match 'Update-Help') { + $recommendations += "Update-Help failures detected. Check network connectivity to help repository and help installation paths." +} + +Write-Result "`n📋 Recommendations:" Info +if ($recommendations) { + $recommendations | ForEach-Object { Write-Host " • $_" -ForegroundColor $colors.Info } +} else { + Write-Host " • Review failures in detail" -ForegroundColor $colors.Info + Write-Host " • Check if test changes are needed" -ForegroundColor $colors.Info + Write-Host " • Consider environment-specific issues" -ForegroundColor $colors.Info +} + +$recommendations | Out-File (Join-Path $OutputDir "recommendations.txt") + +# Summary +Write-Host "`n=== Analysis Complete ===" -ForegroundColor $colors.Step +Write-Host "Results saved to: $OutputDir" -ForegroundColor $colors.Info +Write-Host " - failures.json (detailed failure data)" -ForegroundColor $colors.Info +Write-Host " - analysis.json (summary analysis)" -ForegroundColor $colors.Info +Write-Host " - recommendations.txt (suggested fixes)" -ForegroundColor $colors.Info +Write-Host " - error-markers.json (error markers from logs)" -ForegroundColor $colors.Info +Write-Host " - logs/ (individual job log files)" -ForegroundColor $colors.Info +Write-Host " - artifacts/ (downloaded test artifacts)" -ForegroundColor $colors.Info + +Write-Host "`nNext steps:" -ForegroundColor $colors.Step +Write-Host "1. Review recommendations.txt for analysis" -ForegroundColor $colors.Info +Write-Host "2. Examine failures.json for detailed error messages" -ForegroundColor $colors.Info +Write-Host "3. Check error-markers.json for specific test failures in logs" -ForegroundColor $colors.Info +Write-Host "4. Review individual job logs in logs/ directory for contextual details" -ForegroundColor $colors.Info +Write-Host "`n" diff --git a/.gitignore b/.gitignore index f115e61e22d..48556cf1b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -119,5 +119,8 @@ assets/manpage/*.gz tmp/* .env.local +# Pester test failure analysis results (generated by analyze-pr-test-failures.ps1) +**/pester-analysis-*/ + # Ignore CTRF report files crtf/* From 8f457fc7140a758b1434940fc71320eef54e7874 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Feb 2026 13:40:04 -0800 Subject: [PATCH 277/378] Skip the flaky `Update-Help` test for the `PackageManagement` module (#26845) --- .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 6bf82d21af1..155654b3b80 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -215,7 +215,7 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { - if ($markAsPending) { + if ($markAsPending -or ($IsLinux -and $moduleName -eq "PackageManagement")) { Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." return } @@ -333,9 +333,7 @@ Describe "Validate Update-Help from the Web for one PowerShell module." -Tags @( $ProgressPreference = $SavedProgressPreference } - ## Update-Help from the web has intermittent connectivity issues that cause CI failures. - ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. - RunUpdateHelpTests -Tag "CI" -MarkAsPending + RunUpdateHelpTests -Tag "CI" } Describe "Validate Update-Help from the Web for one PowerShell module for user scope." -Tags @('CI', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { @@ -347,9 +345,7 @@ Describe "Validate Update-Help from the Web for one PowerShell module for user s $ProgressPreference = $SavedProgressPreference } - ## Update-Help from the web has intermittent connectivity issues that cause CI failures. - ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. - RunUpdateHelpTests -Tag "CI" -UserScope -MarkAsPending + RunUpdateHelpTests -Tag "CI" -UserScope } Describe "Validate Update-Help from the Web for all PowerShell modules." -Tags @('Feature', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { From f3b5603b5dfcb0cc209e9e6c2a8e9a0fdaf16236 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:16:54 -0800 Subject: [PATCH 278/378] Bump github/codeql-action from 4.32.2 to 4.32.3 (#26839) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index c5a0b9ff985..96fb89287d6 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 + uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 + uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a5d05091555..422381cf50c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5 + uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 with: sarif_file: results.sarif From 9d68a05ac3f68f07ea6daed31cb95bf3039a4fb8 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Thu, 19 Feb 2026 04:04:45 +0900 Subject: [PATCH 279/378] Add comprehensive `PSCustomObject` tests for `ConvertTo-Json` (#26743) --- .../ConvertTo-Json.Tests.ps1 | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index 4fe4b0d59b6..8be8631ee6b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -1043,6 +1043,250 @@ Describe 'ConvertTo-Json' -tags "CI" { #endregion Comprehensive Array and Dictionary Tests (Phase 2) + + #region Comprehensive PSCustomObject Tests (Phase 3) + # Test coverage for ConvertTo-Json PSCustomObject serialization + # Covers: Pipeline vs InputObject, ETS vs no ETS, nested structures + + Context 'PSCustomObject basic serialization' { + It 'Should serialize PSCustomObject with single property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Name = 'Test' } + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly '{"Name":"Test"}' + $jsonInputObject | Should -BeExactly '{"Name":"Test"}' + } + + It 'Should serialize PSCustomObject with multiple properties via Pipeline and InputObject' { + $obj = [PSCustomObject][ordered]@{ + Name = 'Test' + Value = 42 + Active = $true + } + $expected = '{"Name":"Test","Value":42,"Active":true}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should preserve property order in PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject][ordered]@{ + Zebra = 1 + Alpha = 2 + Middle = 3 + } + $expected = '{"Zebra":1,"Alpha":2,"Middle":3}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with null property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ NullProp = $null } + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly '{"NullProp":null}' + $jsonInputObject | Should -BeExactly '{"NullProp":null}' + } + } + + Context 'PSCustomObject with various property types' { + It 'Should serialize PSCustomObject with scalar properties via Pipeline and InputObject' { + $obj = [PSCustomObject][ordered]@{ + IntVal = 42 + DoubleVal = 3.14 + StringVal = 'hello' + BoolVal = $true + } + $expected = '{"IntVal":42,"DoubleVal":3.14,"StringVal":"hello","BoolVal":true}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with DateTime property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Date = [DateTime]::new(2024, 6, 15, 10, 30, 0, [DateTimeKind]::Utc) + } + $expected = '{"Date":"2024-06-15T10:30:00Z"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with Guid property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Id = [Guid]'12345678-1234-1234-1234-123456789abc' + } + $expected = '{"Id":"12345678-1234-1234-1234-123456789abc"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with enum property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Day = [DayOfWeek]::Monday } + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly '{"Day":1}' + $jsonInputObject | Should -BeExactly '{"Day":1}' + } + + It 'Should serialize PSCustomObject with enum as string via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Day = [DayOfWeek]::Monday } + $jsonPipeline = $obj | ConvertTo-Json -Compress -EnumsAsStrings + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -EnumsAsStrings + $jsonPipeline | Should -BeExactly '{"Day":"Monday"}' + $jsonInputObject | Should -BeExactly '{"Day":"Monday"}' + } + + It 'Should serialize PSCustomObject with array property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Numbers = @(1, 2, 3) } + $expected = '{"Numbers":[1,2,3]}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with hashtable property via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Config = @{ Key = 'Value' } } + $expected = '{"Config":{"Key":"Value"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Nested PSCustomObject' { + It 'Should serialize nested PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Outer = [PSCustomObject]@{ + Inner = 'value' + } + } + $expected = '{"Outer":{"Inner":"value"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize deeply nested PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Level1 = [PSCustomObject]@{ + Level2 = [PSCustomObject]@{ + Level3 = 'deep' + } + } + } + $expected = '{"Level1":{"Level2":{"Level3":"deep"}}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested PSCustomObject with Depth limit via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ + Level1 = [PSCustomObject]@{ + Level2 = [PSCustomObject]@{ + Level3 = 'deep' + } + } + } + $expected = '{"Level1":{"Level2":"@{Level3=deep}"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 1 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 1 + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize PSCustomObject with mixed nested types via Pipeline and InputObject' { + $obj = [PSCustomObject][ordered]@{ + Child = [PSCustomObject]@{ Name = 'child' } + Items = @(1, 2, 3) + Config = @{ Key = 'Value' } + } + $expected = '{"Child":{"Name":"child"},"Items":[1,2,3],"Config":{"Key":"Value"}}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'PSCustomObject ETS properties' { + It 'Should include NoteProperty on PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Original = 'value' } + $obj | Add-Member -MemberType NoteProperty -Name Added -Value 'added' + $expected = '{"Original":"value","Added":"added"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should include ScriptProperty on PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Value = 10 } + $obj | Add-Member -MemberType ScriptProperty -Name Doubled -Value { $this.Value * 2 } + $expected = '{"Value":10,"Doubled":20}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should include multiple ETS properties on PSCustomObject via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Base = 'base' } + $obj | Add-Member -MemberType NoteProperty -Name Note1 -Value 'note1' + $obj | Add-Member -MemberType NoteProperty -Name Note2 -Value 'note2' + $expected = '{"Base":"base","Note1":"note1","Note2":"note2"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Array of PSCustomObject' { + It 'Should serialize array of PSCustomObject via Pipeline and InputObject' { + $arr = @( + [PSCustomObject][ordered]@{ Id = 1; Name = 'First' } + [PSCustomObject][ordered]@{ Id = 2; Name = 'Second' } + ) + $expected = '[{"Id":1,"Name":"First"},{"Id":2,"Name":"Second"}]' + $jsonPipeline = $arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize single PSCustomObject without array wrapper via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Id = 1 } + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly '{"Id":1}' + $jsonInputObject | Should -BeExactly '{"Id":1}' + } + + It 'Should serialize single PSCustomObject with -AsArray via Pipeline and InputObject' { + $obj = [PSCustomObject]@{ Id = 1 } + $jsonPipeline = $obj | ConvertTo-Json -Compress -AsArray + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -AsArray + $jsonPipeline | Should -BeExactly '[{"Id":1}]' + $jsonInputObject | Should -BeExactly '[{"Id":1}]' + } + } + + #endregion Comprehensive PSCustomObject Tests (Phase 3) + #region Comprehensive Depth Truncation and Multilevel Composition Tests (Phase 4) # Test coverage for ConvertTo-Json depth truncation and complex nested structures # Covers: -Depth parameter behavior, multilevel type compositions From 1965e059bc836046ac0759640f64f9311402c545 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 19 Feb 2026 05:39:53 +1000 Subject: [PATCH 280/378] Fix up default value for parameters with the `in` modifier (#26785) --- .../engine/runtime/Binding/Binders.cs | 7 +++++++ .../engine/Basic/CLRBinding.Tests.ps1 | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index 5913c98829b..027c4886380 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -7201,6 +7201,13 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, var argValue = parameters[i].DefaultValue; if (argValue == null) { + if (parameterType.IsByRef) + { + // When the default value is null for a ByRef parameter (e.g. an optional `in` parameter + // using `default`), expression trees cannot create Expression.Default for the T& type. + // In that case we switch to the element type and use Default(TElement) instead. + parameterType = parameterType.GetElementType(); + } argExprs[i] = Expression.Default(parameterType); } else if (!parameters[i].HasDefaultValue && parameterType != typeof(object) && argValue == Type.Missing) diff --git a/test/powershell/engine/Basic/CLRBinding.Tests.ps1 b/test/powershell/engine/Basic/CLRBinding.Tests.ps1 index 98a05d8518e..cb23fa168db 100644 --- a/test/powershell/engine/Basic/CLRBinding.Tests.ps1 +++ b/test/powershell/engine/Basic/CLRBinding.Tests.ps1 @@ -27,6 +27,12 @@ public class TestClass public static string StaticWithOptionalExpected() => StaticWithOptional(); public static string StaticWithOptional([Optional] string value) => value; + public static int PrimitiveTypeWithInDefault(in int value = default) => value; + + public static Guid ValueTypeWithInDefault(in Guid value = default) => value; + + public static string RefTypeWithInDefault(in string value = default) => value; + public object InstanceWithDefaultExpected() => InstanceWithDefault(); public object InstanceWithDefault(object value = null) => value; @@ -101,6 +107,21 @@ public class TestClassCstorWithOptional $actual | Should -Be $expected } + It "Binds to static method with primitive type with in modifier and default argument" { + $actual = [CLRBindingTests.TestClass]::PrimitiveTypeWithInDefault() + $actual | Should -Be 0 + } + + It "Binds to static method with value type with in modifier and default argument" { + $actual = [CLRBindingTests.TestClass]::ValueTypeWithInDefault() + $actual | Should -Be ([Guid]::Empty) + } + + It "Binds to static method with ref type with in modifier and default argument" { + $actual = [CLRBindingTests.TestClass]::RefTypeWithInDefault() + $null -eq $actual | Should -BeTrue + } + It "Binds to instance method with default argument" { $c = [CLRBindingTests.TestClass]::new() From 212c5f97e3bdb0ec175d407b5d471b4af3a3c45b Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 18 Feb 2026 16:35:10 -0800 Subject: [PATCH 281/378] Update to .NET 11 SDK and update dependencies (#26783) --- .pipelines/templates/nupkg.yml | 12 ++++----- .pipelines/templates/windows-hosted-build.yml | 8 +++--- PowerShell.Common.props | 2 +- build.psm1 | 6 ++--- docs/building/linux.md | 2 +- global.json | 2 +- .../PowerShell.Windows.x64.csproj | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 ++++---- .../Microsoft.WSMan.Management.csproj | 2 +- src/Modules/PSGalleryModules.csproj | 4 +-- src/ResGen/ResGen.csproj | 2 +- .../System.Management.Automation.csproj | 12 ++++----- .../remoting/common/RemoteSessionNamedPipe.cs | 1 - src/TypeCatalogGen/TypeCatalogGen.csproj | 2 +- src/powershell/Program.cs | 2 +- test/Test.Common.props | 2 +- test/tools/NamedPipeConnection/build.ps1 | 4 +-- ...soft.PowerShell.NamedPipeConnection.csproj | 2 +- test/tools/OpenCover/OpenCover.psm1 | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- tools/findMissingNotices.ps1 | 4 +-- tools/packaging/boms/windows.json | 25 +++++++++++-------- tools/packaging/packaging.psm1 | 10 ++++---- tools/packaging/packaging.strings.psd1 | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- .../Microsoft.PowerShell.ConsoleHost.csproj | 2 +- .../System.Management.Automation.csproj | 2 +- 32 files changed, 71 insertions(+), 67 deletions(-) diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 3558c949402..c296aadc242 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -117,13 +117,13 @@ jobs: Start-PSBuild -Clean -Runtime linux-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) $sharedModules | Foreach-Object { - $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net10.0\refint\$_.dll" + $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net11.0\refint\$_.dll" Write-Verbose -Verbose "RefAssembly: $refFile" Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose - $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net10.0\$_.xml" + $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net11.0\$_.xml" if (-not (Test-Path $refDoc)) { Write-Warning "$refDoc not found" - Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net10.0\" | Out-String | Write-Verbose -Verbose + Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net11.0\" | Out-String | Write-Verbose -Verbose } else { Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose @@ -133,13 +133,13 @@ jobs: Start-PSBuild -Clean -Runtime win7-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) $winOnlyModules | Foreach-Object { - $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net10.0\refint\*.dll" + $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net11.0\refint\*.dll" Write-Verbose -Verbose 'RefAssembly: $refFile' Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose - $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net10.0\$_.xml" + $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net11.0\$_.xml" if (-not (Test-Path $refDoc)) { Write-Warning "$refDoc not found" - Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net10.0" | Out-String | Write-Verbose -Verbose + Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net11.0" | Out-String | Write-Verbose -Verbose } else { Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 83c6b32cdfd..a2933e90817 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -274,7 +274,7 @@ jobs: ) $sourceModulePath = Join-Path '$(GlobalToolArtifactPath)' 'publish' 'PowerShell.Windows.x64' 'release' 'Modules' - $destModulesPath = Join-Path "$outputPath" 'temp' 'tools' 'net10.0' 'any' 'modules' + $destModulesPath = Join-Path "$outputPath" 'temp' 'tools' 'net11.0' 'any' 'modules' $modulesToCopy | ForEach-Object { $modulePath = Join-Path $sourceModulePath $_ @@ -282,7 +282,7 @@ jobs: } # Copy ref assemblies - Copy-Item '$(Pipeline.Workspace)/Symbols_$(Architecture)/ref' "$outputPath\temp\tools\net10.0\any\ref" -Recurse -Force + Copy-Item '$(Pipeline.Workspace)/Symbols_$(Architecture)/ref' "$outputPath\temp\tools\net11.0\any\ref" -Recurse -Force $contentPath = Join-Path "$outputPath\temp" 'content' $contentFilesPath = Join-Path "$outputPath\temp" 'contentFiles' @@ -290,14 +290,14 @@ jobs: Remove-Item -Path $contentPath,$contentFilesPath -Recurse -Force # remove PDBs to reduce the size of the nupkg - Remove-Item -Path "$outputPath\temp\tools\net10.0\any\*.pdb" -Recurse -Force + Remove-Item -Path "$outputPath\temp\tools\net11.0\any\*.pdb" -Recurse -Force # create powershell.config.json $config = [ordered]@{} $config.Add("Microsoft.PowerShell:ExecutionPolicy", "RemoteSigned") $config.Add("WindowsPowerShellCompatibilityModuleDenyList", @("PSScheduledJob", "BestPractices", "UpdateServices")) - $configPublishPath = Join-Path "$outputPath" 'temp' 'tools' 'net10.0' 'any' "powershell.config.json" + $configPublishPath = Join-Path "$outputPath" 'temp' 'tools' 'net11.0' 'any' "powershell.config.json" Set-Content -Path $configPublishPath -Value ($config | ConvertTo-Json) -Force -ErrorAction Stop Compress-Archive -Path "$outputPath\temp\*" -DestinationPath "$outputPath\$nupkgName" -Force diff --git a/PowerShell.Common.props b/PowerShell.Common.props index dfc16f830d7..df13f125361 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -144,7 +144,7 @@ (c) Microsoft Corporation. PowerShell 7 - net10.0 + net11.0 13.0 true diff --git a/build.psm1 b/build.psm1 index bf175c5f7c2..ee50c9cde51 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1010,8 +1010,8 @@ function New-PSOptions { [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] [string]$Configuration, - [ValidateSet("net10.0")] - [string]$Framework = "net10.0", + [ValidateSet("net11.0")] + [string]$Framework = "net11.0", # These are duplicated from Start-PSBuild # We do not use ValidateScript since we want tab completion @@ -4021,7 +4021,7 @@ function Clear-NativeDependencies $filesToDeleteWinDesktop = @() $deps = Get-Content "$PublishFolder/pwsh.deps.json" -Raw | ConvertFrom-Json -Depth 20 - $targetRuntime = ".NETCoreApp,Version=v10.0/$($script:Options.Runtime)" + $targetRuntime = ".NETCoreApp,Version=v11.0/$($script:Options.Runtime)" $runtimePackNetCore = $deps.targets.${targetRuntime}.PSObject.Properties.Name -like 'runtimepack.Microsoft.NETCore.App.Runtime*' $runtimePackWinDesktop = $deps.targets.${targetRuntime}.PSObject.Properties.Name -like 'runtimepack.Microsoft.WindowsDesktop.App.Runtime*' diff --git a/docs/building/linux.md b/docs/building/linux.md index 6ccf12073e2..55d96e4c21a 100644 --- a/docs/building/linux.md +++ b/docs/building/linux.md @@ -69,7 +69,7 @@ Start-PSBuild -UseNuGetOrg Congratulations! If everything went right, PowerShell is now built. The `Start-PSBuild` script will output the location of the executable: -`./src/powershell-unix/bin/Debug/net10.0/linux-x64/publish/pwsh`. +`./src/powershell-unix/bin/Debug/net11.0/linux-x64/publish/pwsh`. You should now be running the PowerShell Core that you just built, if you run the above executable. You can run our cross-platform Pester tests with `Start-PSPester -UseNuGetOrg`, and our xUnit tests with `Start-PSxUnit`. diff --git a/global.json b/global.json index c2af57a3fe4..2fe6c88b1f6 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.102" + "version": "11.0.100-preview.1.26104.118" } } diff --git a/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj b/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj index 49d607ebfed..8449c58ebb0 100644 --- a/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj +++ b/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj @@ -2,7 +2,7 @@ Exe - net10.0 + net11.0 enable enable true diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 32e0d329886..ab9bd210353 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 7d9d61ede96..a8c2c34aca2 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index eed0722b4d5..56fa91bcf6b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 78232a2f1af..6df470621f5 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 0f827aab553..daa29bd01f3 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index da5ea7ddd04..e3bb66c87ac 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 7008fe6a08d..9136df5c7b3 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -5,7 +5,7 @@ Microsoft Corporation (c) Microsoft Corporation. - net10.0 + net11.0 true @@ -16,7 +16,7 @@ - + diff --git a/src/ResGen/ResGen.csproj b/src/ResGen/ResGen.csproj index 7fcf1ff3f35..954038cfa51 100644 --- a/src/ResGen/ResGen.csproj +++ b/src/ResGen/ResGen.csproj @@ -2,7 +2,7 @@ Generates C# typed bindings for .resx files - net10.0 + net11.0 resgen Exe true diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 8c77c770a8f..d8a66b2ab74 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs index e21608a378f..fc5226a007e 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs @@ -1302,7 +1302,6 @@ protected override NamedPipeClientStream DoConnect(int timeout) return new NamedPipeClientStream( PipeDirection.InOut, isAsync: true, - isConnected: true, pipeHandle); } catch (Exception) diff --git a/src/TypeCatalogGen/TypeCatalogGen.csproj b/src/TypeCatalogGen/TypeCatalogGen.csproj index ffc3ff99986..83b21e178f5 100644 --- a/src/TypeCatalogGen/TypeCatalogGen.csproj +++ b/src/TypeCatalogGen/TypeCatalogGen.csproj @@ -2,7 +2,7 @@ Generates CorePsTypeCatalog.cs given powershell.inc - net10.0 + net11.0 true TypeCatalogGen Exe diff --git a/src/powershell/Program.cs b/src/powershell/Program.cs index aa79bb8cf07..1de961674df 100644 --- a/src/powershell/Program.cs +++ b/src/powershell/Program.cs @@ -152,7 +152,7 @@ private static void AttemptExecPwshLogin(string[] args) IntPtr executablePathPtr = IntPtr.Zero; try { - mib = [MACOS_CTL_KERN, MACOS_KERN_PROCARGS2, pid]; + mib = new int[] { MACOS_CTL_KERN, MACOS_KERN_PROCARGS2, pid }; unsafe { diff --git a/test/Test.Common.props b/test/Test.Common.props index 3fafbbf8f85..be70bda4bcb 100644 --- a/test/Test.Common.props +++ b/test/Test.Common.props @@ -6,7 +6,7 @@ Microsoft Corporation (c) Microsoft Corporation. - net10.0 + net11.0 13.0 true diff --git a/test/tools/NamedPipeConnection/build.ps1 b/test/tools/NamedPipeConnection/build.ps1 index a0978c4cb34..3d92df01fcd 100644 --- a/test/tools/NamedPipeConnection/build.ps1 +++ b/test/tools/NamedPipeConnection/build.ps1 @@ -36,8 +36,8 @@ param ( [ValidateSet("Debug", "Release")] [string] $BuildConfiguration = "Debug", - [ValidateSet("net10.0")] - [string] $BuildFramework = "net10.0" + [ValidateSet("net11.0")] + [string] $BuildFramework = "net11.0" ) $script:ModuleName = 'Microsoft.PowerShell.NamedPipeConnection' diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 89147481bc3..e004a573673 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -8,7 +8,7 @@ 1.0.0.0 1.0.0 1.0.0 - net10.0 + net11.0 true 13.0 diff --git a/test/tools/OpenCover/OpenCover.psm1 b/test/tools/OpenCover/OpenCover.psm1 index 9e7adb640ca..e8848a15085 100644 --- a/test/tools/OpenCover/OpenCover.psm1 +++ b/test/tools/OpenCover/OpenCover.psm1 @@ -624,7 +624,7 @@ function Invoke-OpenCover [parameter()]$OutputLog = "$HOME/Documents/OpenCover.xml", [parameter()]$TestPath = "${script:psRepoPath}/test/powershell", [parameter()]$OpenCoverPath = "$HOME/OpenCover", - [parameter()]$PowerShellExeDirectory = "${script:psRepoPath}/src/powershell-win-core/bin/CodeCoverage/net10.0/win7-x64/publish", + [parameter()]$PowerShellExeDirectory = "${script:psRepoPath}/src/powershell-win-core/bin/CodeCoverage/net11.0/win7-x64/publish", [parameter()]$PesterLogElevated = "$HOME/Documents/TestResultsElevated.xml", [parameter()]$PesterLogUnelevated = "$HOME/Documents/TestResultsUnelevated.xml", [parameter()]$PesterLogFormat = "NUnitXml", diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index af62ecaacab..5d5f1a9e4f9 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index cbb01a67da5..00cd6825dff 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 42722701d97..1346148baee 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -193,8 +193,8 @@ function Get-CGRegistrations { $registrationChanged = $false - $dotnetTargetName = 'net10.0' - $dotnetTargetNameWin7 = 'net10.0-windows8.0' + $dotnetTargetName = 'net11.0' + $dotnetTargetNameWin7 = 'net11.0-windows8.0' $unixProjectName = 'powershell-unix' $windowsProjectName = 'powershell-win-core' $actualRuntime = $Runtime diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index f811109f818..8248b3d03aa 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -1276,11 +1276,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "mscorrc.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "msquic.dll", "FileType": "NonProduct", @@ -2496,6 +2491,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ref\\System.IO.Compression.Zstandard.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "ref\\System.IO.Pipelines.dll", "FileType": "NonProduct", @@ -3206,6 +3206,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "System.IO.Compression.Zstandard.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "System.IO.dll", "FileType": "NonProduct", @@ -4592,27 +4597,27 @@ "Architecture": null }, { - "Pattern": "RegisterManifest.ps1", + "Pattern": "pwsh.profile.dsc.resource.json", "FileType": "Product", "Architecture": null }, { - "Pattern": "RegisterMicrosoftUpdate.ps1", + "Pattern": "pwsh.profile.resource.ps1", "FileType": "Product", "Architecture": null }, { - "Pattern": "System.Management.Automation.dll", + "Pattern": "RegisterManifest.ps1", "FileType": "Product", "Architecture": null }, { - "Pattern": "pwsh.profile.dsc.resource.json", + "Pattern": "RegisterMicrosoftUpdate.ps1", "FileType": "Product", "Architecture": null }, { - "Pattern": "pwsh.profile.resource.ps1", + "Pattern": "System.Management.Automation.dll", "FileType": "Product", "Architecture": null } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index cddde65aa9f..ca4d5d46712 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -18,7 +18,7 @@ $AllDistributions = @() $AllDistributions += $DebianDistributions $AllDistributions += $RedhatDistributions $AllDistributions += 'macOs' -$script:netCoreRuntime = 'net10.0' +$script:netCoreRuntime = 'net11.0' $script:iconFileName = "Powershell_black_64.png" $script:iconPath = Join-Path -path $PSScriptRoot -ChildPath "../../assets/$iconFileName" -Resolve @@ -2323,12 +2323,12 @@ function Get-MacOSPackageIdentifierInfo param( [Parameter(Mandatory)] [string]$Version, - + [switch]$LTS ) - + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - + # Determine package identifier based on preview status if ($IsPreview) { $PackageIdentifier = 'com.microsoft.powershell-preview' @@ -2336,7 +2336,7 @@ function Get-MacOSPackageIdentifierInfo else { $PackageIdentifier = 'com.microsoft.powershell' } - + return @{ IsPreview = $IsPreview PackageIdentifier = $PackageIdentifier diff --git a/tools/packaging/packaging.strings.psd1 b/tools/packaging/packaging.strings.psd1 index eeb9a86ec10..0bf14ff0dbe 100644 --- a/tools/packaging/packaging.strings.psd1 +++ b/tools/packaging/packaging.strings.psd1 @@ -166,7 +166,7 @@ open {0} - + diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index f358b454baa..6a96c8b1173 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -1,6 +1,6 @@ - net10.0 + net11.0 $(RefAsmVersion) true $(SnkFile) diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj index c0794a6a708..07161449da2 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj @@ -1,6 +1,6 @@ - net10.0 + net11.0 $(RefAsmVersion) true $(SnkFile) diff --git a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj index f4626e110fd..d633173b9cf 100644 --- a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj +++ b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj @@ -1,6 +1,6 @@ - net10.0 + net11.0 $(RefAsmVersion) true $(SnkFile) From 2af5ad14a3d6910600bb8e4905a95fcf8aa86c44 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:39:42 +0000 Subject: [PATCH 282/378] Update `LangVersion` to `preview` (#26214) --- PowerShell.Common.props | 2 +- .../WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs | 4 ++-- .../PSVersionInfoGenerator/PSVersionInfoGenerator.csproj | 2 +- test/Test.Common.props | 2 +- test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj | 2 +- .../src/code/Microsoft.PowerShell.NamedPipeConnection.csproj | 2 +- .../Microsoft.PowerShell.Commands.Utility.csproj | 2 +- .../Microsoft.PowerShell.ConsoleHost.csproj | 2 +- .../System.Management.Automation.csproj | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index df13f125361..fa2a5305e32 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -145,7 +145,7 @@ PowerShell 7 net11.0 - 13.0 + preview true true diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs index 9bd76f99413..ea650e80e67 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs @@ -81,9 +81,9 @@ public WebCmdletElementCollection InputFields { List parsedFields = new(); MatchCollection fieldMatch = HtmlParser.InputFieldRegex.Matches(Content); - foreach (Match field in fieldMatch) + foreach (Match match in fieldMatch) { - parsedFields.Add(CreateHtmlObject(field.Value, "INPUT")); + parsedFields.Add(CreateHtmlObject(match.Value, "INPUT")); } _inputFields = new WebCmdletElementCollection(parsedFields); diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 1099b2a3c11..44d93a5e31b 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -7,7 +7,7 @@ netstandard2.0 - 13.0 + preview true true enable diff --git a/test/Test.Common.props b/test/Test.Common.props index be70bda4bcb..8a5522e9eaa 100644 --- a/test/Test.Common.props +++ b/test/Test.Common.props @@ -7,7 +7,7 @@ (c) Microsoft Corporation. net11.0 - 13.0 + preview true true diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 5cbc66081a3..90143a9f482 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -3,7 +3,7 @@ Exe $(PERFLAB_TARGET_FRAMEWORKS) net5.0 - 13.0 + preview diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index e004a573673..ba216dee23e 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -10,7 +10,7 @@ 1.0.0 net11.0 true - 13.0 + preview diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 6a96c8b1173..34ead3a2dc5 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 13.0 + preview diff --git a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj index 07161449da2..378ca59ff95 100644 --- a/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj +++ b/tools/packaging/projects/reference/Microsoft.PowerShell.ConsoleHost/Microsoft.PowerShell.ConsoleHost.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 13.0 + preview diff --git a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj index d633173b9cf..8f80aa50a3d 100644 --- a/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj +++ b/tools/packaging/projects/reference/System.Management.Automation/System.Management.Automation.csproj @@ -5,7 +5,7 @@ true $(SnkFile) true - 13.0 + preview From 2f08eb44e69f0cb5d995dfccb541fd07df215d12 Mon Sep 17 00:00:00 2001 From: Yoshifumi Date: Fri, 20 Feb 2026 04:04:48 +0900 Subject: [PATCH 283/378] Add comprehensive PowerShell class tests for `ConvertTo-Json` (#26769) --- .../ConvertTo-Json.Tests.ps1 | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index 8be8631ee6b..f1ddc43a220 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -1738,4 +1738,156 @@ Describe 'ConvertTo-Json' -tags "CI" { } #endregion Comprehensive Depth Truncation and Multilevel Composition Tests (Phase 4) + + #region Comprehensive PowerShell Class Tests (Phase 5) + # Test coverage for ConvertTo-Json PowerShell class serialization + # Covers: Pipeline vs InputObject, ETS vs no ETS, nested structures, inheritance + + Context 'PowerShell class serialization' { + BeforeAll { + class SimpleClass { + [string]$StringVal + [int]$IntVal + [bool]$BoolVal + [double]$DoubleVal + [bigint]$BigIntVal + [guid]$GuidVal + [ipaddress]$IPVal + [object[]]$ArrayVal + [System.Collections.Specialized.OrderedDictionary]$DictVal + hidden [string]$HiddenVal + } + } + + It 'Should serialize PowerShell class with various property types including ETS via Pipeline and InputObject' { + $obj = [SimpleClass]::new() + $obj.StringVal = 'hello' + $obj.IntVal = 42 + $obj.BoolVal = $true + $obj.DoubleVal = 3.14 + $obj.BigIntVal = [bigint]::Parse('99999999999999999999') + $obj.GuidVal = [guid]'12345678-1234-1234-1234-123456789abc' + $obj.IPVal = [ipaddress]::Parse('192.168.1.1') + $obj.ArrayVal = @(1, 'two', $true) + $obj.DictVal = [ordered]@{ Key = 'Value'; Nested = [ordered]@{ Inner = 1 } } + $obj.HiddenVal = 'secret' + $obj | Add-Member -MemberType NoteProperty -Name ETSNote -Value 'note' + $obj | Add-Member -MemberType ScriptProperty -Name ETSScript -Value { $this.StringVal.Length } + $obj.IPVal | Add-Member -MemberType NoteProperty -Name Label -Value 'primary' + $expectedPipeline = '{"StringVal":"hello","IntVal":42,"BoolVal":true,"DoubleVal":3.14,"BigIntVal":99999999999999999999,"GuidVal":"12345678-1234-1234-1234-123456789abc","IPVal":{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952},"ArrayVal":[1,"two",true],"DictVal":{"Key":"Value","Nested":{"Inner":1}},"HiddenVal":"secret","ETSNote":"note","ETSScript":5}' + $expectedInputObject = '{"StringVal":"hello","IntVal":42,"BoolVal":true,"DoubleVal":3.14,"BigIntVal":99999999999999999999,"GuidVal":"12345678-1234-1234-1234-123456789abc","IPVal":{"AddressFamily":2,"ScopeId":null,"IsIPv6Multicast":false,"IsIPv6LinkLocal":false,"IsIPv6SiteLocal":false,"IsIPv6Teredo":false,"IsIPv6UniqueLocal":false,"IsIPv4MappedToIPv6":false,"Address":16885952},"ArrayVal":[1,"two",true],"DictVal":{"Key":"Value","Nested":{"Inner":1}},"HiddenVal":"secret"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress -Depth 3 + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress -Depth 3 + $jsonPipeline | Should -BeExactly $expectedPipeline + $jsonInputObject | Should -BeExactly $expectedInputObject + } + + It 'Should serialize PowerShell class with default values via Pipeline and InputObject' { + $obj = [SimpleClass]::new() + $expected = '{"StringVal":null,"IntVal":0,"BoolVal":false,"DoubleVal":0.0,"BigIntVal":0,"GuidVal":"00000000-0000-0000-0000-000000000000","IPVal":null,"ArrayVal":null,"DictVal":null,"HiddenVal":null}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'Nested PowerShell class' { + BeforeAll { + class InnerClass { + [string]$Inner + } + + class OuterClass { + [string]$Outer + [InnerClass]$Child + } + + class DeepClass { + [string]$Name + [OuterClass]$Nested + } + } + + It 'Should serialize deeply nested PowerShell class via Pipeline and InputObject' { + $inner = [InnerClass]@{ Inner = 'deep' } + $outer = [OuterClass]@{ Outer = 'middle'; Child = $inner } + $deep = [DeepClass]@{ Name = 'top'; Nested = $outer } + $expected = '{"Name":"top","Nested":{"Outer":"middle","Child":{"Inner":"deep"}}}' + $jsonPipeline = $deep | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $deep -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize nested PowerShell class with null child via Pipeline and InputObject' { + $outer = [OuterClass]@{ Outer = 'outer value'; Child = $null } + $expected = '{"Outer":"outer value","Child":null}' + $jsonPipeline = $outer | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $outer -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + Context 'PowerShell class inheritance' { + BeforeAll { + class BaseClass { + [string]$BaseProp + } + + class ChildClass : BaseClass { + [string]$ChildProp + } + + class GrandChildClass : ChildClass { + [string]$GrandChildProp + } + } + + It 'Should serialize derived class with base properties via Pipeline and InputObject' { + $obj = [ChildClass]@{ BaseProp = 'base'; ChildProp = 'child' } + $expected = '{"ChildProp":"child","BaseProp":"base"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + It 'Should serialize multi-level inherited class via Pipeline and InputObject' { + $obj = [GrandChildClass]@{ + BaseProp = 'base' + ChildProp = 'child' + GrandChildProp = 'grandchild' + } + $expected = '{"GrandChildProp":"grandchild","ChildProp":"child","BaseProp":"base"}' + $jsonPipeline = $obj | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $obj -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + + } + + Context 'Mixed PSCustomObject and PowerShell class' { + BeforeAll { + class MixedClass { + [string]$ClassName + } + } + + It 'Should serialize array with mixed types via Pipeline and InputObject' { + $classObj = [MixedClass]@{ ClassName = 'class' } + $customObj = [PSCustomObject]@{ CustomName = 'custom' } + $arr = @($classObj, $customObj) + $expected = '[{"ClassName":"class"},{"CustomName":"custom"}]' + $jsonPipeline = $arr | ConvertTo-Json -Compress + $jsonInputObject = ConvertTo-Json -InputObject $arr -Compress + $jsonPipeline | Should -BeExactly $expected + $jsonInputObject | Should -BeExactly $expected + } + } + + #endregion Comprehensive PowerShell Class Tests (Phase 5) + } From cf40400cb9b250a65a65fc18064884cb73be10d1 Mon Sep 17 00:00:00 2001 From: kasperk81 <83082615+kasperk81@users.noreply.github.com> Date: Thu, 19 Feb 2026 21:28:04 +0200 Subject: [PATCH 284/378] Fetch latest ICU release version dynamically (#26827) --- tools/packaging/packaging.psm1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index ca4d5d46712..f400e060b25 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2148,7 +2148,7 @@ function Get-PackageDependencies # than the build version and we know that older versions just works. # $MinICUVersion = 60 # runtime minimum supported - $BuildICUVersion = 76 # current build version + $BuildICUVersion = Get-IcuLatestRelease $MaxICUVersion = $BuildICUVersion + 30 # headroom if ($Distribution -eq 'deb') { @@ -5808,3 +5808,15 @@ function Test-IsProductFile { return $false } + +# Get major version from latest ICU release (latest: stable version) +function Get-IcuLatestRelease { + $response = Invoke-WebRequest -Uri "https://github.com/unicode-org/icu/releases/latest" + $tagUrl = ($response.Links | Where-Object href -like "*releases/tag/release-*")[0].href + + if ($tagUrl -match 'release-(\d+)\.') { + return [int]$Matches[1] + } + + throw "Unable to determine the latest ICU release version." +} From 6a91b1f4c7c2c56c555930145f7e72091c3bcc87 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Thu, 19 Feb 2026 20:56:46 -0500 Subject: [PATCH 285/378] Bring the `v7.6.0-rc.1` changelog to master (#26857) --- CHANGELOG/preview.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index f1c5f566289..851640f8cc5 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,39 @@ # Preview Changelog +## [7.6.0-rc.1] - 2026-02-19 + +### Tests + +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26705) + +### Build and Packaging Improvements + +
    + + + +

    Expand to see details.

    + +
    + +
      +
    • Update branch for release (#26779)
    • +
    • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26767)
    • +
    • Update Microsoft.PowerShell.Native package version (#26748)
    • +
    • Move PowerShell build to depend on .NET SDK 10.0.102 (#26717)
    • +
    • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26715)
    • +
    • Fix macOS preview package identifier detection to use version string (#26709)
    • +
    • Update metadata.json to update the Latest attribute with a better name (#26708)
    • +
    • Remove unused runCodesignValidationInjection variable from pipeline templates (#26707)
    • +
    • Update Get-ChangeLog to handle backport PRs correctly (#26706)
    • +
    • Bring release changes from the v7.6.0-preview.6 release (#26626)
    • +
    • Fix the DSC test by skipping AfterAll cleanup if the initial setup in BeforeAll failed (#26622)
    • +
    + +
    + +[7.6.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.6...v7.6.0-rc.1 + ## [7.6.0-preview.6] - 2025-12-11 ### Engine Updates and Fixes From f2c9775d7084192b69f2d5155a33035a44d37596 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Fri, 20 Feb 2026 12:34:59 -0500 Subject: [PATCH 286/378] Update metadata.json for v7.6.0-rc.1 (#26856) --- tools/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index e0f4952c588..1bf3e96e39c 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,10 +1,10 @@ { "StableReleaseTag": "v7.5.4", - "PreviewReleaseTag": "v7.6.0-preview.5", + "PreviewReleaseTag": "v7.6.0-rc.1", "ServicingReleaseTag": "v7.0.13", "ReleaseTag": "v7.5.4", "LTSReleaseTag" : ["v7.4.13"], - "NextReleaseTag": "v7.6.0-preview.6", + "NextReleaseTag": "v7.7.0-preview.1", "LTSRelease": { "PublishToChannels": false, "Package": false }, "StableRelease": { "PublishToChannels": false, "Package": false } } From b58ec3609342ab8a9bdffe65924e57f77dbcf9c7 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 20 Feb 2026 10:29:13 -0800 Subject: [PATCH 287/378] Exclude .exe packages from publishing to GitHub (#26859) --- .pipelines/templates/release-githubNuget.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 5f67ce6a9e4..206079c555f 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -35,6 +35,14 @@ jobs: targetType: inline script: | $Path = "$(Pipeline.Workspace)/GitHubPackages" + + # The .exe packages are for Windows Update only and should not be uploaded to GitHub release. + $exefiles = Get-ChildItem -Path $Path -Filter *.exe + if ($exefiles) { + Write-Verbose -Verbose "Remove .exe packages:" + $exefiles | Remove-Item -Force -Verbose + } + $OutputPath = Join-Path $Path 'hashes.sha256' $packages = Get-ChildItem -Path $Path -Include * -Recurse -File $checksums = $packages | From c19a440244a5b4b4f63b987fb1a816dec77ed2a5 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 20 Feb 2026 14:05:55 -0800 Subject: [PATCH 288/378] Fix `Import-Module.Tests.ps1` to handle Arm32 platform (#26862) --- test/powershell/Language/Scripting/Requires.Tests.ps1 | 2 +- .../Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/powershell/Language/Scripting/Requires.Tests.ps1 b/test/powershell/Language/Scripting/Requires.Tests.ps1 index d4cad910e10..b5cbb397325 100644 --- a/test/powershell/Language/Scripting/Requires.Tests.ps1 +++ b/test/powershell/Language/Scripting/Requires.Tests.ps1 @@ -41,7 +41,7 @@ Describe "Requires tests" -Tags "CI" { BeforeAll { $currentVersion = $PSVersionTable.PSVersion - $powerShellVersions = "1.0", "2.0", "3.0", "4.0", "5.0", "5.1", "6.0", "6.1", "6.2", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6" + $powerShellVersions = "1.0", "2.0", "3.0", "4.0", "5.0", "5.1", "6.0", "6.1", "6.2", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7" $latestVersion = [version]($powerShellVersions | Sort-Object -Descending -Top 1) $nonExistingMinor = "$($latestVersion.Major).$($latestVersion.Minor + 1)" $nonExistingMajor = "$($latestVersion.Major + 1).0" diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 index 6885abe847d..19dc80caf28 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 @@ -62,6 +62,7 @@ Describe "Import-Module" -Tags "CI" { 'X86' { 'x86' } 'X64' { 'amd64' } 'Arm64' { 'arm' } + 'Arm' { 'arm' } default { throw "Unknown processor architecture" } } New-ModuleManifest -Path "$TestDrive\TestModule.psd1" -ProcessorArchitecture $currentProcessorArchitecture From 19fa6a9f79eefebaa8c401b759dcdacc3d4cc703 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:40:05 +0000 Subject: [PATCH 289/378] Remove obsolete `CA2006` rule suppression (#25939) --- .../security/CertificateProvider.cs | 1 - .../engine/remoting/fanin/WSManNativeAPI.cs | 9 --------- .../remoting/fanin/WSManPluginFacade.cs | 10 ---------- .../remoting/fanin/WSManTransportManager.cs | 19 +++---------------- .../security/SecuritySupport.cs | 2 -- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs index 08ee5a70f51..37c687a7770 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs @@ -3424,7 +3424,6 @@ internal static IntPtr GetOwnerWindow(PSHost host) return IntPtr.Zero; } #else - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private static IntPtr hWnd = IntPtr.Zero; private static bool firstRun = true; diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs index 289f88c576f..d7bce634620 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs @@ -304,7 +304,6 @@ internal struct WSManUserNameCredentialStruct /// /// Making password secure. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr password; } @@ -626,7 +625,6 @@ internal class WSManBinaryOrTextDataStruct { internal int bufferLength; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr data; } @@ -637,10 +635,8 @@ internal class WSManData_ManToUn : IDisposable { private readonly WSManDataStruct _internalData; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _marshalledObject = IntPtr.Zero; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _marshalledBuffer = IntPtr.Zero; /// @@ -933,7 +929,6 @@ internal struct WSManStreamIDSetStruct { internal int streamIDsCount; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr streamIDs; } @@ -1085,7 +1080,6 @@ internal struct WSManOptionSetStruct /// /// Pointer to an array of WSManOption objects. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr options; internal bool optionsMustUnderstand; @@ -1223,13 +1217,11 @@ internal struct WSManCommandArgSetInternal { internal int argsCount; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr args; } private WSManCommandArgSetInternal _internalData; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private MarshalledObject _data; #region Managed to Unmanaged @@ -1733,7 +1725,6 @@ internal struct WSManShellAsyncCallback // GC handle which prevents garbage collector from collecting this delegate. private GCHandle _gcHandle; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private readonly IntPtr _asyncCallback; internal WSManShellAsyncCallback(WSManShellCompletionFunction callback) diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginFacade.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginFacade.cs index 7fbc236a4dd..2d99a42cfb9 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginFacade.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginFacade.cs @@ -343,61 +343,51 @@ internal class WSManPluginEntryDelegatesInternal /// /// WsManPluginShutdownPluginCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginShutdownPluginCallbackNative; /// /// WSManPluginShellCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginShellCallbackNative; /// /// WSManPluginReleaseShellContextCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginReleaseShellContextCallbackNative; /// /// WSManPluginCommandCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginCommandCallbackNative; /// /// WSManPluginReleaseCommandContextCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginReleaseCommandContextCallbackNative; /// /// WSManPluginSendCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginSendCallbackNative; /// /// WSManPluginReceiveCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginReceiveCallbackNative; /// /// WSManPluginSignalCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginSignalCallbackNative; /// /// WSManPluginConnectCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginConnectCallbackNative; /// /// WSManPluginCommandCallbackNative. /// - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] internal IntPtr wsManPluginShutdownCallbackNative; } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs index 58b9cfe098d..d4ee779b5a2 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManTransportManager.cs @@ -317,18 +317,13 @@ internal CompletionEventArgs(CompletionNotification notification) #endregion #region Private Data + // operation handles are owned by WSMan - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManSessionHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManShellOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManReceiveOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManSendOperationHandle; + // this is used with WSMan callbacks to represent a session transport manager. private long _sessionContextID; @@ -2643,7 +2638,6 @@ private void DisposeWSManAPIDataAsync() /// internal class WSManAPIDataCommon : IDisposable { - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _handle; // if any private WSManNativeApi.WSManStreamIDSet_ManToUn _inputStreamSet; @@ -2791,18 +2785,11 @@ internal sealed class WSManClientCommandTransportManager : BaseClientCommandTran // operation handles private readonly IntPtr _wsManShellOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManCmdOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _cmdSignalOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManReceiveOperationHandle; - - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private IntPtr _wsManSendOperationHandle; + // this is used with WSMan callbacks to represent a command transport manager. private long _cmdContextId; diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 12e03d85174..dc6d048c5b1 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1607,10 +1607,8 @@ internal static void CurrentDomain_ProcessExit(object sender, EventArgs e) } } - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private static IntPtr s_amsiContext = IntPtr.Zero; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] private static IntPtr s_amsiSession = IntPtr.Zero; private static readonly bool s_amsiInitFailed = false; From cfd59665308d440795c6430d9ae0f5432211e609 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:11:12 +0000 Subject: [PATCH 290/378] Enable CA1852: Seal internal types (#25890) --- .globalconfig | 4 ++++ test/tools/TestAlc/init/Init.cs | 2 +- test/tools/TestExe/TestExe.cs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.globalconfig b/.globalconfig index 21ecbc766aa..e0dd4ccb9e5 100644 --- a/.globalconfig +++ b/.globalconfig @@ -510,6 +510,10 @@ dotnet_diagnostic.CA1846.severity = warning # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1847 dotnet_diagnostic.CA1847.severity = warning +# CA1852: Seal internal types +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852 +dotnet_diagnostic.CA1852.severity = warning + # CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' # https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1853 dotnet_diagnostic.CA1853.severity = warning diff --git a/test/tools/TestAlc/init/Init.cs b/test/tools/TestAlc/init/Init.cs index 4241e56fa4e..33f6635f712 100644 --- a/test/tools/TestAlc/init/Init.cs +++ b/test/tools/TestAlc/init/Init.cs @@ -10,7 +10,7 @@ namespace Test.Isolated.Init { - internal class CustomLoadContext : AssemblyLoadContext + internal sealed class CustomLoadContext : AssemblyLoadContext { private readonly string _dependencyDirPath; diff --git a/test/tools/TestExe/TestExe.cs b/test/tools/TestExe/TestExe.cs index a9b3d834261..9230f9e6bff 100644 --- a/test/tools/TestExe/TestExe.cs +++ b/test/tools/TestExe/TestExe.cs @@ -20,7 +20,7 @@ internal enum EnvTarget System = 2, } - internal class TestExe + internal sealed class TestExe { private static int Main(string[] args) { From 7ca2b72af765aa52ebde99aa1214f6ec29f51868 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Feb 2026 12:33:12 -0800 Subject: [PATCH 291/378] Fix a preview detection test for the packaging script (#26882) --- test/packaging/packaging.tests.ps1 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 index cc4bbe0d728..a7d322205bc 100644 --- a/test/packaging/packaging.tests.ps1 +++ b/test/packaging/packaging.tests.ps1 @@ -46,18 +46,15 @@ Describe "Packaging Module Functions" { $result.PackageIdentifier | Should -Be "com.microsoft.powershell" } - It "Should NOT use package name for preview detection (bug fix verification)" { + It "Should NOT use package name for preview detection (bug fix verification) - " -TestCases @( + @{ Version = "7.6.0-preview.6"; Name = "Preview" } + @{ Version = "7.6.0-rc.1"; Name = "RC" } + ) { # This test verifies the fix for issue #26673 # The bug was using ($Name -like '*-preview') which always returned false # because preview builds use Name="powershell" not "powershell-preview" - - $Version = "7.6.0-preview.6" - $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" - - # The INCORRECT logic (the bug): $Name -like '*-preview' - $incorrectCheck = $Name -like '*-preview' - $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" - + param($Version) + # The CORRECT logic (the fix): uses version string $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" From f3eb51b1f40c9b731dfcf46284f51a646973c6c8 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:35:13 -0800 Subject: [PATCH 292/378] Add GitOps policy to auto-label backport candidates when CL-BuildPackaging is added (#26881) --- ...d.clBuildPackaging.addBackportConsider.yml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/policies/labelAdded.clBuildPackaging.addBackportConsider.yml diff --git a/.github/policies/labelAdded.clBuildPackaging.addBackportConsider.yml b/.github/policies/labelAdded.clBuildPackaging.addBackportConsider.yml new file mode 100644 index 00000000000..78edc18cb1a --- /dev/null +++ b/.github/policies/labelAdded.clBuildPackaging.addBackportConsider.yml @@ -0,0 +1,56 @@ +id: labelAdded.clBuildPackaging.addBackportConsider +name: GitOps.PullRequestIssueManagement +description: Add backport consideration labels when CL-BuildPackaging is added to an open PR targeting master +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: Add BackPort-7.4.x-Consider when CL-BuildPackaging is added to open PR targeting master + if: + - payloadType: Pull_Request + - isOpen + - labelAdded: + label: CL-BuildPackaging + - targetsBranch: + branch: master + - not: + hasLabel: + label: BackPort-7.4.x-Consider + then: + - addLabel: + label: BackPort-7.4.x-Consider + + - description: Add BackPort-7.5.x-Consider when CL-BuildPackaging is added to open PR targeting master + if: + - payloadType: Pull_Request + - isOpen + - labelAdded: + label: CL-BuildPackaging + - targetsBranch: + branch: master + - not: + hasLabel: + label: BackPort-7.5.x-Consider + then: + - addLabel: + label: BackPort-7.5.x-Consider + + - description: Add BackPort-7.6.x-Consider when CL-BuildPackaging is added to open PR targeting master + if: + - payloadType: Pull_Request + - isOpen + - labelAdded: + label: CL-BuildPackaging + - targetsBranch: + branch: master + - not: + hasLabel: + label: BackPort-7.6.x-Consider + then: + - addLabel: + label: BackPort-7.6.x-Consider +onFailure: +onSuccess: From 7cdcd5893f784ddee1e6db702013190e83c0bb7a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Feb 2026 13:45:32 -0800 Subject: [PATCH 293/378] Correct the package name for .deb and .rpm packages (#26877) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Travis Plunk --- .github/workflows/macos-ci.yml | 3 ++- tools/packaging/packaging.psm1 | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 8f15a2f3a6d..c7717a26738 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -54,6 +54,7 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v6 @@ -161,7 +162,7 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: - macos-15-large steps: diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index f400e060b25..16ae6b21fcc 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1159,12 +1159,16 @@ function New-UnixPackage { } # Determine if the version is a preview version - # Only LTS packages get a prefix in the name - # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) - # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # For deb/rpm packages, use the '-lts' and '-preview' channel suffix variants to match existing names on packages.microsoft.com. + # For osxpkg package, only LTS packages get a channel suffix in the name. $Name = if($LTS) { "powershell-lts" } + elseif ($IsPreview -and $Type -ne "osxpkg") { + "powershell-preview" + } else { "powershell" } From 43d4388d038a663bbd500481d3fd52817c00b93e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:27:47 -0800 Subject: [PATCH 294/378] Bump github/codeql-action from 4.32.3 to 4.32.4 (#26879) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 96fb89287d6..fbbb5c31efe 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 + uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 + uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 422381cf50c..c51e85b9448 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 with: sarif_file: results.sarif From a6e0d94c7c002618c10f14b9c70addfc2f7cf8f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:57:39 -0800 Subject: [PATCH 295/378] Bump actions/dependency-review-action from 4.8.2 to 4.8.3 (#26861) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index dbef2e1c8b2..6bace648853 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 + uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 From 7311378cf9bdb8567becaecdcad49315da00175b Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:59:25 -0700 Subject: [PATCH 296/378] Add version in description and pass store task on failure (#26885) --- .pipelines/templates/release-MSIX-Publish.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 2bf1e130103..a92c71f826b 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -59,8 +59,15 @@ jobs: $json.listings.'en-us'.baseListing.releaseNotes = $message + # Add PowerShell version to the top of the description + $description = $json.listings.'en-us'.baseListing.description + $version = "$(ReleaseTag)" + $updatedDescription = "Version: $version`n`n$description" + $json.listings.'en-us'.baseListing.description = $updatedDescription + Write-Verbose -Verbose "Updated description: $updatedDescription" + $json | ConvertTo-Json -Depth 100 | Set-Content $jsonPath -Encoding UTF8 - displayName: 'Update Release Notes in JSON' + displayName: 'Add Changelog Link and Version Number to SBJSON' - task: PowerShell@2 inputs: @@ -101,6 +108,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) + continueOnError: true inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' @@ -114,6 +122,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) + continueOnError: true inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' From 6e2b4c784a8b2e832e5442c9b2c72f3433339873 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 25 Feb 2026 14:51:56 -0500 Subject: [PATCH 297/378] Split TPN manifest and Component Governance manifest (#26891) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../templates/compliance/generateNotice.yml | 2 +- .vsts-ci/linux-internal.yml | 2 +- .vsts-ci/mac.yml | 2 +- .vsts-ci/psresourceget-acr.yml | 2 +- .vsts-ci/windows-arm64.yml | 2 +- tools/{ => cgmanifest/main}/cgmanifest.json | 96 +-- tools/cgmanifest/tpn/cgmanifest.json | 755 ++++++++++++++++++ tools/clearlyDefined/ClearlyDefined.ps1 | 2 +- .../Find-LastHarvestedVersion.ps1 | 156 ++++ .../src/ClearlyDefined/ClearlyDefined.psm1 | 275 ++++++- tools/findMissingNotices.ps1 | 234 +++++- tools/packaging/packaging.psm1 | 2 +- 12 files changed, 1459 insertions(+), 71 deletions(-) rename tools/{ => cgmanifest/main}/cgmanifest.json (91%) create mode 100644 tools/cgmanifest/tpn/cgmanifest.json create mode 100644 tools/clearlyDefined/Find-LastHarvestedVersion.ps1 diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 0a38ed8f8e6..90fd08dd8d9 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -55,7 +55,7 @@ jobs: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' inputs: - sourceScanPath: '$(repoRoot)\tools' + sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - pwsh: | $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml index c1c8bcef62d..b90ab0d9eb4 100644 --- a/.vsts-ci/linux-internal.yml +++ b/.vsts-ci/linux-internal.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 4d3681edca1..678ded65259 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index 194c7ba9f57..225e2699533 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -34,7 +34,7 @@ pr: - .github/ISSUE_TEMPLATE/* - .github/workflows/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/windows-arm64.yml b/.vsts-ci/windows-arm64.yml index 4c75c1d31e0..1c4bc2ee8af 100644 --- a/.vsts-ci/windows-arm64.yml +++ b/.vsts-ci/windows-arm64.yml @@ -28,7 +28,7 @@ pr: - .dependabot/config.yml - .github/ISSUE_TEMPLATE/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/tools/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json similarity index 91% rename from tools/cgmanifest.json rename to tools/cgmanifest/main/cgmanifest.json index 2334f070852..a0746028a56 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -85,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -125,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -165,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -175,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -185,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -205,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -215,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -225,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -235,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -245,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -255,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -265,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -275,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -285,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -295,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -305,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -315,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -325,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -335,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -355,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -365,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -375,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -435,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -445,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -455,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -475,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -505,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -515,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -525,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -535,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -545,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -555,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -565,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -575,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -585,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -595,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -605,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -615,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -625,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -635,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -645,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -655,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -705,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -715,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -725,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -745,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false diff --git a/tools/cgmanifest/tpn/cgmanifest.json b/tools/cgmanifest/tpn/cgmanifest.json new file mode 100644 index 00000000000..a0746028a56 --- /dev/null +++ b/tools/cgmanifest/tpn/cgmanifest.json @@ -0,0 +1,755 @@ +{ + "Registrations": [ + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers.Unstable", + "Version": "1.0.0.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers", + "Version": "1.0.0-beta.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Humanizer.Core", + "Version": "2.14.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Json.More.Net", + "Version": "2.1.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonPointer.Net", + "Version": "5.3.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonSchema.Net", + "Version": "7.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Markdig.Signed", + "Version": "0.45.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.ApplicationInsights", + "Version": "2.23.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Bcl.AsyncInterfaces", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Analyzers", + "Version": "3.11.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Common", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.CSharp", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Extensions.ObjectPool", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Management.Infrastructure.Runtime.Win", + "Version": "3.0.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.PowerShell.MarkdownRender", + "Version": "7.2.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Security.Extensions", + "Version": "1.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.Registry.AccessControl", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.SystemEvents", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Windows.Compatibility", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Newtonsoft.Json", + "Version": "13.0.4" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x86.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x86.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers.Unstable", + "Version": "1.2.0.556" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers", + "Version": "1.1.118" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.CodeDom", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition.Registration", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Configuration.ConfigurationManager", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.Odbc", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.OleDb", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.SqlClient", + "Version": "4.9.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.EventLog", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.PerformanceCounter", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.AccountManagement", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.Protocols", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Drawing.Common", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Packaging", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Management", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Net.Http.WinHttpHandler", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Reflection.Context", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Runtime.Caching", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Pkcs", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.ProtectedData", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Xml", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Permissions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Http", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetFramingBase", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetTcp", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Primitives", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Syndication", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceProcess.ServiceController", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Speech", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Web.Services.Description", + "Version": "8.1.2" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Windows.Extensions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + } + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" +} diff --git a/tools/clearlyDefined/ClearlyDefined.ps1 b/tools/clearlyDefined/ClearlyDefined.ps1 index 1830c2969e5..c5303b8622b 100644 --- a/tools/clearlyDefined/ClearlyDefined.ps1 +++ b/tools/clearlyDefined/ClearlyDefined.ps1 @@ -21,7 +21,7 @@ if ($ForceModuleReload) { Import-Module -Name "$PSScriptRoot/src/ClearlyDefined" @extraParams -$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest.json" | ConvertFrom-Json +$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest/main/cgmanifest.json" | ConvertFrom-Json $fullCgList = $cgManfest.Registrations.Component | ForEach-Object { [Pscustomobject]@{ diff --git a/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 new file mode 100644 index 00000000000..a989a3e1fc4 --- /dev/null +++ b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 @@ -0,0 +1,156 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Find the last harvested version of a NuGet package from ClearlyDefined. + +.DESCRIPTION + Searches for the last harvested version of a package by checking versions + backwards from the specified current version. This is useful for reverting + to a known-good harvested version when a newer version hasn't been harvested yet. + +.PARAMETER Name + The NuGet package name to search for. + +.PARAMETER CurrentVersion + The version to start searching backwards from. Version comparison uses semantic versioning. + +.PARAMETER PackageSourceName + The NuGet package source name to use when searching for available versions. + Default is 'findMissingNoticesNugetOrg' if not specified. + +.EXAMPLE + Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24" + + # This will return "8.0.22" if that's the last harvested version + +.NOTES + Requires the ClearlyDefined module to be imported: + Import-Module ".\clearlyDefined\src\ClearlyDefined" -Force +#> + +function Find-LastHarvestedVersion { + [CmdletBinding()] + param( + [parameter(Mandatory)] + [string]$Name, + + [parameter(Mandatory)] + [string]$CurrentVersion, + + [string]$PackageSourceName = 'findMissingNoticesNugetOrg' + ) + + try { + Write-Verbose "Finding last harvested version for $Name starting from v$CurrentVersion..." + + # Parse the current version + try { + [System.Management.Automation.SemanticVersion]$currentSemVer = $CurrentVersion + } catch { + [Version]$currentSemVer = $CurrentVersion + } + + # First try the ClearlyDefined search API (more efficient) + try { + Write-Verbose "Searching ClearlyDefined API for versions of $Name (sorted by release date)..." + # Get versions sorted by release date descending (newest first) for efficiency + $versions = Get-ClearlyDefinedPackageVersions -PackageName $Name + + if ($versions -and $versions.Count -gt 0) { + # Results are already sorted by release date newest first + # Filter to versions <= current version + foreach ($versionInfo in $versions) { + try { + $versionObj = [System.Management.Automation.SemanticVersion]$versionInfo.Version + if ($versionObj -le $currentSemVer) { + # Check harvest status + if ($versionInfo.Harvested) { + Write-Verbose "Found harvested version: v$($versionInfo.Version)" + return $versionInfo.Version + } else { + Write-Verbose "v$($versionInfo.Version) - Not harvested, continuing..." + } + } + } catch { + # Skip versions that can't be parsed + } + } + + Write-Verbose "No harvested version found in ClearlyDefined results" + return $null + } + } catch { + Write-Verbose "ClearlyDefined search API failed ($_), falling back to NuGet search..." + } + + # Fallback: Get all available versions from NuGet and check individually + Write-Verbose "Falling back to NuGet source search..." + + # Ensure package source exists + if (!(Get-PackageSource -Name $PackageSourceName -ErrorAction SilentlyContinue)) { + Write-Verbose "Registering package source: $PackageSourceName" + $null = Register-PackageSource -Name $PackageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet + } + + # Get all available versions from NuGet + try { + $allVersions = Find-Package -Name $Name -AllowPrereleaseVersions -source $PackageSourceName -AllVersions -ErrorAction SilentlyContinue | ForEach-Object { + try { + $packageVersion = [System.Management.Automation.SemanticVersion]$_.Version + } catch { + $packageVersion = [Version]$_.Version + } + $_ | Add-Member -Name SemVer -MemberType NoteProperty -Value $packageVersion -PassThru + } | Where-Object { $_.SemVer -le $currentSemVer } | Sort-Object -Property SemVer -Descending | ForEach-Object { $_.Version } + } catch { + Write-Warning "Failed to get versions for $Name : $_" + return $null + } + + if (!$allVersions) { + Write-Verbose "No versions found for $Name" + return $null + } + + # Check each version backwards until we find one that's harvested + foreach ($version in $allVersions) { + $pkg = [PSCustomObject]@{ + type = "nuget" + Name = $Name + PackageVersion = $version + } + + try { + $result = $pkg | Get-ClearlyDefinedData + if ($result -and $result.harvested) { + Write-Verbose "Found harvested version: v$version" + return $version + } else { + Write-Verbose "v$version - Not harvested, continuing..." + } + } catch { + Write-Verbose "Error checking v$version : $_" -Verbose + } + } + + Write-Verbose "No harvested version found for $Name" + return $null + } finally { + Save-ClearlyDefinedCache + } +} + +# If this script is called directly (not sourced), run a test +if ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -like '. "*Find-LastHarvestedVersion*') { + # Script was sourced, just load the function +} else { + # Script was called directly + Write-Host "Testing Find-LastHarvestedVersion function..." + Write-Host "Ensure ClearlyDefined module is loaded first:" + Write-Host ' Import-Module ".\clearlydefined\src\ClearlyDefined" -Force' + Write-Host "" + Write-Host "Example usage:" + Write-Host ' Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24"' +} diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4d874402977..4e3d375dc5a 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -2,6 +2,9 @@ # Licensed under the MIT License. # Start the collection (known as harvest) of ClearlyDefined data for a package + +$retryIntervalSec = 90 +$maxRetryCount = 5 function Start-ClearlyDefinedHarvest { [CmdletBinding()] param( @@ -27,7 +30,9 @@ function Start-ClearlyDefinedHarvest { $coordinates = Get-ClearlyDefinedCoordinates @PSBoundParameters $body = @{tool='package';coordinates=$coordinates} | convertto-json Write-Verbose $body -Verbose - (Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $body -ContentType 'application/json' -MaximumRetryCount 5 -RetryIntervalSec 60 -Verbose).Content + Start-job -ScriptBlock { + Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $using:body -ContentType 'application/json' -MaximumRetryCount $using:maxRetryCount -RetryIntervalSec $using:retryIntervalSec + } } } @@ -74,6 +79,207 @@ Function Get-ClearlyDefinedCoordinates { # Cache of ClearlyDefined data $cdCache = @{} +function Test-ClearlyDefinedCachePersistenceAllowed { + [CmdletBinding()] + param() + + if ($env:TF_BUILD -or $env:ADO_BUILD_ID -or $env:BUILD_BUILDID) { + return $false + } + + if ($env:GITHUB_ACTIONS -or $env:GITHUB_RUN_ID) { + return $false + } + + return $true +} + +function Get-ClearlyDefinedCachePath { + [CmdletBinding()] + param() + + $tempPath = [System.IO.Path]::GetTempPath() + return (Join-Path -Path $tempPath -ChildPath 'clearlydefined-cache.json') +} + +function Save-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache persistence for CI environment.' + return + } + + if ($cdCache.Count -eq 0) { + Write-Verbose 'No cache entries to persist.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + $entries = foreach ($key in $cdCache.Keys) { + [PSCustomObject]@{ + coordinates = $key + data = $cdCache[$key] + } + } + + $cachePayload = @{ + savedAtUtc = (Get-Date).ToUniversalTime() + entries = $entries + } | ConvertTo-Json -Depth 20 + + $cachePayload | Set-Content -Path $cachePath -Encoding UTF8 + Write-Verbose "Persisted cache to $cachePath" +} + +function Import-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache import for CI environment.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + if (-not (Test-Path -Path $cachePath)) { + Write-Verbose 'No persisted cache found.' + return + } + + try { + $payload = Get-Content -Path $cachePath -Raw | ConvertFrom-Json + } catch { + Write-Verbose "Failed to read cache file: $cachePath" + return + } + + if (-not $payload.entries) { + Write-Verbose 'Cache file did not contain entries.' + return + } + + foreach ($entry in $payload.entries) { + if (-not $entry.coordinates -or -not $entry.data) { + continue + } + + try { + $entry.data.cachedTime = [datetime]$entry.data.cachedTime + } catch { + continue + } + + $cdCache[$entry.coordinates] = $entry.data + } + + Write-Verbose "Imported $($cdCache.Count) cache entries from $cachePath" +} + +# Search for packages in ClearlyDefined +Function Search-ClearlyDefined { + [CmdletBinding()] + param( + [string]$Type = 'nuget', + [string]$Provider = 'nuget', + [string]$Namespace, + [string]$Name, + [string]$Pattern, + [datetime]$ReleasedAfter, + [datetime]$ReleasedBefore, + [ValidateSet('releaseDate', 'name')] + [string]$Sort, + [switch]$SortDesc + ) + + $queryParams = @() + if ($Type) { $queryParams += "type=$([System.Uri]::EscapeDataString($Type))" } + if ($Provider) { $queryParams += "provider=$([System.Uri]::EscapeDataString($Provider))" } + if ($Namespace) { $queryParams += "namespace=$([System.Uri]::EscapeDataString($Namespace))" } + if ($Name) { $queryParams += "name=$([System.Uri]::EscapeDataString($Name))" } + if ($Pattern) { $queryParams += "pattern=$([System.Uri]::EscapeDataString($Pattern))" } + if ($ReleasedAfter) { $queryParams += "releasedAfter=$($ReleasedAfter.ToString('o'))" } + if ($ReleasedBefore) { $queryParams += "releasedBefore=$($ReleasedBefore.ToString('o'))" } + if ($Sort) { $queryParams += "sort=$([System.Uri]::EscapeDataString($Sort))" } + if ($SortDesc) { $queryParams += "sortDesc=true" } + + $searchUri = "https://api.clearlydefined.io/definitions?" + ($queryParams -join '&') + Write-Verbose "Searching ClearlyDefined: $searchUri" + + try { + $results = Invoke-RestMethod -Uri $searchUri -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec + return $results + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to search ClearlyDefined: $_" + return $null + } +} + +# Get available versions for a NuGet package with harvest status +Function Get-ClearlyDefinedPackageVersions { + [CmdletBinding()] + param( + [parameter(mandatory = $true)] + [string] + $PackageName, + + [validateset('nuget')] + [string] + $PackageType = 'nuget' + ) + + # Search for all definitions of this package, sorted by release date (newest first) + Write-Verbose "Fetching versions of $PackageName from ClearlyDefined..." + + $results = Search-ClearlyDefined -Type $PackageType -Provider nuget -Name $PackageName -Sort releaseDate -SortDesc + + if (!$results) { + Write-Verbose "No results found for $PackageName" + return @() + } + + # Convert results to version info objects + $versions = @() + + # API returns results in different formats depending on the query + $dataArray = $null + if ($results.data) { + $dataArray = $results.data + } elseif ($results -is [array]) { + $dataArray = $results + } elseif ($results.PSObject.Properties.Count -gt 0) { + # If it's an object with properties, try to extract the actual results + foreach ($prop in $results.PSObject.Properties) { + if ($prop.Value -is [object] -and $prop.Value.revision) { + $dataArray += $prop.Value + } + } + } + + if ($dataArray) { + foreach ($item in $dataArray) { + if ($item.revision) { + $harvested = if ($item.licensed -and $item.licensed.declared) { $true } else { $false } + + $versions += [PSCustomObject]@{ + Name = $item.name + Version = $item.revision + Harvested = $harvested + Licensed = $item.licensed.declared + } + } + } + } + + # Results are already sorted by API, no need to re-sort + return $versions +} + # Get the ClearlyDefined data for a package Function Get-ClearlyDefinedData { [CmdletBinding()] @@ -96,8 +302,9 @@ Function Get-ClearlyDefinedData { ) Begin { - $cacheMinutes = 60 - $cacheCutoff = (get-date).AddMinutes(-$cacheMinutes) + # Different TTLs for different cache types + $harvestedCacheMinutes = 60 # Cache positive results for 60 minutes + $nonHarvestedCacheMinutes = 30 # Cache negative results for 30 minutes (less aggressive) $coordinateList = @() } @@ -111,19 +318,55 @@ Function Get-ClearlyDefinedData { foreach($coordinates in $coordinateList) { Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates" -PercentComplete (($completed / $total) * 100) $containsKey = $cdCache.ContainsKey($coordinates) - if ($containsKey -and $cdCache[$coordinates].cachedTime -gt $cacheCutoff) { - Write-Verbose "Returning cached data for $coordinates" - Write-Output $cdCache[$coordinates] - continue + + if ($containsKey) { + $cached = $cdCache[$coordinates] + # Check if cache entry is still valid based on its type + $cacheCutoff = if ($cached.harvestedResult) { + (get-date).AddMinutes(-$harvestedCacheMinutes) + } else { + (get-date).AddMinutes(-$nonHarvestedCacheMinutes) + } + + if ($cached.cachedTime -gt $cacheCutoff) { + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache hit" -PercentComplete (($completed / $total) * 100) + Write-Verbose "Returning cached data for $coordinates (harvested: $($cached.harvestedResult))" + Write-Output $cached + $completed++ + continue + } } - Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount 5 -RetryIntervalSec 60 | ForEach-Object { - [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } - Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru - if ($_.harvested) { - Write-Verbose "Caching data for $coordinates" - $cdCache[$coordinates] = $_ + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache miss" -PercentComplete (($completed / $total) * 100) + + try { + Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec | ForEach-Object { + [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } + # Always cache, with harvestedResult property to distinguish for TTL purposes + Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | + Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru | + Add-Member -NotePropertyName harvestedResult -NotePropertyValue $harvested -PassThru | + ForEach-Object { + Write-Verbose "Caching data for $coordinates (harvested: $($_.harvested))" + $cdCache[$coordinates] = $_ + Write-Output $_ + } + } + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to get ClearlyDefined data for $coordinates : $_" + # Return a minimal object indicating failure/not harvested so the pipeline continues + $failedResult = [PSCustomObject]@{ + coordinates = $coordinates + harvested = $false + harvestedResult = $false + cachedTime = (get-date) + licensed = @{ declared = $null } } + Write-Output $failedResult } $completed++ } @@ -134,4 +377,10 @@ Export-ModuleMember -Function @( 'Start-ClearlyDefinedHarvest' 'Get-ClearlyDefinedData' 'ConvertFrom-ClearlyDefinedCoordinates' + 'Search-ClearlyDefined' + 'Get-ClearlyDefinedPackageVersions' + 'Save-ClearlyDefinedCache' + 'Import-ClearlyDefinedCache' + 'Test-ClearlyDefinedCachePersistenceAllowed' + 'Get-ClearlyDefinedCachePath' ) diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 1346148baee..884eff50664 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -7,12 +7,14 @@ param( [switch] $Fix, - [switch] $IsStable + [switch] $IsStable, + [switch] $ForceHarvestedOnly ) Import-Module dotnet.project.assets Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" +. "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { @@ -20,7 +22,7 @@ if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) } $existingRegistrationTable = @{} -$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\..\tools\cgmanifest.json).ProviderPath +$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\cgmanifest\main\cgmanifest.json).ProviderPath $existingRegistrationsJson = Get-Content $cgManifestPath | ConvertFrom-Json -AsHashtable $existingRegistrationsJson.Registrations | ForEach-Object { $registration = [Registration]$_ @@ -335,8 +337,91 @@ if ($IsStable) { } $count = $newRegistrations.Count +$registrationsToSave = $newRegistrations +$tpnRegistrationsToSave = $null + +# If -ForceHarvestedOnly is specified with -Fix, only include harvested packages +# and revert non-harvested packages to their previous versions +if ($Fix -and $ForceHarvestedOnly) { + Write-Verbose "Checking harvest status and filtering to harvested packages with reversion..." -Verbose + + # Import ClearlyDefined module to check harvest status + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Import cache from previous runs to speed up lookups + Import-ClearlyDefinedCache + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + + # Build a lookup table of harvest status by package name + version + $harvestStatus = @{} + foreach ($item in $fullList) { + $key = "$($item.Name)|$($item.PackageVersion)" + $harvestStatus[$key] = $item.harvested + } + + # Build a lookup table of old versions from existing manifest + $oldVersions = @{} + foreach ($registration in $existingRegistrationsJson.Registrations) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Process each new registration: keep harvested, revert non-harvested + $tpnRegistrationsToSave = @() + $harvestedCount = 0 + $revertedCount = 0 + + foreach ($reg in $newRegistrations) { + $name = $reg.Component.Nuget.Name + $version = $reg.Component.Nuget.Version + $key = "$name|$version" + + if ($harvestStatus.ContainsKey($key) -and $harvestStatus[$key]) { + # Package is harvested, include it + $tpnRegistrationsToSave += $reg + $harvestedCount++ + } else { + # Package not harvested, find last harvested version + $lastHarvestedVersion = Find-LastHarvestedVersion -Name $name -CurrentVersion $version + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + if ($lastHarvestedVersion -ne $version) { + $revertedReg = New-NugetComponent -Name $name -Version $lastHarvestedVersion -DevelopmentDependency:$reg.DevelopmentDependency + $tpnRegistrationsToSave += $revertedReg + $revertedCount++ + Write-Verbose "Reverted $name from v$version to last harvested v$lastHarvestedVersion" -Verbose + } else { + $tpnRegistrationsToSave += $reg + } + } elseif ($oldVersions.ContainsKey($name)) { + $tpnRegistrationsToSave += $oldVersions[$name] + $revertedCount++ + Write-Verbose "Reverted $name to previous version (no harvested version found)" -Verbose + } else { + Write-Warning "$name v$version not harvested and no previous version found. Excluding from manifest." + } + } + } + + Write-Verbose "Completed filtering for TPN: $harvestedCount harvested + $revertedCount reverted = $($tpnRegistrationsToSave.Count) total" -Verbose +} + $newJson = @{ - Registrations = $newRegistrations + Registrations = $registrationsToSave '$schema' = "https://json.schemastore.org/component-detection-manifest.json" } | ConvertTo-Json -depth 99 @@ -345,6 +430,149 @@ if ($Fix -and $registrationChanged) { Set-GWVariable -Name CGMANIFEST_PATH -Value $cgManifestPath } +# If -ForceHarvestedOnly was used, write the TPN manifest with filtered registrations +if ($Fix -and $ForceHarvestedOnly -and $tpnRegistrationsToSave.Count -gt 0) { + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + New-Item -ItemType Directory -Path $tpnManifestDir -Force | Out-Null + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + $tpnManifest = @{ + Registrations = @($tpnRegistrationsToSave) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest created/updated with $($tpnRegistrationsToSave.Count) registrations (filtered for harvested packages)" -Verbose +} + +# Skip legacy TPN update when -ForceHarvestedOnly already produced a filtered manifest +if ($Fix -and $registrationChanged -and -not $ForceHarvestedOnly) { + # Import ClearlyDefined module to check harvest status + Write-Verbose "Checking harvest status for newly added packages..." -Verbose + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + $needHarvest = $fullList | Where-Object { !$_.harvested } + + if ($needHarvest.Count -gt 0) { + Write-Verbose "Found $($needHarvest.Count) packages that need harvesting. Starting harvest..." -Verbose + $needHarvest | Select-Object -ExpandProperty coordinates | ConvertFrom-ClearlyDefinedCoordinates | Start-ClearlyDefinedHarvest + } else { + Write-Verbose "All packages are already harvested." -Verbose + } + + # After manifest update and harvest, update TPN manifest with individual package status + Write-Verbose "Updating TPN manifest with individual package harvest status..." -Verbose + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + # Load current TPN manifest to get previous versions + $currentTpnManifest = @() + if (Test-Path $tpnManifestPath) { + $currentTpnJson = Get-Content $tpnManifestPath | ConvertFrom-Json -AsHashtable + $currentTpnManifest = $currentTpnJson.Registrations + } + + # Build a lookup table of old versions + $oldVersions = @{} + foreach ($registration in $currentTpnManifest) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Note: Do not recheck harvest status here. Harvesting is an async process that takes a significant amount of time. + # Use the harvest data from the initial check. Newly triggered harvests will be captured + # on the next run of this script after harvesting completes. + $finalHarvestData = $fullList + + # Update packages individually based on harvest status + $tpnRegistrations = @() + $harvestedCount = 0 + $restoredCount = 0 + + foreach ($item in $finalHarvestData) { + $matchingNewRegistration = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name -and + $_.Component.Nuget.Version -eq $item.PackageVersion + } + + if ($matchingNewRegistration) { + if ($item.harvested) { + # Use new harvested version + $tpnRegistrations += $matchingNewRegistration + $harvestedCount++ + } else { + # Package not harvested - find the last harvested version from ClearlyDefined API + Write-Verbose "Finding last harvested version for $($item.Name)..." -Verbose + + $lastHarvestedVersion = $null + try { + # Search through all versions of this package to find the last harvested one + # Create a list of versions we know about from all runtimes + $packageVersionsToCheck = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name + } | ForEach-Object { $_.Component.Nuget.Version } | Sort-Object -Unique -Descending + + foreach ($versionToCheck in $packageVersionsToCheck) { + $versionCheckList = [PSCustomObject]@{ + type = "nuget" + Name = $item.Name + PackageVersion = $versionToCheck + } + + $versionStatus = $versionCheckList | Get-ClearlyDefinedData + if ($versionStatus -and $versionStatus.harvested) { + $lastHarvestedVersion = $versionToCheck + break # Found the most recent harvested version + } + } + } catch { + Write-Verbose "Error checking harvested versions for $($item.Name): $_" -Verbose + } + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + $revertedReg = New-NugetComponent -Name $item.Name -Version $lastHarvestedVersion -DevelopmentDependency:$matchingNewRegistration.DevelopmentDependency + $tpnRegistrations += $revertedReg + $restoredCount++ + Write-Verbose "Reverted $($item.Name) from v$($item.PackageVersion) to last harvested v$lastHarvestedVersion" -Verbose + } elseif ($oldVersions.ContainsKey($item.Name)) { + $tpnRegistrations += $oldVersions[$item.Name] + $restoredCount++ + Write-Verbose "Reverted $($item.Name) to previous version in TPN (no harvested version found)" -Verbose + } else { + Write-Warning "$($item.Name) v$($item.PackageVersion) not harvested and no harvested version found. Excluding from TPN manifest." + } + } + } + } + + # Save updated TPN manifest + if ($tpnRegistrations.Count -gt 0) { + $tpnManifest = @{ + Registrations = @($tpnRegistrations) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest updated: $harvestedCount new harvested + $restoredCount reverted to last harvested versions" -Verbose + } +} + if (!$Fix -and $registrationChanged) { $temp = Get-GWTempPath diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 16ae6b21fcc..53d895bc49b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4920,7 +4920,7 @@ function New-GlobalToolNupkgSource } # Set VSTS environment variable for CGManifest file path. - $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools\cgmanifest.json" + $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools/cgmanifest/main/cgmanifest.json" $globalToolCGManifestFilePath = Resolve-Path -Path $globalToolCGManifestPFilePath -ErrorAction SilentlyContinue if (($null -eq $globalToolCGManifestFilePath) -or (! (Test-Path -Path $globalToolCGManifestFilePath))) { From 95e38946b187512721018da5b265df77728adb77 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 26 Feb 2026 17:50:37 -0500 Subject: [PATCH 298/378] Add PMC packages for debian13 and rhel10 (#26912) --- tools/packages.microsoft.com/mapping.json | 42 +++++++++++++++-------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 682c96d9110..334f6dfdd55 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -21,6 +21,13 @@ ], "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, + { + "url": "microsoft-rhel10.0-prod", + "distribution": [ + "stable" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" + }, { "url": "cbl-mariner-2.0-prod-Microsoft-aarch64", "distribution": [ @@ -99,6 +106,27 @@ ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" }, + { + "url": "microsoft-debian-bullseye-prod", + "distribution": [ + "bullseye" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-bookworm-prod", + "distribution": [ + "bookworm" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-trixie-prod", + "distribution": [ + "trixie" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, { "url": "microsoft-ubuntu-bionic-prod", "distribution": [ @@ -133,20 +161,6 @@ "xenial" ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - }, - { - "url": "microsoft-debian-bullseye-prod", - "distribution": [ - "bullseye" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - }, - { - "url": "microsoft-debian-bookworm-prod", - "distribution": [ - "bookworm" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" } ] } From 3544ce5dbbd8539342f6b4b45b8d8623941eb62c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 2 Mar 2026 12:40:22 -0800 Subject: [PATCH 299/378] Update PowerShell Profile DSC resource manifests to allow null for content (#26929) --- dsc/pwsh.profile.dsc.resource.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsc/pwsh.profile.dsc.resource.json b/dsc/pwsh.profile.dsc.resource.json index cd18e94eec6..aa5f5c29eee 100644 --- a/dsc/pwsh.profile.dsc.resource.json +++ b/dsc/pwsh.profile.dsc.resource.json @@ -90,7 +90,7 @@ "content": { "title": "Content", "description": "Defines the content of the profile. If you don't specify this property, the resource doesn't manage the file contents. If you specify this property as an empty string, the resource removes all content from the file. If you specify this property as a non-empty string, the resource sets the file contents to the specified string. The resources retains newlines from this property without any modification.", - "type": "string" + "type": [ "string", "null" ] }, "_exist": { "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json" From eb1915e76b511e1d7d1094c3dc2511065ed0c850 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:42:27 -0500 Subject: [PATCH 300/378] Hardcode Official templates (#26928) --- .../PowerShell-Coordinated_Packages-Official.yml | 11 +++-------- .pipelines/PowerShell-Packages-Official.yml | 11 +++-------- .pipelines/PowerShell-Release-Official-Azure.yml | 9 ++------- .pipelines/PowerShell-Release-Official.yml | 11 +++-------- .pipelines/PowerShell-vPack-Official.yml | 9 ++------- 5 files changed, 13 insertions(+), 38 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index e4de1fe5c21..380c9c5516e 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -29,11 +29,8 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) resources: repositories: @@ -91,8 +88,6 @@ variables: value: true ${{ else }}: value: false - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -100,10 +95,10 @@ variables: - name: ob_sdl_binskim_enabled value: false - name: ps_official_build - value: ${{ parameters.OfficialBuild }} + value: true extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: customTags: 'ES365AIMigrationTooling' featureFlags: diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 18ef7b2d14c..a13ef12378a 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,14 +24,11 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false - name: disableNetworkIsolation type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -67,8 +64,6 @@ variables: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: MSIXSigningProfile - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: disableNetworkIsolation value: ${{ parameters.disableNetworkIsolation }} @@ -89,7 +84,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: cloudvault: enabled: false @@ -294,7 +289,7 @@ extends: jobs: - template: /.pipelines/templates/package-create-msix.yml@self parameters: - OfficialBuild: ${{ parameters.OfficialBuild }} + OfficialBuild: true - stage: upload displayName: 'Upload' diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index f4c41143b5f..81543420460 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -13,11 +13,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -49,8 +46,6 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} resources: repositories: @@ -72,7 +67,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: featureFlags: WindowsHostVersion: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 868d61ebfd0..fa14b9b0acb 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -29,11 +29,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip MSIX Publish type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -65,10 +62,8 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: releaseEnvironment - value: ${{ iif ( parameters.OfficialBuild, 'Production', 'Test' ) }} + value: 'Production' # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -97,7 +92,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: release: category: NonAzure diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 096dfb574a4..fbbf3683db5 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,9 +1,6 @@ trigger: none parameters: # parameters are shown up in ADO UI in a build queue time -- name: OfficialBuild - type: boolean - default: true - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean @@ -33,7 +30,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -58,8 +55,6 @@ variables: value: ${{ parameters.ReleaseTagVar }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual - name: netiso @@ -75,7 +70,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/Microsoft.Official.yml@onebranchTemplates parameters: platform: name: 'windows_undocked' # windows undocked From 2c14e1147014a2be863e7b48d1d155b2778997d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:41:33 -0700 Subject: [PATCH 301/378] Bump github/codeql-action from 4.32.4 to 4.32.6 (#26942) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index fbbb5c31efe..21966cb855c 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 + uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 + uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index c51e85b9448..ee70756298b 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.5 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: sarif_file: results.sarif From 1ee3d7116d20143cbc06cbb71c56390fb432c7d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:41:56 -0700 Subject: [PATCH 302/378] Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#26938) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 6bace648853..79f45e9eb4d 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 + uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 From e170b7210a375b2ed75f3d2e5e41772858b97679 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 14:13:30 -0700 Subject: [PATCH 303/378] Bump actions/upload-artifact from 6 to 7 (#26914) --- .github/workflows/macos-ci.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-packaging-reusable.yml | 2 +- .github/workflows/xunit-tests.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index c7717a26738..5f363e0c265 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -229,7 +229,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ee70756298b..7e868e10dbf 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index bb4873adeb3..55715c42a4c 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -81,7 +81,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 5d225446cb7..a1c86bea70a 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -46,7 +46,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 if: always() with: name: ${{ inputs.test_results_artifact_name }} From 312291762e0bfc2467481aac4f22b48df02107ed Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 18:16:18 -0400 Subject: [PATCH 304/378] Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26893) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Co-authored-by: Dongbo Wang --- DotnetRuntimeMetadata.json | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 2 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest/main/cgmanifest.json | 8 +++--- .../src/ClearlyDefined/ClearlyDefined.psm1 | 27 +++++++++++++------ 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 1ae71bf0737..7c4a2191467 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.101", + "sdkImageVersion": "11.0.100-preview.1.26104.118", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 56fa91bcf6b..b2fae8b21e7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index daa29bd01f3..5f680de58dc 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 90143a9f482..58ea02cf1b5 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,6 +10,6 @@ - +
    diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 5d5f1a9e4f9..7580229ce98 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 6ce2ee32ceb..4cf097c7956 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -30,7 +30,7 @@ all
    - + diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index a0746028a56..4d856723eaa 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -65,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.45.0" + "Version": "1.0.0" } }, "DevelopmentDependency": false @@ -495,7 +496,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.SqlClient", - "Version": "4.9.0" + "Version": "4.9.1" } }, "DevelopmentDependency": false @@ -750,6 +751,5 @@ }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4e3d375dc5a..88fc1f7cabd 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -40,19 +40,30 @@ function ConvertFrom-ClearlyDefinedCoordinates { [CmdletBinding()] param( [parameter(mandatory = $true, ValueFromPipeline = $true)] - [string] + [object] $Coordinates ) Begin {} Process { - $parts = $Coordinates.Split('/') - [PSCustomObject]@{ - type = $parts[0] - provider = $parts[1] - namespace = $parts[2] - name = $parts[3] - revision = $parts[4] + if ($Coordinates -is [string]) { + $parts = $Coordinates.Split('/') + [PSCustomObject]@{ + type = $parts[0] + provider = $parts[1] + namespace = $parts[2] + name = $parts[3] + revision = $parts[4] + } + } else { + # Coordinates is already an object (e.g., from ClearlyDefined API response) + [PSCustomObject]@{ + type = $Coordinates.type + provider = $Coordinates.provider + namespace = $Coordinates.namespace + name = $Coordinates.name + revision = $Coordinates.revision + } } } End {} From a76568c22d0a6015d304c8773e2fd53a56907c53 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:55:00 -0500 Subject: [PATCH 305/378] Add 7.4.14 changelog (#26998) Co-authored-by: Justin Chung Co-authored-by: Travis Plunk Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CHANGELOG/7.4.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md index 89a3f64e37c..f999c20315f 100644 --- a/CHANGELOG/7.4.md +++ b/CHANGELOG/7.4.md @@ -1,5 +1,82 @@ # 7.4 Changelog +## [7.4.14] + +### General Cmdlet Updates and Fixes + +- Fix `PSMethodInvocationConstraints.GetHashCode` method (#26959) + +### Tools + +- Add merge conflict marker detection to `linux-ci` workflow and refactor existing actions to use reusable `get-changed-files` action (#26362) +- Add reusable `get-changed-files` action and refactor existing actions (#26361) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26342) + +### Tests + +- Skip the flaky `Update-Help` test for the `PackageManagement` module (#26871) +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26869) +- Add GitHub Actions annotations for Pester test failures (#26800) +- Mark flaky `Update-Help` web tests as pending to unblock CI (#26805) +- Update the `Update-Help` tests to use `-Force` to remove read-only files (#26786) +- Fix merge conflict checker for empty file lists and filter `*.cs` files (#26387) +- Add markdown link verification for PRs (#26340) + +### Build and Packaging Improvements + +
    + + + +

    Update .NET SDK to 8.0.419

    + +
    + +
      +
    • Update MaxVisitCount and MaxHashtableKeyCount if visitor safe value context indicates SkipLimitCheck is true (Internal 38882)
    • +
    • Hardcode Official templates (#26962)
    • +
    • Split TPN manifest and Component Governance manifest (#26961)
    • +
    • Correct the package name for .deb and .rpm packages (#26960)
    • +
    • Bring over all changes for MSIX packaging template (#26933)
    • +
    • .NET Resolution and Store Publishing Updates (#26930)
    • +
    • Update Application Insights package version to 2.23.0 (#26883)
    • +
    • Update metadata.json to update the Latest attribute with a better name (#26872)
    • +
    • Update Get-ChangeLog to handle backport PRs correctly (#26870)
    • +
    • Remove unused runCodesignValidationInjection variable from pipeline templates (#26868)
    • +
    • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26864)
    • +
    • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26863)
    • +
    • Fix macOS preview package identifier detection to use version string (#26774)
    • +
    • Update the macOS package name for preview releases to match the previous pattern (#26435)
    • +
    • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26434)
    • +
    • Fix template path for rebuild branch check in package.yml (#26433)
    • +
    • Add rebuild branch support with conditional MSIX signing (#26418)
    • +
    • Move package validation to package pipeline (#26417)
    • +
    • Backport Store publishing improvements (#26401)
    • +
    • Fix path to metadata.json in channel selection script (#26399)
    • +
    • Optimize/split Windows package signing (#26413)
    • +
    • Improve ADO package build and validation across platforms (#26405)
    • +
    • Separate Store Automation Service Endpoints, Resolve AppID (#26396)
    • +
    • Fix the task name to not use the pre-release task (#26395)
    • +
    • Remove usage of fpm for DEB package generation (#26382)
    • +
    • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26344)
    • +
    • Replace fpm with native rpmbuild for RPM package generation (#26337)
    • +
    • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26363)
    • +
    • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26336)
    • +
    • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26335)
    • +
    • Add network isolation policy parameter to vPack pipeline (#26339)
    • +
    • GitHub Workflow cleanup (#26334)
    • +
    • Add build to vPack Pipeline (#25980)
    • +
    • Update vPack name (#26222)
    • +
    + +
    + +### Documentation and Help Content + +- Update Third Party Notices (#26892) + +[7.4.14]: https://github.com/PowerShell/PowerShell/compare/v7.4.13...v7.4.14 + ## [7.4.13] ### Build and Packaging Improvements From 7498139bae4a8ef40a6df9c845a4e9867dbcb22d Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 11 Mar 2026 16:39:10 -0400 Subject: [PATCH 306/378] Update `Microsoft.PowerShell.PSResourceGet` version to 1.2.0 (#27003) --- src/Modules/PSGalleryModules.csproj | 2 +- tools/packaging/boms/windows.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 9136df5c7b3..3903b164b09 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 8248b3d03aa..8d900902bc2 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -1216,6 +1216,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\.signature.p7s", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", "FileType": "NonProduct", From fffe6094cf6d19593e77c803259c6d8a6ce0f18a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 12 Mar 2026 11:37:25 -0700 Subject: [PATCH 307/378] Update changelog for release v7.5.5 (#27014) --- CHANGELOG/7.5.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index 80b3ee0a8aa..d908532ff82 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,90 @@ # 7.5 Changelog +## [7.5.5] + +### Engine Updates and Fixes + +- Fix up `SSHConnectionInfo` ssh PATH checks (#26165) (Thanks @jborean93!) + +### General Cmdlet Updates and Fixes + +- Close pipe client handles after creating the child ssh process (#26822) +- Fix the progress preference variable in script cmdlets (#26791) (Thanks @cmkb3!) + +### Tools + +- Add merge conflict marker detection to `linux-ci` workflow and refactor existing actions to use reusable `get-changed-files` action (#26812) +- Add reusable `get-changed-files` action and refactor existing actions (#26811) +- Create GitHub Copilot setup workflow (#26807) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26799) + +### Tests + +- Mark flaky `Update-Help` web tests as pending to unblock CI (#26837) +- Add GitHub Actions annotations for Pester test failures (#26836) +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26823) +- Fix merge conflict checker for empty file lists and filter `*.cs` files (#26813) +- Update the `Update-Help` tests to use `-Force` to remove read-only files (#26788) +- Add markdown link verification for PRs (#26407) + +### Build and Packaging Improvements + +
    + + +

    Update to .NET SDK 9.0.312

    +

    We thank the following contributors!

    +

    @kasperk81, @RichardSlater

    + +
    + +
      +
    • Revert change to module name ThreadJob (#26997)
    • +
    • Update branch for release (#26990)
    • +
    • Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26987)
    • +
    • Update CGManifests (#26981)
    • +
    • Hardcode Official templates (#26968)
    • +
    • Split TPN manifest and Component Governance manifest (#26967)
    • +
    • Fix a preview detection test for the packaging script (#26966)
    • +
    • Correct the package name for .deb and .rpm packages (#26964)
    • +
    • Bring Release Changes from v7.6.0-preview.6 (#26963)
    • +
    • Merge the v7.6.0-preview.5 release branch back to master (#26958)
    • +
    • Fix macOS preview package identifier detection to use version string (#26835)
    • +
    • Update metadata.json to update the Latest attribute with a better name (#26826)
    • +
    • Remove unused runCodesignValidationInjection variable from pipeline templates (#26825)
    • +
    • Update Get-ChangeLog to handle backport PRs correctly (#26824)
    • +
    • Mirror .NET/runtime ICU version range in PowerShell (#26821) (Thanks @kasperk81!)
    • +
    • Update the macos package name for preview releases to match the previous pattern (#26820)
    • +
    • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26819)
    • +
    • Fix template path for rebuild branch check in package.yml (#26818)
    • +
    • Add rebuild branch support with conditional MSIX signing (#26817)
    • +
    • Move package validation to package pipeline (#26816)
    • +
    • Optimize/split windows package signing (#26815)
    • +
    • Improve ADO package build and validation across platforms (#26814)
    • +
    • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26810)
    • +
    • Remove usage of fpm for DEB package generation (#26809)
    • +
    • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26801)
    • +
    • Fix build to only enable ready-to-run for the Release configuration (#26798)
    • +
    • Fix R2R for fxdependent packaging (#26797)
    • +
    • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26794)
    • +
    • Replace fpm with native rpmbuild for RPM package generation (#26793)
    • +
    • Add libicu76 dependency to support Debian 13 (#26792) (Thanks @RichardSlater!)
    • +
    • Specify .NET search by build type (#26408)
    • +
    • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26773)
    • +
    • Fix path to metadata.json in channel selection script (#26400)
    • +
    • Separate store automation service endpoints and resolve AppID (#26266)
    • +
    • Update a few packages to use the right version corresponding to .NET 9 (#26671)
    • +
    • Add network isolation policy parameter to vPack pipeline (#26393)
    • +
    • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26391)
    • +
    • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26390)
    • +
    • GitHub Workflow cleanup (#26389)
    • +
    • Update vPack name (#26221)
    • +
    + +
    + +[7.5.5]: https://github.com/PowerShell/PowerShell/compare/v7.5.4...v7.5.5 + ## [7.5.4] ### Build and Packaging Improvements From 1f8bbe1e5332bb8fe1b39c81c366ddadbf9dd1a2 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 12 Mar 2026 12:34:12 -0700 Subject: [PATCH 308/378] Fix the container image for vPack, MSIX vPack and Package pipelines (#27015) --- .pipelines/MSIXBundle-vPack-Official.yml | 5 ++++- .pipelines/PowerShell-Coordinated_Packages-Official.yml | 3 ++- .pipelines/PowerShell-vPack-Official.yml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 997b7c458be..876da9c2aff 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -22,7 +22,7 @@ variables: BuildSolution: $(Build.SourcesDirectory)\dirs.proj ReleaseTagVar: ${{ parameters.ReleaseTagVar }} BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 @@ -46,6 +46,9 @@ resources: extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 platform: name: 'windows_undocked' # windows undocked diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 380c9c5516e..12460e2861c 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -68,7 +68,7 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] - name: ReleaseTagVar @@ -105,6 +105,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index fbbf3683db5..c49560bf2b8 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -42,7 +42,7 @@ variables: - name: BuildConfiguration value: Release - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: Codeql.Enabled value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - name: DOTNET_CLI_TELEMETRY_OPTOUT From 8c9c9e11872c8d98c2e7d7a1ed991fc7e1d07354 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 16 Mar 2026 12:40:26 -0700 Subject: [PATCH 309/378] Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27039) --- .pipelines/templates/mac-package-build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index def866173ac..6585773c743 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -102,6 +102,10 @@ jobs: Restore-PSOptions -PSOptionsPath "$psoptionsPath" Get-PSOptions | Write-Verbose -Verbose + if (-not (Test-Path "$repoRoot/tools/metadata.json")) { + throw "metadata.json not found in $repoRoot/tools" + } + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json Write-Verbose -Verbose "metadata:" @@ -120,14 +124,19 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" + Write-Verbose -Message "LTS Release: $LTS" -Verbose } Start-PSBootstrap -Scenario Package $macosRuntime = "osx-$buildArch" - Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + + if ($LTS) { + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $pkgNameFilter = "powershell-*$macosRuntime.pkg" Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File From e053a339a1109ed16d36d77b9a47ab35ad4d017d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Mar 2026 14:47:59 -0700 Subject: [PATCH 310/378] Create Linux LTS deb/rpm packages for LTS releases (#27049) --- .pipelines/templates/linux-package-build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index ea49b9fea5d..bb7ed723f42 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -155,10 +155,6 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" - if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" - } - if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } @@ -168,6 +164,11 @@ jobs: Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + if ($LTS) { + Write-Verbose -Message "LTS Release: $LTS" -Verbose + Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $vstsCommandString = "vso[task.setvariable variable=PackageFilter]$pkgFilter" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" From 28a2e35f061ab45466b7c607127c85d2c1c4381c Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:46:37 +0000 Subject: [PATCH 311/378] Fix `IDisposable` implementation in sealed classes (#26215) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- .../commands/management/Hotfix.cs | 19 +--- .../commands/management/Process.cs | 11 +- .../commands/utility/Tee-Object.cs | 16 +-- .../commands/utility/XmlCommands.cs | 3 +- .../engine/Modules/GetModuleCommand.cs | 18 +--- .../engine/Modules/ImportModuleCommand.cs | 16 +-- .../engine/MshCommandRuntime.cs | 11 +- .../engine/hostifaces/PowerShell.cs | 100 +++++++----------- .../hostifaces/PowerShellProcessInstance.cs | 37 +++---- .../engine/hostifaces/RunspacePool.cs | 2 +- .../utils/CryptoUtils.cs | 15 +-- 11 files changed, 81 insertions(+), 167 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs index 1aa94509469..d0f15346396 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Hotfix.cs @@ -206,26 +206,11 @@ private bool FilterMatch(ManagementObject obj) #region "IDisposable Members" /// - /// Dispose Method. + /// Release all resources. /// public void Dispose() { - this.Dispose(true); - // Use SuppressFinalize in case a subclass - // of this type implements a finalizer. - GC.SuppressFinalize(this); - } - - /// - /// Dispose Method. - /// - /// - public void Dispose(bool disposing) - { - if (disposing) - { - _searchProcess?.Dispose(); - } + _searchProcess?.Dispose(); } #endregion "IDisposable Members" diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index c959cfcb33e..91efda12263 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -2188,15 +2188,12 @@ protected override void BeginProcessing() #region IDisposable Overrides /// - /// Dispose WaitHandle used to honor -Wait parameter. + /// Release all resources. /// + /// + /// Dispose WaitHandle used to honor -Wait parameter. + /// public void Dispose() - { - Dispose(true); - System.GC.SuppressFinalize(this); - } - - private void Dispose(bool isDisposing) { _cancellationTokenSource.Dispose(); } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs index 27ea15406f7..4a0f4831299 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tee-Object.cs @@ -140,12 +140,15 @@ protected override void EndProcessing() _commandWrapper.ShutDown(); } - private void Dispose(bool isDisposing) + /// + /// Release all resources. + /// + public void Dispose() { if (!_alreadyDisposed) { _alreadyDisposed = true; - if (isDisposing && _commandWrapper != null) + if (_commandWrapper != null) { _commandWrapper.Dispose(); _commandWrapper = null; @@ -153,15 +156,6 @@ private void Dispose(bool isDisposing) } } - /// - /// Dispose method in IDisposable. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - #region private private CommandWrapper _commandWrapper; private bool _alreadyDisposed; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs index 6473d6d4fae..cc3b1f2b251 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs @@ -331,13 +331,12 @@ public string[] LiteralPath private bool _disposed = false; /// - /// Public dispose method. + /// Release all resources. /// public void Dispose() { if (!_disposed) { - GC.SuppressFinalize(this); if (_helper != null) { _helper.Dispose(); diff --git a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs index 39c3e9c905e..caf7527d73e 100644 --- a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs @@ -297,29 +297,17 @@ protected override void StopProcessing() #region IDisposable Members /// - /// Releases resources associated with this object. + /// Release all resources. /// public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases resources associated with this object. - /// - private void Dispose(bool disposing) { if (_disposed) { return; } - if (disposing) - { - _cancellationTokenSource.Dispose(); - } - + _cancellationTokenSource.Dispose(); + _disposed = true; } diff --git a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs index 05357bbb5e5..532079d1a77 100644 --- a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs @@ -1780,28 +1780,16 @@ protected override void StopProcessing() #region IDisposable Members /// - /// Releases resources associated with this object. + /// Release all resources. /// public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases resources associated with this object. - /// - private void Dispose(bool disposing) { if (_disposed) { return; } - if (disposing) - { - _cancellationTokenSource.Dispose(); - } + _cancellationTokenSource.Dispose(); _disposed = true; } diff --git a/src/System.Management.Automation/engine/MshCommandRuntime.cs b/src/System.Management.Automation/engine/MshCommandRuntime.cs index d5f821bc930..e674cb1c5eb 100644 --- a/src/System.Management.Automation/engine/MshCommandRuntime.cs +++ b/src/System.Management.Automation/engine/MshCommandRuntime.cs @@ -2372,19 +2372,18 @@ internal AllowWrite(InternalCommand permittedToWrite, bool permittedToWriteToPip _pp._permittedToWriteToPipeline = permittedToWriteToPipeline; _pp._permittedToWriteThread = Thread.CurrentThread; } + /// - /// End the scope where WriteObject/WriteError is permitted. + /// Release all resources. /// - /// + /// + /// End the scope where WriteObject/WriteError is permitted. + /// public void Dispose() { _pp._permittedToWrite = _wasPermittedToWrite; _pp._permittedToWriteToPipeline = _wasPermittedToWriteToPipeline; _pp._permittedToWriteThread = _wasPermittedToWriteThread; - GC.SuppressFinalize(this); } // There is no finalizer, by design. This class relies on always diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs index c86b86b4ffb..3af978ea165 100644 --- a/src/System.Management.Automation/engine/hostifaces/PowerShell.cs +++ b/src/System.Management.Automation/engine/hostifaces/PowerShell.cs @@ -3880,15 +3880,50 @@ private void PipelineStateChanged(object source, PipelineStateEventArgs stateEve #region IDisposable Overrides /// - /// Dispose all managed resources. This will suppress finalizer on the object from getting called by - /// calling System.GC.SuppressFinalize(this). + /// Release all resources. /// public void Dispose() { - Dispose(true); - // To prevent derived types with finalizers from having to re-implement System.IDisposable to call it, - // unsealed types without finalizers should still call SuppressFinalize. - System.GC.SuppressFinalize(this); + lock (_syncObject) + { + // if already disposed return + if (_isDisposed) + { + return; + } + } + + // Stop the currently running command outside of the lock + if (InvocationStateInfo.State == PSInvocationState.Running || + InvocationStateInfo.State == PSInvocationState.Stopping) + { + Stop(); + } + + lock (_syncObject) + { + _isDisposed = true; + } + + if (OutputBuffer != null && OutputBufferOwner) + { + OutputBuffer.Dispose(); + } + + if (_errorBuffer != null && ErrorBufferOwner) + { + _errorBuffer.Dispose(); + } + + if (IsRunspaceOwner) + { + _runspace.Dispose(); + } + + RemotePowerShell?.Dispose(); + + _invokeAsyncResult = null; + _stopAsyncResult = null; } #endregion @@ -4121,59 +4156,6 @@ private void AssertNotDisposed() } } - /// - /// Release all the resources. - /// - /// - /// if true, release all the managed objects. - /// - private void Dispose(bool disposing) - { - if (disposing) - { - lock (_syncObject) - { - // if already disposed return - if (_isDisposed) - { - return; - } - } - - // Stop the currently running command outside of the lock - if (InvocationStateInfo.State == PSInvocationState.Running || - InvocationStateInfo.State == PSInvocationState.Stopping) - { - Stop(); - } - - lock (_syncObject) - { - _isDisposed = true; - } - - if (OutputBuffer != null && OutputBufferOwner) - { - OutputBuffer.Dispose(); - } - - if (_errorBuffer != null && ErrorBufferOwner) - { - _errorBuffer.Dispose(); - } - - if (IsRunspaceOwner) - { - _runspace.Dispose(); - } - - RemotePowerShell?.Dispose(); - - _invokeAsyncResult = null; - _stopAsyncResult = null; - } - } - /// /// Clear the internal elements. /// diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs b/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs index 5ab95041877..f86d2c00a54 100644 --- a/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs +++ b/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs @@ -179,15 +179,9 @@ public bool HasExited #region Dispose /// - /// Implementing the interface. + /// Release all resources. /// public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) { if (_isDisposed) { @@ -203,23 +197,20 @@ private void Dispose(bool disposing) _isDisposed = true; } - - if (disposing) + + try + { + if (Process != null && !Process.HasExited) + Process.Kill(); + } + catch (InvalidOperationException) + { + } + catch (Win32Exception) + { + } + catch (NotSupportedException) { - try - { - if (Process != null && !Process.HasExited) - Process.Kill(); - } - catch (InvalidOperationException) - { - } - catch (Win32Exception) - { - } - catch (NotSupportedException) - { - } } } diff --git a/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs b/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs index 7dc9e8d31de..e7cfb888a88 100644 --- a/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs +++ b/src/System.Management.Automation/engine/hostifaces/RunspacePool.cs @@ -1199,7 +1199,7 @@ public void EndClose(IAsyncResult asyncResult) } /// - /// Dispose the current runspacepool. + /// Release all resources. /// public void Dispose() { diff --git a/src/System.Management.Automation/utils/CryptoUtils.cs b/src/System.Management.Automation/utils/CryptoUtils.cs index dfda3032728..c82c96ecdc3 100644 --- a/src/System.Management.Automation/utils/CryptoUtils.cs +++ b/src/System.Management.Automation/utils/CryptoUtils.cs @@ -576,21 +576,12 @@ internal static PSRSACryptoServiceProvider GetRSACryptoServiceProviderForServer( #region IDisposable /// - /// Dispose resources. + /// Release all resources. /// public void Dispose() { - Dispose(true); - System.GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (disposing) - { - _rsa?.Dispose(); - _aes?.Dispose(); - } + _rsa?.Dispose(); + _aes?.Dispose(); } #endregion IDisposable From 73186fb1382b7c5207a8c59d1269dc35adc7b584 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 18 Mar 2026 16:42:23 -0400 Subject: [PATCH 312/378] Fix PMC repo URL for RHEL10 (#27059) --- .pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 | 2 +- tools/packages.microsoft.com/mapping.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index 23f91c1bff2..6797ff94575 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -64,7 +64,7 @@ function Get-MappedRepositoryIds { $repoIds.AddRange(([string[]]$repos.id)) } else { - Write-Failure "Could not find repo for $urlGlob" + throw "Could not find repo for $urlGlob" } if ($repoIds.Count -gt 0) { diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 334f6dfdd55..154a9582872 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -22,7 +22,7 @@ "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, { - "url": "microsoft-rhel10.0-prod", + "url": "microsoft-rhel10-prod", "distribution": [ "stable" ], From 569eb7246c92d35953c8448352e7ae87c0dc3f56 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:28:37 -0400 Subject: [PATCH 313/378] Move `_GetDependencies` MSBuild target from dynamic generation in `build.psm1` into `Microsoft.PowerShell.SDK.csproj` (#27052) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- build.psm1 | 25 ++----------------- .../Microsoft.PowerShell.SDK.csproj | 24 +++++++++++++++++- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/build.psm1 b/build.psm1 index ee50c9cde51..ec91f2cf314 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2681,38 +2681,17 @@ function Start-TypeGen # Add .NET CLI tools to PATH Find-Dotnet - # This custom target depends on 'ResolveAssemblyReferencesDesignTime', whose definition can be found in the sdk folder. - # To find the available properties of '_ReferencesFromRAR' when switching to a new dotnet sdk, follow the steps below: - # 1. create a dummy project using the new dotnet sdk. - # 2. build the dummy project with this command: - # dotnet msbuild .\dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag - # 3. search '_ReferencesFromRAR' in the produced 'msbuild.log' file. You will find the properties there. - $GetDependenciesTargetPath = "$PSScriptRoot/src/Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets" - $GetDependenciesTargetValue = @' - - - - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> - - - - -'@ - New-Item -ItemType Directory -Path (Split-Path -Path $GetDependenciesTargetPath -Parent) -Force > $null - Set-Content -Path $GetDependenciesTargetPath -Value $GetDependenciesTargetValue -Force -Encoding Ascii - Push-Location "$PSScriptRoot/src/Microsoft.PowerShell.SDK" try { $ps_inc_file = "$PSScriptRoot/src/TypeCatalogGen/$IncFileName" - dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo + Start-NativeExecution { dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo } } finally { Pop-Location } Push-Location "$PSScriptRoot/src/TypeCatalogGen" try { - dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName + Start-NativeExecution { dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName } } finally { Pop-Location } diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 5f680de58dc..979764ff79f 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -31,4 +31,26 @@
    - + + + + + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + + + + + \ No newline at end of file From a15947e77af7f0a1c771abf10a26949d79669505 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 18 Mar 2026 15:12:50 -0700 Subject: [PATCH 314/378] Update `metadata.json` for the v7.6.0 release (#27054) --- tools/metadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index 1bf3e96e39c..57433aec4c6 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,9 +1,9 @@ { - "StableReleaseTag": "v7.5.4", + "StableReleaseTag": "v7.6.0", "PreviewReleaseTag": "v7.6.0-rc.1", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.5.4", - "LTSReleaseTag" : ["v7.4.13"], + "ReleaseTag": "v7.6.0", + "LTSReleaseTag": ["v7.4.14", "v7.6.0"], "NextReleaseTag": "v7.7.0-preview.1", "LTSRelease": { "PublishToChannels": false, "Package": false }, "StableRelease": { "PublishToChannels": false, "Package": false } From 78e437c6f30cceb2e6f9e3e66548afcce234005b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 18 Mar 2026 15:32:15 -0700 Subject: [PATCH 315/378] Fix the `PSNativeCommandArgumentPassing` test (#27057) --- .../NativeExecution/NativeCommandArguments.Tests.ps1 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 index 8e09df9b699..ead0fb39efb 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 @@ -5,12 +5,7 @@ param() Describe "Behavior is specific for each platform" -tags "CI" { It "PSNativeCommandArgumentPassing is set to 'Windows' on Windows systems" -skip:(-not $IsWindows) { - if ([Version]::TryParse($PSVersiontable.PSVersion.ToString(), [ref]$null)) { - $PSNativeCommandArgumentPassing | Should -BeExactly "Legacy" - } - else { - $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" - } + $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" } It "PSNativeCommandArgumentPassing is set to 'Standard' on non-Windows systems" -skip:($IsWindows) { $PSNativeCommandArgumentPassing | Should -Be "Standard" From 9c6a012e7dbf7956ab37e2bf1a239251d376a251 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:57:10 -0500 Subject: [PATCH 316/378] Update build to create two msix's and msixbundles for LTS and Stable (#27056) --- .pipelines/templates/package-create-msix.yml | 78 +++++++++++++++---- .../templates/packaging/windows/package.yml | 8 ++ tools/packaging/packaging.psm1 | 19 ++--- 3 files changed, 81 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 255915ab02c..e461bb6efd9 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -85,17 +85,44 @@ jobs: $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose } - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - $makeappx = '$(MakeAppxPath)' $outputDir = "$sourceDir\output" New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - Get-ChildItem -Path $sourceDir -Recurse + # Separate LTS and Stable/Preview MSIX files by filename convention + $ltsMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -match '-LTS-' }) + $stableMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -notmatch '-LTS-' }) + + Write-Verbose -Verbose "Stable/Preview MSIX files: $($stableMsix.Name -join ', ')" + Write-Verbose -Verbose "LTS MSIX files: $($ltsMsix.Name -join ', ')" + + # Create Stable/Preview bundle + if ($stableMsix.Count -gt 0) { + $stableDir = "$sourceDir\stable" + New-Item $stableDir -Type Directory -Force > $null + $stableMsix | Copy-Item -Destination $stableDir -Force + $file = $stableMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $stableBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating Stable/Preview bundle: $stableBundleName" + & $makeappx bundle /d $stableDir /p "$outputDir\$stableBundleName" + } + + # Create LTS bundle + if ($ltsMsix.Count -gt 0) { + $ltsDir = "$sourceDir\lts" + New-Item $ltsDir -Type Directory -Force > $null + $ltsMsix | Copy-Item -Destination $ltsDir -Force + $file = $ltsMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $ltsBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating LTS bundle: $ltsBundleName" + & $makeappx bundle /d $ltsDir /p "$outputDir\$ltsBundleName" + } + + Write-Verbose -Verbose "Created bundles:" + Get-ChildItem -Path $outputDir -Recurse + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" @@ -112,16 +139,18 @@ jobs: search_root: '$(BundleDir)' - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" + $signedBundles = @(Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File) + Write-Verbose -Verbose "Signed bundles: $($signedBundles.Name -join ', ')" if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + foreach ($bundle in $signedBundles) { + Copy-Item -Path $bundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + } - Write-Verbose -Verbose "Uploaded Bundle:" + Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts @@ -225,6 +254,29 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + # These variables are used in the next tasks to determine which ServiceEndpoint to use $ltsValue = $IsLTS.ToString().ToLower() $stableValue = $IsStable.ToString().ToLower() @@ -256,7 +308,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' @@ -268,7 +320,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 1f03d65ab21..92926e6aa59 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -136,12 +136,14 @@ jobs: # Don't build LTS packages for rebuild branches $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + $Stable = [bool]$metadata.StableRelease.Package if ($isRebuildBranch) { Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose } Write-Verbose -Verbose "LTS: $LTS" + Write-Verbose -Verbose "Stable: $Stable" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" @@ -175,6 +177,12 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + # When both LTS and Stable are requested, also build the Stable MSIX + if ($packageTypes -contains 'msix' -and $LTS -and $Stable) { + Write-Verbose -Verbose "Both LTS and Stable packages requested. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + } + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 53d895bc49b..baab911f60d 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4274,18 +4274,8 @@ function New-MSIXPackage $makepri = Get-Item (Join-Path $makeappx.Directory "makepri.exe") -ErrorAction Stop + $displayName = $ProductName $ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion - $productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion - $packageName = $productSemanticVersionWithName - if ($Private) { - $ProductNameSuffix = 'Private' - } - - if ($ProductNameSuffix) { - $packageName += "-$ProductNameSuffix" - } - - $displayName = $productName if ($Private) { $ProductName = 'PowerShell-Private' @@ -4301,6 +4291,13 @@ function New-MSIXPackage Write-Verbose -Verbose "ProductName: $productName" Write-Verbose -Verbose "DisplayName: $displayName" + $packageName = $ProductName + '-' + $ProductSemanticVersion + + # Appends Architecture to the package name + if ($ProductNameSuffix) { + $packageName += "-$ProductNameSuffix" + } + $ProductVersion = Get-WindowsVersion -PackageName $packageName # Any app that is submitted to the Store must have a PhoneIdentity in its appxmanifest. From a51e7be624ab6dbde17f1d35ef470b69b8ebc2db Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 19 Mar 2026 14:04:53 -0700 Subject: [PATCH 317/378] Check in `7.6.md` after v7.6.0 release (#27063) --- CHANGELOG/7.6.md | 807 +++++++++++++++++++++++++++++++++++++++++++ CHANGELOG/preview.md | 759 ---------------------------------------- 2 files changed, 807 insertions(+), 759 deletions(-) create mode 100644 CHANGELOG/7.6.md diff --git a/CHANGELOG/7.6.md b/CHANGELOG/7.6.md new file mode 100644 index 00000000000..47a8d33182f --- /dev/null +++ b/CHANGELOG/7.6.md @@ -0,0 +1,807 @@ +# 7.6 Changelog + +## [7.6.0] + +### General Cmdlet Updates and Fixes + +- Update PowerShell Profile DSC resource manifests to allow `null` for content (#26973) + +### Tests + +- Add GitHub Actions annotations for Pester test failures (#26969) +- Fix `Import-Module.Tests.ps1` to handle Arm32 platform (#26888) + +### Build and Packaging Improvements + +
    + + + +

    Update to .NET SDK 10.0.201

    + +
    + +
      +
    • Update v7.6 release branch to use .NET SDK 10.0.201 (#27041)
    • +
    • Create LTS package and non-LTS package for macOS for LTS releases (#27040)
    • +
    • Fix the container image for package pipelines (#27020)
    • +
    • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0 (#27007)
    • +
    • Update LTS and Stable release settings in metadata (#27006)
    • +
    • Update branch for release (#26989)
    • +
    • Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26986)
    • +
    • Update NuGet package versions in cgmanifest.json to actually match the branch (#26982)
    • +
    • Bump actions/upload-artifact from 6 to 7 (#26979)
    • +
    • Split TPN manifest and Component Governance manifest (#26978)
    • +
    • Bump github/codeql-action from 4.32.4 to 4.32.6 (#26975)
    • +
    • Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#26974)
    • +
    • Hardcode Official templates (#26972)
    • +
    • Fix a preview detection test for the packaging script (#26971)
    • +
    • Add PMC packages for debian13 and rhel10 (#26917)
    • +
    • Add version in description and pass store task on failure (#26889)
    • +
    • Exclude .exe packages from publishing to GitHub (#26887)
    • +
    • Correct the package name for .deb and .rpm packages (#26884)
    • +
    + +
    + +[7.6.0]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-rc.1...v7.6.0 + +## [7.6.0-rc.1] - 2026-02-19 + +### Tests + +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26705) + +### Build and Packaging Improvements + +
    + + + +

    Expand to see details.

    + +
    + +
      +
    • Update branch for release (#26779)
    • +
    • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26767)
    • +
    • Update Microsoft.PowerShell.Native package version (#26748)
    • +
    • Move PowerShell build to depend on .NET SDK 10.0.102 (#26717)
    • +
    • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26715)
    • +
    • Fix macOS preview package identifier detection to use version string (#26709)
    • +
    • Update metadata.json to update the Latest attribute with a better name (#26708)
    • +
    • Remove unused runCodesignValidationInjection variable from pipeline templates (#26707)
    • +
    • Update Get-ChangeLog to handle backport PRs correctly (#26706)
    • +
    • Bring release changes from the v7.6.0-preview.6 release (#26626)
    • +
    • Fix the DSC test by skipping AfterAll cleanup if the initial setup in BeforeAll failed (#26622)
    • +
    + +
    + +[7.6.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.6...v7.6.0-rc.1 + +## [7.6.0-preview.6] - 2025-12-11 + +### Engine Updates and Fixes + +- Properly Expand Aliases to their actual ResolvedCommand (#26571) (Thanks @kilasuit!) + +### General Cmdlet Updates and Fixes + +- Update `Microsoft.PowerShell.PSResourceGet` to `v1.2.0-preview5` (#26590) +- Make the experimental feature `PSFeedbackProvider` stable (#26502) +- Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26487) +- Add Delimiter parameter to `Get-Clipboard` (#26572) (Thanks @MartinGC94!) +- Close pipe client handles after creating the child ssh process (#26564) +- Make some experimental features stable (#26490) +- DSC v3 resource for PowerShell Profile (#26447) + +### Tools + +- Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26530) +- Add reusable get-changed-files action and refactor existing actions (#26529) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26494) + +### Tests + +- Fix merge conflict checker for empty file lists and filter *.cs files (#26556) +- Add markdown link verification for PRs (#26445) + +### Build and Packaging Improvements + +
    + + + +

    Expand to see details.

    + +
    + +
      +
    • Fix template path for rebuild branch check in package.yml (#26560)
    • +
    • Update the macos package name for preview releases to match the previous pattern (#26576)
    • +
    • Add rebuild branch support with conditional MSIX signing (#26573)
    • +
    • Update the WCF packages to the latest version that is compatible with v4.10.3 (#26503)
    • +
    • Improve ADO package build and validation across platforms (#26532)
    • +
    • Mirror .NET/runtime ICU version range in PowerShell (#26563) (Thanks @kasperk81!)
    • +
    • Update the macos package name for preview releases to match the previous pattern (#26562)
    • +
    • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26561)
    • +
    • Move package validation to package pipeline (#26558)
    • +
    • Optimize/split windows package signing (#26557)
    • +
    • Remove usage of fpm for DEB package generation (#26504)
    • +
    • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26524)
    • +
    • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501)
    • +
    • Replace fpm with native rpmbuild for RPM package generation (#26441)
    • +
    • Fix GitHub API rate limit errors in test actions (#26492)
    • +
    • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26493)
    • +
    • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26488)
    • +
    • Fix build to only enable ready-to-run for the Release configuration (#26481)
    • +
    • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26468)
    • +
    • Update outdated package references (#26471)
    • +
    • GitHub Workflow cleanup (#26439)
    • +
    • Update PSResourceGet package version to preview4 (#26438)
    • +
    • Update PSReadLine to v2.4.5 (#26446)
    • +
    • Add network isolation policy parameter to vPack pipeline (#26444)
    • +
    • Fix a couple more lint errors
    • +
    • Fix lint errors in preview.md
    • +
    • Make MSIX publish stage dependent on SetReleaseTagandContainerName stage
    • +
    + +
    + +[7.6.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.5...v7.6.0-preview.6 + +## [7.6.0-preview.5] - 2025-09-30 + +### Engine Updates and Fixes + +- Allow opt-out of the named-pipe listener using the environment variable `POWERSHELL_DIAGNOSTICS_OPTOUT` (#26086) +- Ensure that socket timeouts are set only during the token validation (#26066) +- Fix race condition in `RemoteHyperVSocket` (#26057) +- Fix `stderr` output of console host to respect `NO_COLOR` (#24391) +- Update PSRP protocol to deprecate session key exchange between newer client and server (#25774) +- Fix the `ssh` PATH check in `SSHConnectionInfo` when the default Runspace is not available (#25780) (Thanks @jborean93!) +- Adding hex format for native command exit codes (#21067) (Thanks @sba923!) +- Fix infinite loop crash in variable type inference (#25696) (Thanks @MartinGC94!) +- Add `PSForEach` and `PSWhere` as aliases for the PowerShell intrinsic methods `Where` and `Foreach` (#25511) (Thanks @powercode!) + +### General Cmdlet Updates and Fixes + +- Remove `IsScreenReaderActive()` check from `ConsoleHost` (#26118) +- Fix `ConvertFrom-Json` to ignore comments inside array literals (#14553) (#26050) (Thanks @MatejKafka!) +- Fix `-Debug` to not trigger the `ShouldProcess` prompt (#26081) +- Add the parameter `Register-ArgumentCompleter -NativeFallback` to support registering a cover-all completer for native commands (#25230) +- Change the default feedback provider timeout from 300ms to 1000ms (#25910) +- Update PATH environment variable for package manager executable on Windows (#25847) +- Fix `Write-Host` to respect `OutputRendering = PlainText` (#21188) +- Improve the `$using` expression support in `Invoke-Command` (#24025) (Thanks @jborean93!) +- Use parameter `HelpMessage` for tool tip in parameter completion (#25108) (Thanks @jborean93!) +- Revert "Never load a module targeting the PSReadLine module's `SessionState`" (#25792) +- Fix debug tracing error with magic extents (#25726) (Thanks @jborean93!) +- Add `MethodInvocation` trace for overload tracing (#21320) (Thanks @jborean93!) +- Improve verbose and debug logging level messaging in web cmdlets (#25510) (Thanks @JustinGrote!) +- Fix quoting in completion if the path includes a double quote character (#25631) (Thanks @MartinGC94!) +- Fix the common parameter `-ProgressAction` for advanced functions (#24591) (Thanks @cmkb3!) +- Use absolute path in `FileSystemProvider.CreateDirectory` (#24615) (Thanks @Tadas!) +- Make inherited protected internal instance members accessible in PowerShell class scope (#25245) (Thanks @mawosoft!) +- Treat `-Target` as literal in `New-Item` (#25186) (Thanks @GameMicrowave!) +- Remove duplicate modules from completion results (#25538) (Thanks @MartinGC94!) +- Add completion for variables assigned in `ArrayLiteralAst` and `ParenExpressionAst` (#25303) (Thanks @MartinGC94!) +- Add support for thousands separators in `[bigint]` casting (#25396) (Thanks @AbishekPonmudi!) +- Add internal methods to check Preferences (#25514) (Thanks @iSazonov!) +- Improve debug logging of Web cmdlet request and response (#25479) (Thanks @JustinGrote!) +- Revert "Allow empty prefix string in 'Import-Module -Prefix' to override default prefix in manifest (#20409)" (#25462) (Thanks @MartinGC94!) +- Fix the `NullReferenceException` when writing progress records to console from multiple threads (#25440) (Thanks @kborowinski!) +- Update `Get-Service` to ignore common errors when retrieving non-critical properties for a service (#24245) (Thanks @jborean93!) +- Add single/double quote support for `Join-String` Argument Completer (#25283) (Thanks @ArmaanMcleod!) +- Fix tab completion for env/function variables (#25346) (Thanks @jborean93!) +- Fix `Out-GridView` by replacing use of obsolete `BinaryFormatter` with custom implementation (#25497) (Thanks @mawosoft!) +- Remove the use of Windows PowerShell ETW provider ID from codebase and update the `PSDiagnostics` module to work for PowerShell 7 (#25590) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @xtqqczze, @mawosoft, @ArmaanMcleod

    + +
    + +
      +
    • Enable CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types (#25813) (Thanks @xtqqczze!)
    • +
    • Remove some unused ConsoleControl structs (#26063) (Thanks @xtqqczze!)
    • +
    • Remove unused FileStreamBackReader.NativeMethods type (#26062) (Thanks @xtqqczze!)
    • +
    • Ensure data-serialization files end with one newline (#26039) (Thanks @xtqqczze!)
    • +
    • Remove unnecessary CS0618 suppressions from Variant APIs (#26006) (Thanks @xtqqczze!)
    • +
    • Ensure .cs files end with exactly one newline (#25968) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2105 rule suppression (#25938) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1703 rule suppression (#25955) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2240 rule suppression (#25957) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1701 rule suppression (#25948) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2233 rule suppression (#25951) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1026 rule suppression (#25934) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA1059 rule suppression (#25940) (Thanks @xtqqczze!)
    • +
    • Remove obsolete CA2118 rule suppression (#25924) (Thanks @xtqqczze!)
    • +
    • Remove redundant System.Runtime.Versioning attributes (#25926) (Thanks @xtqqczze!)
    • +
    • Seal internal types in Microsoft.PowerShell.Commands.Utility (#25892) (Thanks @xtqqczze!)
    • +
    • Seal internal types in Microsoft.PowerShell.Commands.Management (#25849) (Thanks @xtqqczze!)
    • +
    • Make the interface IDeepCloneable internal to minimize confusion (#25552)
    • +
    • Remove OnDeserialized and Serializable attributes from Microsoft.Management.UI.Internal project (#25548)
    • +
    • Refactor Tooltip/ListItemText mapping to use CompletionDisplayInfoMapper delegate (#25395) (Thanks @ArmaanMcleod!)
    • +
    + +
    + +### Tools + +- Add Codeql Suppressions (#25943, #26132) +- Update CODEOWNERS to add Justin as a maintainer (#25386) +- Do not run labels workflow in the internal repository (#25279) + +### Tests + +- Mark the 3 consistently failing tests as pending to unblock PRs (#26091) +- Make some tests less noisy on failure (#26035) (Thanks @xtqqczze!) +- Suppress false positive `PSScriptAnalyzer` warnings in tests and build scripts (#25864) +- Fix updatable help test for new content (#25819) +- Add more tests for `PSForEach` and `PSWhere` methods (#25519) +- Fix the isolated module test that was disabled previously (#25420) + +### Build and Packaging Improvements + +
    + + + +

    We thank the following contributors!

    +

    @alerickson, @senerh, @RichardSlater, @xtqqczze

    + +
    + +
      +
    • Update package references for the master branch (#26124)
    • +
    • Remove ThreadJob module and update PSReadLine to 2.4.4-beta4 (#26120)
    • +
    • Automate Store Publishing (#25725)
    • +
    • Add global config change detection to action (#26082)
    • +
    • Update outdated package references (#26069)
    • +
    • Ensure that the workflows are triggered on .globalconfig and other files at the root of the repo (#26034)
    • +
    • Update Microsoft.PowerShell.PSResourceGet to 1.2.0-preview3 (#26056) (Thanks @alerickson!)
    • +
    • Update metadata for Stable to v7.5.3 and LTS to v7.4.12 (#26054) (Thanks @senerh!)
    • +
    • Bump github/codeql-action from 3.30.2 to 3.30.3 (#26036)
    • +
    • Update version for the package Microsoft.PowerShell.Native (#26041)
    • +
    • Fix the APIScan pipeline (#26016)
    • +
    • Move PowerShell build to use .NET SDK 10.0.100-rc.1 (#26027)
    • +
    • fix(apt-package): add libicu76 dependency to support Debian 13 (#25866) (Thanks @RichardSlater!)
    • +
    • Bump github/codeql-action from 3.30.1 to 3.30.2 (#26029)
    • +
    • Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26025)
    • +
    • Bump github/codeql-action from 3.30.0 to 3.30.1 (#26008)
    • +
    • Bump actions/github-script from 7 to 8 (#25983)
    • +
    • Fix variable reference for release environment in pipeline (#26012)
    • +
    • Add LinuxHost Network configuration to PowerShell Packages pipeline (#26000)
    • +
    • Make logical template name consistent between pipelines (#25990)
    • +
    • Update container images to use mcr.microsoft.com for Linux and Azure GǪ (#25981)
    • +
    • Bump github/codeql-action from 3.29.11 to 3.30.0 (#25966)
    • +
    • Bump actions/setup-dotnet from 4 to 5 (#25978)
    • +
    • Add build to vPack Pipeline (#25915)
    • +
    • Replace DOTNET_SKIP_FIRST_TIME_EXPERIENCE with DOTNET_NOLOGO (#25946) (Thanks @xtqqczze!)
    • +
    • Bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#25930)
    • +
    • Bump github/codeql-action from 3.29.10 to 3.29.11 (#25889)
    • +
    • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25885)
    • +
    • Specify .NET Search by Build Type (#25837)
    • +
    • Update PowerShell to use .NET SDK v10-preview.7 (#25876)
    • +
    • Bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#25882)
    • +
    • Bump github/codeql-action from 3.29.9 to 3.29.10 (#25881)
    • +
    • Change the macos runner image to macos 15 large (#25867)
    • +
    • Bump actions/checkout from 4 to 5 (#25853)
    • +
    • Bump github/codeql-action from 3.29.7 to 3.29.9 (#25857)
    • +
    • Update to .NET 10 Preview 6 (#25828)
    • +
    • Bump agrc/create-reminder-action from 1.1.20 to 1.1.22 (#25808)
    • +
    • Bump agrc/reminder-action from 1.0.17 to 1.0.18 (#25807)
    • +
    • Bump github/codeql-action from 3.28.19 to 3.29.5 (#25797)
    • +
    • Bump super-linter/super-linter from 7.4.0 to 8.0.0 (#25770)
    • +
    • Update metadata for v7.5.2 and v7.4.11 releases (#25687)
    • +
    • Correct Capitalization Referencing Templates (#25669)
    • +
    • Change linux packaging tests to ubuntu latest (#25634)
    • +
    • Bump github/codeql-action from 3.28.18 to 3.28.19 (#25636)
    • +
    • Move to .NET 10 preview 4 and update package references (#25602)
    • +
    • Revert "Add windows signing for pwsh.exe" (#25586)
    • +
    • Bump ossf/scorecard-action from 2.4.1 to 2.4.2 (#25628)
    • +
    • Publish .msixbundle package as a VPack (#25612)
    • +
    • Bump agrc/reminder-action from 1.0.16 to 1.0.17 (#25573)
    • +
    • Bump agrc/create-reminder-action from 1.1.18 to 1.1.20 (#25572)
    • +
    • Bump github/codeql-action from 3.28.17 to 3.28.18 (#25580)
    • +
    • Bump super-linter/super-linter from 7.3.0 to 7.4.0 (#25563)
    • +
    • Bump actions/dependency-review-action from 4.7.0 to 4.7.1 (#25562)
    • +
    • Update metadata.json with 7.4.10 (#25554)
    • +
    • Bump github/codeql-action from 3.28.16 to 3.28.17 (#25508)
    • +
    • Bump actions/dependency-review-action from 4.6.0 to 4.7.0 (#25529)
    • +
    • Move MSIXBundle to Packages and Release to GitHub (#25512)
    • +
    • Update outdated package references (#25506)
    • +
    • Bump github/codeql-action from 3.28.15 to 3.28.16 (#25429)
    • +
    • Fix Conditional Parameter to Skip NuGet Publish (#25468)
    • +
    • Update metadata.json (#25438)
    • +
    • Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25437)
    • +
    • Use new variables template for vPack (#25434)
    • +
    • Bump agrc/create-reminder-action from 1.1.17 to 1.1.18 (#25416)
    • +
    • Add PSScriptAnalyzer (#25423)
    • +
    • Update outdated package references (#25392)
    • +
    • Use GitHubReleaseTask instead of custom script (#25398)
    • +
    • Update APIScan to use new symbols server (#25388)
    • +
    • Retry ClearlyDefined operations (#25385)
    • +
    • Update to .NET 10.0.100-preview.3 (#25358)
    • +
    • Enhance path filters action to set outputs for all changes when not a PR (#25367)
    • +
    • Combine GitHub and Nuget Release Stage (#25318)
    • +
    • Add Windows Store Signing to MSIX bundle (#25296)
    • +
    • Bump skitionek/notify-microsoft-teams from 190d4d92146df11f854709774a4dae6eaf5e2aa3 to e7a2493ac87dad8aa7a62f079f295e54ff511d88 (#25366)
    • +
    • Add CodeQL suppressions for PowerShell intended behavior (#25359)
    • +
    • Migrate MacOS Signing to OneBranch (#25295)
    • +
    • Bump github/codeql-action from 3.28.13 to 3.28.15 (#25290)
    • +
    • Update test result processing to use NUnitXml format and enhance logging for better clarity (#25288)
    • +
    • Fix R2R for fxdependent packaging (#26131)
    • +
    • Remove UseDotnet task and use the dotnet-install script (#26093)
    • +
    + +
    + +### Documentation and Help Content + +- Fix a typo in the 7.4 changelog (#26038) (Thanks @VbhvGupta!) +- Add 7.4.12 changelog (#26011) +- Add v7.5.3 changelog (#25994) +- Fix typo in changelog for script filename suggestion (#25962) +- Update changelog for v7.5.2 (#25668) +- Update changelog for v7.4.11 (#25667) +- Update build documentation with instruction of dev terminal (#25587) +- Update links and contribution guide in documentation (#25532) (Thanks @JustinGrote!) +- Add 7.4.10 changelog (#25520) +- Add 7.5.1 changelog (#25382) + +[7.6.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.4...v7.6.0-preview.5 + +## [7.6.0-preview.4] + +### Breaking Changes + +- Fix `WildcardPattern.Escape` to escape lone backticks correctly (#25211) (Thanks @ArmaanMcleod!) +- Convert `-ChildPath` parameter to `string[]` for `Join-Path` cmdlet (#24677) (Thanks @ArmaanMcleod!) + +PowerShell 7.6-preview.4 includes the following updated modules: + +- **Microsoft.PowerShell.ThreadJob** v2.2.0 +- **ThreadJob** v2.1.0 +The **ThreadJob** module was renamed to **Microsoft.PowerShell.ThreadJob**. There is no difference +in the functionality of the module. To ensure backward compatibility for scripts that use the old +name, the **ThreadJob** v2.1.0 module is a proxy module that points to the +**Microsoft.PowerShell.ThreadJob** v2.2.0. + +### Engine Updates and Fixes + +- Add `PipelineStopToken` to `Cmdlet` which will be signaled when the pipeline is stopping (#24620) (Thanks @jborean93!) +- Fallback to AppLocker after `WldpCanExecuteFile` (#24912) +- Move .NET method invocation logging to after the needed type conversion is done for method arguments (#25022) +- Fix share completion with provider and spaces (#19440) (Thanks @MartinGC94!) + +### General Cmdlet Updates and Fixes + +- Exclude `-OutVariable` assignments within the same `CommandAst` when inferring variables (#25224) (Thanks @MartinGC94!) +- Fix infinite loop in variable type inference (#25206) (Thanks @MartinGC94!) +- Update `Microsoft.PowerShell.PSResourceGet` version in `PSGalleryModules.csproj` (#25135) +- Add tooltips for hashtable key completions (#17864) (Thanks @MartinGC94!) +- Fix type inference of parameters in classic functions (#25172) (Thanks @MartinGC94!) +- Improve assignment type inference (#21143) (Thanks @MartinGC94!) +- Fix `TypeName.GetReflectionType()` to work when the `TypeName` instance represents a generic type definition within a `GenericTypeName` (#24985) +- Remove the old fuzzy suggestion and fix the local script filename suggestion (#25177) +- Improve variable type inference (#19830) (Thanks @MartinGC94!) +- Fix parameter completion when script requirements fail (#17687) (Thanks @MartinGC94!) +- Improve the completion for attribute arguments (#25129) (Thanks @MartinGC94!) +- Fix completion that relies on pseudobinding in script blocks (#25122) (Thanks @MartinGC94!) +- Don't complete duplicate command names (#21113) (Thanks @MartinGC94!) +- Make `SystemPolicy` public APIs visible but non-op on Unix platforms so that they can be included in `PowerShellStandard.Library` (#25051) +- Set standard handles explicitly when starting a process with `-NoNewWindow` (#25061) +- Fix tooltip for variable expansion and include desc (#25112) (Thanks @jborean93!) +- Add type inference for functions without OutputType attribute and anonymous functions (#21127) (Thanks @MartinGC94!) +- Add completion for variables assigned by command redirection (#25104) (Thanks @MartinGC94!) +- Handle type inference for redirected commands (#21131) (Thanks @MartinGC94!) +- Allow empty prefix string in `Import-Module -Prefix` to override default prefix in manifest (#20409) (Thanks @MartinGC94!) +- Update variable/property assignment completion so it can fallback to type inference (#21134) (Thanks @MartinGC94!) +- Use `Get-Help` approach to find `about_*.help.txt` files with correct locale for completions (#24194) (Thanks @MartinGC94!) +- Use script filepath when completing relative paths for using statements (#20017) (Thanks @MartinGC94!) +- Fix completion of variables assigned inside Do loops (#25076) (Thanks @MartinGC94!) +- Fix completion of provider paths when a path returns itself instead of its children (#24755) (Thanks @MartinGC94!) +- Enable completion of scoped variables without specifying scope (#20340) (Thanks @MartinGC94!) +- Fix issue with incomplete results when completing paths with wildcards in non-filesystem providers (#24757) (Thanks @MartinGC94!) +- Allow DSC parsing through OS architecture translation layers (#24852) (Thanks @bdeb1337!) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @ArmaanMcleod, @pressRtowin

    + +
    + +
      +
    • Refactor and add comments to CompletionRequiresQuotes to clarify implementation (#25223) (Thanks @ArmaanMcleod!)
    • +
    • Add QuoteCompletionText method to CompletionHelpers class (#25180) (Thanks @ArmaanMcleod!)
    • +
    • Remove CompletionHelpers escape parameter from CompletionRequiresQuotes (#25178) (Thanks @ArmaanMcleod!)
    • +
    • Refactor CompletionHelpers HandleDoubleAndSingleQuote to have less nesting logic (#25179) (Thanks @ArmaanMcleod!)
    • +
    • Make the use of Oxford commas consistent (#25139)(#25140)(Thanks @pressRtowin!)
    • +
    • Move common completion methods to CompletionHelpers class (#25138) (Thanks @ArmaanMcleod!)
    • +
    • Return Array.Empty instead of collection [] (#25137) (Thanks @ArmaanMcleod!)
    • +
    + +
    + +### Tools + +- Check GH token availability for Get-Changelog (#25133) + +### Tests + +- Add XUnit test for `HandleDoubleAndSingleQuote` in CompletionHelpers class (#25181) (Thanks @ArmaanMcleod!) + +### Build and Packaging Improvements + +
    + +
      +
    • Switch to ubuntu-lastest for CI (#25247)
    • +
    • Update outdated package references (#25026)(#25232)
    • +
    • Bump Microsoft.PowerShell.ThreadJob and ThreadJob modules (#25232)
    • +
    • Bump github/codeql-action from 3.27.9 to 3.28.13 (#25218)(#25231)
    • +
    • Update .NET SDK to 10.0.100-preview.2 (#25154)(#25225)
    • +
    • Remove obsolete template from Windows Packaging CI (#25226)
    • +
    • Bump actions/upload-artifact from 4.5.0 to 4.6.2 (#25220)
    • +
    • Bump agrc/reminder-action from 1.0.15 to 1.0.16 (#25222)
    • +
    • Bump actions/checkout from 2 to 4 (#25221)
    • +
    • Add NoWarn NU1605 to System.ServiceModel.* (#25219)
    • +
    • Bump actions/github-script from 6 to 7 (#25217)
    • +
    • Bump ossf/scorecard-action from 2.4.0 to 2.4.1 (#25216)
    • +
    • Bump super-linter/super-linter from 7.2.1 to 7.3.0 (#25215)
    • +
    • Bump agrc/create-reminder-action from 1.1.16 to 1.1.17 (#25214)
    • +
    • Remove dependabot updates that don't work (#25213)
    • +
    • Update GitHub Actions to work in private GitHub repo (#25197)
    • +
    • Cleanup old release pipelines (#25201)
    • +
    • Update package pipeline windows image version (#25191)
    • +
    • Skip additional packages when generating component manifest (#25102)
    • +
    • Only build Linux for packaging changes (#25103)
    • +
    • Remove Az module installs and AzureRM uninstalls in pipeline (#25118)
    • +
    • Add GitHub Actions workflow to verify PR labels (#25145)
    • +
    • Add back-port workflow using dotnet/arcade (#25106)
    • +
    • Make Component Manifest Updater use neutral target in addition to RID target (#25094)
    • +
    • Make sure the vPack pipeline does not produce an empty package (#24988)
    • +
    + +
    + +### Documentation and Help Content + +- Add 7.4.9 changelog (#25169) +- Create changelog for 7.4.8 (#25089) + +[7.6.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.3...v7.6.0-preview.4 + +## [7.6.0-preview.3] + +### Breaking Changes + +- Remove trailing space from event source name (#24192) (Thanks @MartinGC94!) + +### General Cmdlet Updates and Fixes + +- Add completion single/double quote support for `-Noun` parameter for `Get-Command` (#24977) (Thanks @ArmaanMcleod!) +- Stringify `ErrorRecord` with empty exception message to empty string (#24949) (Thanks @MatejKafka!) +- Add completion single/double quote support for `-PSEdition` parameter for `Get-Module` (#24971) (Thanks @ArmaanMcleod!) +- Error when `New-Item -Force` is passed an invalid directory name (#24936) (Thanks @kborowinski!) +- Allow `Start-Transcript`to use `$Transcript` which is a `PSObject` wrapped string to specify the transcript path (#24963) (Thanks @kborowinski!) +- Add quote handling in `Verb`, `StrictModeVersion`, `Scope` & `PropertyType` Argument Completers with single helper method (#24839) (Thanks @ArmaanMcleod!) +- Improve `Start-Process -Wait` polling efficiency (#24711) (Thanks @jborean93!) +- Convert `InvalidCommandNameCharacters` in `AnalysisCache` to `SearchValues` for more efficient char searching (#24880) (Thanks @ArmaanMcleod!) +- Convert `s_charactersRequiringQuotes` in Completion Completers to `SearchValues` for more efficient char searching (#24879) (Thanks @ArmaanMcleod!) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @xtqqczze, @fMichaleczek, @ArmaanMcleod

    + +
    + +
      +
    • Fix RunspacePool, RunspacePoolInternal and RemoteRunspacePoolInternal IDisposable implementation (#24720) (Thanks @xtqqczze!)
    • +
    • Remove redundant Attribute suffix (#24940) (Thanks @xtqqczze!)
    • +
    • Fix formatting of the XML comment for SteppablePipeline.Clean() (#24941)
    • +
    • Use Environment.ProcessId in SpecialVariables.PID (#24926) (Thanks @fMichaleczek!)
    • +
    • Replace char[] array in CompletionRequiresQuotes with cached SearchValues (#24907) (Thanks @ArmaanMcleod!)
    • +
    • Update IndexOfAny calls with invalid path/filename to SearchValues<char> for more efficient char searching (#24896) (Thanks @ArmaanMcleod!)
    • +
    • Seal internal types in PlatformInvokes (#24826) (Thanks @xtqqczze!)
    • +
    + +
    + +### Tools + +- Update CODEOWNERS (#24989) + +### Build and Packaging Improvements + +
    + + + +

    We thank the following contributors!

    +

    @xtqqczze, @KyZy7

    + +
    + +
      +
    • Update branch for release - Transitive - false - none (#24995)
    • +
    • Add setup dotnet action to the build composite action (#24996)
    • +
    • Give the pipeline runs meaningful names (#24987)
    • +
    • Fix V-Pack download package name (#24866)
    • +
    • Set LangVersion compiler option to 13.0 in Test.Common.props (#24621) (Thanks @xtqqczze!)
    • +
    • Fix release branch filters (#24933)
    • +
    • Fix GitHub Action filter overmatching (#24929)
    • +
    • Add UseDotnet task for installing dotnet (#24905)
    • +
    • Convert powershell/PowerShell-CI-macos to GitHub Actions (#24914)
    • +
    • Convert powershell/PowerShell-CI-linux to GitHub Actions (#24913)
    • +
    • Convert powershell/PowerShell-Windows-CI to GitHub Actions (#24899)
    • +
    • Fix MSIX stage in release pipeline (#24900)
    • +
    • Update .NET SDK (#24906)
    • +
    • Update metadata.json (#24862)
    • +
    • PMC parse state correctly from update command's response (#24850)
    • +
    • Add EV2 support for publishing PowerShell packages to PMC (#24841)
    • +
    • Remove AzDO credscan as it is now in GitHub (#24842)
    • +
    • Add *.props and sort path filters for windows CI (#24822)
    • +
    • Use work load identity service connection to download makeappx tool from storage account (#24817)
    • +
    • Update path filters for Windows CI (#24809)
    • +
    • Update outdated package references (#24758)
    • +
    • Update metadata.json (#24787) (Thanks @KyZy7!)
    • +
    • Add tool package download in publish nuget stage (#24790)
    • +
    • Fix Changelog content grab during GitHub Release (#24788)
    • +
    • Update metadata.json (#24764)
    • +
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#24767)
    • +
    • Add a parameter that skips verify packages step (#24763)
    • +
    + +
    + +### Documentation and Help Content + +- Add 7.4.7 Changelog (#24844) +- Create changelog for v7.5.0 (#24808) +- Update Changelog for v7.6.0-preview.2 (#24775) + +[7.6.0-preview.3]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.2...v7.6.0-preview.3 + +## [7.6.0-preview.2] - 2025-01-14 + +### General Cmdlet Updates and Fixes + +- Add the `AIShell` module to telemetry collection list (#24747) +- Add helper in `EnumSingleTypeConverter` to get enum names as array (#17785) (Thanks @fflaten!) +- Return correct FileName property for `Get-Item` when listing alternate data streams (#18019) (Thanks @kilasuit!) +- Add `-ExcludeModule` parameter to `Get-Command` (#18955) (Thanks @MartinGC94!) +- Update Named and Statement block type inference to not consider AssignmentStatements and Increment/decrement operators as part of their output (#21137) (Thanks @MartinGC94!) +- Update `DnsNameList` for `X509Certificate2` to use `X509SubjectAlternativeNameExtension.EnumerateDnsNames` Method (#24714) (Thanks @ArmaanMcleod!) +- Add completion of modules by their shortname (#20330) (Thanks @MartinGC94!) +- Fix `Get-ItemProperty` to report non-terminating error for cast exception (#21115) (Thanks @ArmaanMcleod!) +- Add `-PropertyType` argument completer for `New-ItemProperty` (#21117) (Thanks @ArmaanMcleod!) +- Fix a bug in how `Write-Host` handles `XmlNode` object (#24669) (Thanks @brendandburns!) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @xtqqczze

    + +
    + +
      +
    • Seal ClientRemoteSessionDSHandlerImpl (#21218) (Thanks @xtqqczze!)
    • +
    • Seal internal type ClientRemoteSessionDSHandlerImpl (#24705) (Thanks @xtqqczze!)
    • +
    • Seal classes in RemotingProtocol2 (#21164) (Thanks @xtqqczze!)
    • +
    + +
    + +### Tools + +- Added Justin Chung as PowerShell team memeber on releaseTools.psm1 (#24672) + +### Tests + +- Skip CIM ETS member test on older Windows platforms (#24681) + +### Build and Packaging Improvements + +
    + + + +

    Updated SDK to 9.0.101

    + +
    + +
      +
    • Update branch for release - Transitive - false - none (#24754)
    • +
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#24767)
    • +
    • Add a parameter that skips verify packages step (#24763)
    • +
    • Make the AssemblyVersion not change for servicing releases (#24667)
    • +
    • Fixed release pipeline errors and switched to KS3 (#24751)
    • +
    • Update outdated package references (#24580)
    • +
    • Bump actions/upload-artifact from 4.4.3 to 4.5.0 (#24689)
    • +
    • Update .NET feed with new domain as azureedge is retiring (#24703)
    • +
    • Bump super-linter/super-linter from 7.2.0 to 7.2.1 (#24678)
    • +
    • Bump github/codeql-action from 3.27.7 to 3.27.9 (#24674)
    • +
    • Bump actions/dependency-review-action from 4.4.0 to 4.5.0 (#24607)
    • +
    + +
    + +### Documentation and Help Content + +- Update cmdlets WG members (#24275) (Thanks @kilasuit!) + +[7.6.0-preview.2]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.1...v7.6.0-preview.2 + +## [7.6.0-preview.1] - 2024-12-16 + +### Breaking Changes + +- Treat large Enum values as numbers in `ConvertTo-Json` (#20999) (Thanks @jborean93!) + +### General Cmdlet Updates and Fixes + +- Add proper error for running `Get-PSSession -ComputerName` on Unix (#21009) (Thanks @jborean93!) +- Resolve symbolic link target relative to the symbolic link instead of the working directory (#15235) (#20943) (Thanks @MatejKafka!) +- Fix up buffer management getting network roots (#24600) (Thanks @jborean93!) +- Support `PSObject` wrapped values in `ArgumentToEncodingTransformationAttribute` (#24555) (Thanks @jborean93!) +- Update PSReadLine to 2.3.6 (#24380) +- Add telemetry to track the use of features (#24247) +- Handle global tool specially when prepending `PSHome` to `PATH` (#24228) +- Fix how processor architecture is validated in `Import-Module` (#24265) +- Make features `PSCommandNotFoundSuggestion`, `PSCommandWithArgs`, and `PSModuleAutoLoadSkipOfflineFiles` stable (#24246) +- Write type data to the pipeline instead of collecting it (#24236) (Thanks @MartinGC94!) +- Add support to `Get-Error` to handle BoundParameters (#20640) +- Fix `Get-FormatData` to not cast a type incorrectly (#21157) +- Delay progress bar in `Copy-Item` and `Remove-Item` cmdlets (#24013) (Thanks @TheSpyGod!) +- Add `-Force` parameter to `Resolve-Path` and `Convert-Path` cmdlets to support wildcard hidden files (#20981) (Thanks @ArmaanMcleod!) +- Use host exe to determine `$PSHOME` location when `SMA.dll` location is not found (#24072) +- Fix `Test-ModuleManifest` so it can use a UNC path (#24115) + +### Code Cleanup + +
    + + + +

    We thank the following contributors!

    +

    @eltociear, @JayBazuzi

    + +
    + +
      +
    • Fix typos in ShowModuleControl.xaml.cs (#24248) (Thanks @eltociear!)
    • +
    • Fix a typo in the build doc (#24172) (Thanks @JayBazuzi!)
    • +
    + +
    + +### Tools + +- Fix devcontainer extensions key (#24359) (Thanks @ThomasNieto!) +- Support new backport branch format (#24378) +- Update markdownLink.yml to not run on release branches (#24323) +- Remove old code that downloads msix for win-arm64 (#24175) + +### Tests + +- Fix cleanup in PSResourceGet test (#24339) + +### Build and Packaging Improvements + +
    + + + +

    We thank the following contributors!

    +

    @MartinGC94, @jborean93, @xtqqczze, @alerickson, @iSazonov, @rzippo

    + +
    + +
      +
    • Deploy Box update (#24632)
    • +
    • Remove Regex use (#24235) (Thanks @MartinGC94!)
    • +
    • Improve cim ETS member inference completion (#24235) (Thanks @MartinGC94!)
    • +
    • Emit ProgressRecord in CLIXML minishell output (#21373) (Thanks @jborean93!)
    • +
    • Assign the value returned by the MaybeAdd method
    • (#24652) +
    • Add support for interface static abstract props (#21061) (Thanks @jborean93!)
    • +
    • Change call to optional add in the binder expression (#24451) (Thanks @jborean93!)
    • +
    • Turn off AMSI member invocation on nix release builds (#24451) (Thanks @jborean93!)
    • +
    • Bump github/codeql-action from 3.27.0 to 3.27.6 (#24639)
    • +
    • Update src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs (#24239) (Thanks @jborean93!)
    • +
    • Apply suggestions from code review (#24239) (Thanks @jborean93!)
    • +
    • Add remote runspace check for PushRunspace (#24239) (Thanks @jborean93!)
    • +
    • Set LangVersion compiler option to 13.0 (#24619) (Thanks @xtqqczze!)
    • +
    • Set LangVersion compiler option to 13.0 (#24617) (Thanks @xtqqczze!)
    • +
    • Update metadata.json for PowerShell 7.5 RC1 release (#24589)
    • +
    • Update nuget publish to use Deploy Box (#24596)
    • +
    • Added Deploy Box Product Pathway to GitHub Release and NuGet Release Pipelines (#24583)
    • +
    • Update machine pool for copy blob and upload buildinfo stage (#24587)
    • +
    • Bump .NET 9 and dependencies (#24573)
    • +
    • Bump actions/dependency-review-action from 4.3.4 to 4.4.0 (#24503)
    • +
    • Bump actions/checkout from 4.2.1 to 4.2.2 (#24488)
    • +
    • Bump agrc/reminder-action from 1.0.14 to 1.0.15 (#24384)
    • +
    • Bump actions/upload-artifact from 4.4.0 to 4.4.3 (#24410)
    • +
    • Update branch for release (#24534)
    • +
    • Revert "Update package references (#24414)" (#24532)
    • +
    • Add a way to use only NuGet feed sources (#24528)
    • +
    • Update PSResourceGet to v1.1.0-RC2 (#24512) (Thanks @alerickson!)
    • +
    • Bump .NET to 9.0.100-rc.2.24474.11 (#24509)
    • +
    • Fix seed max value for Container Linux CI (#24510)
    • +
    • Update metadata.json for 7.2.24 and 7.4.6 releases (#24484)
    • +
    • Download package from package build for generating vpack (#24481)
    • +
    • Keep the roff file when gzipping it. (#24450)
    • +
    • Delete the msix blob if it's already there (#24353)
    • +
    • Add PMC mapping for debian 12 (bookworm) (#24413)
    • +
    • Checkin generated manpage (#24423)
    • +
    • Add CodeQL scanning to APIScan build (#24303)
    • +
    • Update package references (#24414)
    • +
    • Update vpack pipeline (#24281)
    • +
    • Bring changes from v7.5.0-preview.5 Release Branch to Master (#24369)
    • +
    • Bump agrc/create-reminder-action from 1.1.15 to 1.1.16 (#24375)
    • +
    • Add BaseUrl to buildinfo json file (#24376)
    • +
    • Update metadata.json (#24352)
    • +
    • Copy to static site instead of making blob public (#24269)
    • +
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0-preview2 (#24300) (Thanks @alerickson!)
    • +
    • add updated libicu dependency for debian packages (#24301)
    • +
    • add mapping to azurelinux repo (#24290)
    • +
    • Remove the MD5 branch in the strong name signing token calculation (#24288)
    • +
    • Bump .NET 9 to 9.0.100-rc.1.24452.12 (#24273)
    • +
    • Ensure the official build files CodeQL issues (#24278)
    • +
    • Update experimental-feature json files (#24271)
    • +
    • Make some release tests run in a hosted pools (#24270)
    • +
    • Do not build the exe for Global tool shim project (#24263)
    • +
    • Update and add new NuGet package sources for different environments. (#24264)
    • +
    • Bump skitionek/notify-microsoft-teams (#24261)
    • +
    • Create new pipeline for compliance (#24252)
    • +
    • Capture environment better (#24148)
    • +
    • Add specific path for issues in tsaconfig (#24244)
    • +
    • Use Managed Identity for APIScan authentication (#24243)
    • +
    • Add windows signing for pwsh.exe (#24219)
    • +
    • Bump super-linter/super-linter from 7.0.0 to 7.1.0 (#24223)
    • +
    • Update the URLs used in nuget.config files (#24203)
    • +
    • Check Create and Submit in vPack build by default (#24181)
    • +
    • Replace PSVersion source generator with incremental one (#23815) (Thanks @iSazonov!)
    • +
    • Save man files in /usr/share/man instead of /usr/local/share/man (#23855) (Thanks @rzippo!)
    • +
    • Bump super-linter/super-linter from 6.8.0 to 7.0.0 (#24169)
    • +
    + +
    + +### Documentation and Help Content + +- Updated Third Party Notices (#24666) +- Update `HelpInfoUri` for 7.5 (#24610) +- Update changelog for v7.4.6 release (#24496) +- Update to the latest NOTICES file (#24259) +- Update the changelog `preview.md` (#24213) +- Update changelog readme with 7.4 (#24182) (Thanks @ThomasNieto!) +- Fix Markdown linting error (#24204) +- Updated changelog for v7.2.23 (#24196) (Internal 32131) +- Update changelog and `metadata.json` for v7.4.5 release (#24183) +- Bring 7.2 changelogs back to master (#24158) + +[7.6.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-rc.1...v7.6.0-preview.1 diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 851640f8cc5..8e97635bada 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,761 +1,2 @@ # Preview Changelog -## [7.6.0-rc.1] - 2026-02-19 - -### Tests - -- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26705) - -### Build and Packaging Improvements - -
    - - - -

    Expand to see details.

    - -
    - -
      -
    • Update branch for release (#26779)
    • -
    • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26767)
    • -
    • Update Microsoft.PowerShell.Native package version (#26748)
    • -
    • Move PowerShell build to depend on .NET SDK 10.0.102 (#26717)
    • -
    • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26715)
    • -
    • Fix macOS preview package identifier detection to use version string (#26709)
    • -
    • Update metadata.json to update the Latest attribute with a better name (#26708)
    • -
    • Remove unused runCodesignValidationInjection variable from pipeline templates (#26707)
    • -
    • Update Get-ChangeLog to handle backport PRs correctly (#26706)
    • -
    • Bring release changes from the v7.6.0-preview.6 release (#26626)
    • -
    • Fix the DSC test by skipping AfterAll cleanup if the initial setup in BeforeAll failed (#26622)
    • -
    - -
    - -[7.6.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.6...v7.6.0-rc.1 - -## [7.6.0-preview.6] - 2025-12-11 - -### Engine Updates and Fixes - -- Properly Expand Aliases to their actual ResolvedCommand (#26571) (Thanks @kilasuit!) - -### General Cmdlet Updates and Fixes - -- Update `Microsoft.PowerShell.PSResourceGet` to `v1.2.0-preview5` (#26590) -- Make the experimental feature `PSFeedbackProvider` stable (#26502) -- Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26487) -- Add Delimiter parameter to `Get-Clipboard` (#26572) (Thanks @MartinGC94!) -- Close pipe client handles after creating the child ssh process (#26564) -- Make some experimental features stable (#26490) -- DSC v3 resource for PowerShell Profile (#26447) - -### Tools - -- Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26530) -- Add reusable get-changed-files action and refactor existing actions (#26529) -- Refactor analyze job to reusable workflow and enable on Windows CI (#26494) - -### Tests - -- Fix merge conflict checker for empty file lists and filter *.cs files (#26556) -- Add markdown link verification for PRs (#26445) - -### Build and Packaging Improvements - -
    - - - -

    Expand to see details.

    - -
    - -
      -
    • Fix template path for rebuild branch check in package.yml (#26560)
    • -
    • Update the macos package name for preview releases to match the previous pattern (#26576)
    • -
    • Add rebuild branch support with conditional MSIX signing (#26573)
    • -
    • Update the WCF packages to the latest version that is compatible with v4.10.3 (#26503)
    • -
    • Improve ADO package build and validation across platforms (#26532)
    • -
    • Mirror .NET/runtime ICU version range in PowerShell (#26563) (Thanks @kasperk81!)
    • -
    • Update the macos package name for preview releases to match the previous pattern (#26562)
    • -
    • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26561)
    • -
    • Move package validation to package pipeline (#26558)
    • -
    • Optimize/split windows package signing (#26557)
    • -
    • Remove usage of fpm for DEB package generation (#26504)
    • -
    • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26524)
    • -
    • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501)
    • -
    • Replace fpm with native rpmbuild for RPM package generation (#26441)
    • -
    • Fix GitHub API rate limit errors in test actions (#26492)
    • -
    • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26493)
    • -
    • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26488)
    • -
    • Fix build to only enable ready-to-run for the Release configuration (#26481)
    • -
    • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26468)
    • -
    • Update outdated package references (#26471)
    • -
    • GitHub Workflow cleanup (#26439)
    • -
    • Update PSResourceGet package version to preview4 (#26438)
    • -
    • Update PSReadLine to v2.4.5 (#26446)
    • -
    • Add network isolation policy parameter to vPack pipeline (#26444)
    • -
    • Fix a couple more lint errors
    • -
    • Fix lint errors in preview.md
    • -
    • Make MSIX publish stage dependent on SetReleaseTagandContainerName stage
    • -
    - -
    - -[7.6.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.5...v7.6.0-preview.6 - -## [7.6.0-preview.5] - 2025-09-30 - -### Engine Updates and Fixes - -- Allow opt-out of the named-pipe listener using the environment variable `POWERSHELL_DIAGNOSTICS_OPTOUT` (#26086) -- Ensure that socket timeouts are set only during the token validation (#26066) -- Fix race condition in `RemoteHyperVSocket` (#26057) -- Fix `stderr` output of console host to respect `NO_COLOR` (#24391) -- Update PSRP protocol to deprecate session key exchange between newer client and server (#25774) -- Fix the `ssh` PATH check in `SSHConnectionInfo` when the default Runspace is not available (#25780) (Thanks @jborean93!) -- Adding hex format for native command exit codes (#21067) (Thanks @sba923!) -- Fix infinite loop crash in variable type inference (#25696) (Thanks @MartinGC94!) -- Add `PSForEach` and `PSWhere` as aliases for the PowerShell intrinsic methods `Where` and `Foreach` (#25511) (Thanks @powercode!) - -### General Cmdlet Updates and Fixes - -- Remove `IsScreenReaderActive()` check from `ConsoleHost` (#26118) -- Fix `ConvertFrom-Json` to ignore comments inside array literals (#14553) (#26050) (Thanks @MatejKafka!) -- Fix `-Debug` to not trigger the `ShouldProcess` prompt (#26081) -- Add the parameter `Register-ArgumentCompleter -NativeFallback` to support registering a cover-all completer for native commands (#25230) -- Change the default feedback provider timeout from 300ms to 1000ms (#25910) -- Update PATH environment variable for package manager executable on Windows (#25847) -- Fix `Write-Host` to respect `OutputRendering = PlainText` (#21188) -- Improve the `$using` expression support in `Invoke-Command` (#24025) (Thanks @jborean93!) -- Use parameter `HelpMessage` for tool tip in parameter completion (#25108) (Thanks @jborean93!) -- Revert "Never load a module targeting the PSReadLine module's `SessionState`" (#25792) -- Fix debug tracing error with magic extents (#25726) (Thanks @jborean93!) -- Add `MethodInvocation` trace for overload tracing (#21320) (Thanks @jborean93!) -- Improve verbose and debug logging level messaging in web cmdlets (#25510) (Thanks @JustinGrote!) -- Fix quoting in completion if the path includes a double quote character (#25631) (Thanks @MartinGC94!) -- Fix the common parameter `-ProgressAction` for advanced functions (#24591) (Thanks @cmkb3!) -- Use absolute path in `FileSystemProvider.CreateDirectory` (#24615) (Thanks @Tadas!) -- Make inherited protected internal instance members accessible in PowerShell class scope (#25245) (Thanks @mawosoft!) -- Treat `-Target` as literal in `New-Item` (#25186) (Thanks @GameMicrowave!) -- Remove duplicate modules from completion results (#25538) (Thanks @MartinGC94!) -- Add completion for variables assigned in `ArrayLiteralAst` and `ParenExpressionAst` (#25303) (Thanks @MartinGC94!) -- Add support for thousands separators in `[bigint]` casting (#25396) (Thanks @AbishekPonmudi!) -- Add internal methods to check Preferences (#25514) (Thanks @iSazonov!) -- Improve debug logging of Web cmdlet request and response (#25479) (Thanks @JustinGrote!) -- Revert "Allow empty prefix string in 'Import-Module -Prefix' to override default prefix in manifest (#20409)" (#25462) (Thanks @MartinGC94!) -- Fix the `NullReferenceException` when writing progress records to console from multiple threads (#25440) (Thanks @kborowinski!) -- Update `Get-Service` to ignore common errors when retrieving non-critical properties for a service (#24245) (Thanks @jborean93!) -- Add single/double quote support for `Join-String` Argument Completer (#25283) (Thanks @ArmaanMcleod!) -- Fix tab completion for env/function variables (#25346) (Thanks @jborean93!) -- Fix `Out-GridView` by replacing use of obsolete `BinaryFormatter` with custom implementation (#25497) (Thanks @mawosoft!) -- Remove the use of Windows PowerShell ETW provider ID from codebase and update the `PSDiagnostics` module to work for PowerShell 7 (#25590) - -### Code Cleanup - -
    - - - -

    We thank the following contributors!

    -

    @xtqqczze, @mawosoft, @ArmaanMcleod

    - -
    - -
      -
    • Enable CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types (#25813) (Thanks @xtqqczze!)
    • -
    • Remove some unused ConsoleControl structs (#26063) (Thanks @xtqqczze!)
    • -
    • Remove unused FileStreamBackReader.NativeMethods type (#26062) (Thanks @xtqqczze!)
    • -
    • Ensure data-serialization files end with one newline (#26039) (Thanks @xtqqczze!)
    • -
    • Remove unnecessary CS0618 suppressions from Variant APIs (#26006) (Thanks @xtqqczze!)
    • -
    • Ensure .cs files end with exactly one newline (#25968) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA2105 rule suppression (#25938) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA1703 rule suppression (#25955) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA2240 rule suppression (#25957) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA1701 rule suppression (#25948) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA2233 rule suppression (#25951) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA1026 rule suppression (#25934) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA1059 rule suppression (#25940) (Thanks @xtqqczze!)
    • -
    • Remove obsolete CA2118 rule suppression (#25924) (Thanks @xtqqczze!)
    • -
    • Remove redundant System.Runtime.Versioning attributes (#25926) (Thanks @xtqqczze!)
    • -
    • Seal internal types in Microsoft.PowerShell.Commands.Utility (#25892) (Thanks @xtqqczze!)
    • -
    • Seal internal types in Microsoft.PowerShell.Commands.Management (#25849) (Thanks @xtqqczze!)
    • -
    • Make the interface IDeepCloneable internal to minimize confusion (#25552)
    • -
    • Remove OnDeserialized and Serializable attributes from Microsoft.Management.UI.Internal project (#25548)
    • -
    • Refactor Tooltip/ListItemText mapping to use CompletionDisplayInfoMapper delegate (#25395) (Thanks @ArmaanMcleod!)
    • -
    - -
    - -### Tools - -- Add Codeql Suppressions (#25943, #26132) -- Update CODEOWNERS to add Justin as a maintainer (#25386) -- Do not run labels workflow in the internal repository (#25279) - -### Tests - -- Mark the 3 consistently failing tests as pending to unblock PRs (#26091) -- Make some tests less noisy on failure (#26035) (Thanks @xtqqczze!) -- Suppress false positive `PSScriptAnalyzer` warnings in tests and build scripts (#25864) -- Fix updatable help test for new content (#25819) -- Add more tests for `PSForEach` and `PSWhere` methods (#25519) -- Fix the isolated module test that was disabled previously (#25420) - -### Build and Packaging Improvements - -
    - - - -

    We thank the following contributors!

    -

    @alerickson, @senerh, @RichardSlater, @xtqqczze

    - -
    - -
      -
    • Update package references for the master branch (#26124)
    • -
    • Remove ThreadJob module and update PSReadLine to 2.4.4-beta4 (#26120)
    • -
    • Automate Store Publishing (#25725)
    • -
    • Add global config change detection to action (#26082)
    • -
    • Update outdated package references (#26069)
    • -
    • Ensure that the workflows are triggered on .globalconfig and other files at the root of the repo (#26034)
    • -
    • Update Microsoft.PowerShell.PSResourceGet to 1.2.0-preview3 (#26056) (Thanks @alerickson!)
    • -
    • Update metadata for Stable to v7.5.3 and LTS to v7.4.12 (#26054) (Thanks @senerh!)
    • -
    • Bump github/codeql-action from 3.30.2 to 3.30.3 (#26036)
    • -
    • Update version for the package Microsoft.PowerShell.Native (#26041)
    • -
    • Fix the APIScan pipeline (#26016)
    • -
    • Move PowerShell build to use .NET SDK 10.0.100-rc.1 (#26027)
    • -
    • fix(apt-package): add libicu76 dependency to support Debian 13 (#25866) (Thanks @RichardSlater!)
    • -
    • Bump github/codeql-action from 3.30.1 to 3.30.2 (#26029)
    • -
    • Update Ev2 Shell Extension Image to AzureLinux 3 for PMC Release (#26025)
    • -
    • Bump github/codeql-action from 3.30.0 to 3.30.1 (#26008)
    • -
    • Bump actions/github-script from 7 to 8 (#25983)
    • -
    • Fix variable reference for release environment in pipeline (#26012)
    • -
    • Add LinuxHost Network configuration to PowerShell Packages pipeline (#26000)
    • -
    • Make logical template name consistent between pipelines (#25990)
    • -
    • Update container images to use mcr.microsoft.com for Linux and Azure GǪ (#25981)
    • -
    • Bump github/codeql-action from 3.29.11 to 3.30.0 (#25966)
    • -
    • Bump actions/setup-dotnet from 4 to 5 (#25978)
    • -
    • Add build to vPack Pipeline (#25915)
    • -
    • Replace DOTNET_SKIP_FIRST_TIME_EXPERIENCE with DOTNET_NOLOGO (#25946) (Thanks @xtqqczze!)
    • -
    • Bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#25930)
    • -
    • Bump github/codeql-action from 3.29.10 to 3.29.11 (#25889)
    • -
    • Remove AsyncSDL from Pipelines Toggle Official/NonOfficial Runs (#25885)
    • -
    • Specify .NET Search by Build Type (#25837)
    • -
    • Update PowerShell to use .NET SDK v10-preview.7 (#25876)
    • -
    • Bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#25882)
    • -
    • Bump github/codeql-action from 3.29.9 to 3.29.10 (#25881)
    • -
    • Change the macos runner image to macos 15 large (#25867)
    • -
    • Bump actions/checkout from 4 to 5 (#25853)
    • -
    • Bump github/codeql-action from 3.29.7 to 3.29.9 (#25857)
    • -
    • Update to .NET 10 Preview 6 (#25828)
    • -
    • Bump agrc/create-reminder-action from 1.1.20 to 1.1.22 (#25808)
    • -
    • Bump agrc/reminder-action from 1.0.17 to 1.0.18 (#25807)
    • -
    • Bump github/codeql-action from 3.28.19 to 3.29.5 (#25797)
    • -
    • Bump super-linter/super-linter from 7.4.0 to 8.0.0 (#25770)
    • -
    • Update metadata for v7.5.2 and v7.4.11 releases (#25687)
    • -
    • Correct Capitalization Referencing Templates (#25669)
    • -
    • Change linux packaging tests to ubuntu latest (#25634)
    • -
    • Bump github/codeql-action from 3.28.18 to 3.28.19 (#25636)
    • -
    • Move to .NET 10 preview 4 and update package references (#25602)
    • -
    • Revert "Add windows signing for pwsh.exe" (#25586)
    • -
    • Bump ossf/scorecard-action from 2.4.1 to 2.4.2 (#25628)
    • -
    • Publish .msixbundle package as a VPack (#25612)
    • -
    • Bump agrc/reminder-action from 1.0.16 to 1.0.17 (#25573)
    • -
    • Bump agrc/create-reminder-action from 1.1.18 to 1.1.20 (#25572)
    • -
    • Bump github/codeql-action from 3.28.17 to 3.28.18 (#25580)
    • -
    • Bump super-linter/super-linter from 7.3.0 to 7.4.0 (#25563)
    • -
    • Bump actions/dependency-review-action from 4.7.0 to 4.7.1 (#25562)
    • -
    • Update metadata.json with 7.4.10 (#25554)
    • -
    • Bump github/codeql-action from 3.28.16 to 3.28.17 (#25508)
    • -
    • Bump actions/dependency-review-action from 4.6.0 to 4.7.0 (#25529)
    • -
    • Move MSIXBundle to Packages and Release to GitHub (#25512)
    • -
    • Update outdated package references (#25506)
    • -
    • Bump github/codeql-action from 3.28.15 to 3.28.16 (#25429)
    • -
    • Fix Conditional Parameter to Skip NuGet Publish (#25468)
    • -
    • Update metadata.json (#25438)
    • -
    • Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25437)
    • -
    • Use new variables template for vPack (#25434)
    • -
    • Bump agrc/create-reminder-action from 1.1.17 to 1.1.18 (#25416)
    • -
    • Add PSScriptAnalyzer (#25423)
    • -
    • Update outdated package references (#25392)
    • -
    • Use GitHubReleaseTask instead of custom script (#25398)
    • -
    • Update APIScan to use new symbols server (#25388)
    • -
    • Retry ClearlyDefined operations (#25385)
    • -
    • Update to .NET 10.0.100-preview.3 (#25358)
    • -
    • Enhance path filters action to set outputs for all changes when not a PR (#25367)
    • -
    • Combine GitHub and Nuget Release Stage (#25318)
    • -
    • Add Windows Store Signing to MSIX bundle (#25296)
    • -
    • Bump skitionek/notify-microsoft-teams from 190d4d92146df11f854709774a4dae6eaf5e2aa3 to e7a2493ac87dad8aa7a62f079f295e54ff511d88 (#25366)
    • -
    • Add CodeQL suppressions for PowerShell intended behavior (#25359)
    • -
    • Migrate MacOS Signing to OneBranch (#25295)
    • -
    • Bump github/codeql-action from 3.28.13 to 3.28.15 (#25290)
    • -
    • Update test result processing to use NUnitXml format and enhance logging for better clarity (#25288)
    • -
    • Fix R2R for fxdependent packaging (#26131)
    • -
    • Remove UseDotnet task and use the dotnet-install script (#26093)
    • -
    - -
    - -### Documentation and Help Content - -- Fix a typo in the 7.4 changelog (#26038) (Thanks @VbhvGupta!) -- Add 7.4.12 changelog (#26011) -- Add v7.5.3 changelog (#25994) -- Fix typo in changelog for script filename suggestion (#25962) -- Update changelog for v7.5.2 (#25668) -- Update changelog for v7.4.11 (#25667) -- Update build documentation with instruction of dev terminal (#25587) -- Update links and contribution guide in documentation (#25532) (Thanks @JustinGrote!) -- Add 7.4.10 changelog (#25520) -- Add 7.5.1 changelog (#25382) - -[7.6.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.4...v7.6.0-preview.5 - -## [7.6.0-preview.4] - -### Breaking Changes - -- Fix `WildcardPattern.Escape` to escape lone backticks correctly (#25211) (Thanks @ArmaanMcleod!) -- Convert `-ChildPath` parameter to `string[]` for `Join-Path` cmdlet (#24677) (Thanks @ArmaanMcleod!) - -PowerShell 7.6-preview.4 includes the following updated modules: - -- **Microsoft.PowerShell.ThreadJob** v2.2.0 -- **ThreadJob** v2.1.0 -The **ThreadJob** module was renamed to **Microsoft.PowerShell.ThreadJob**. There is no difference -in the functionality of the module. To ensure backward compatibility for scripts that use the old -name, the **ThreadJob** v2.1.0 module is a proxy module that points to the -**Microsoft.PowerShell.ThreadJob** v2.2.0. - -### Engine Updates and Fixes - -- Add `PipelineStopToken` to `Cmdlet` which will be signaled when the pipeline is stopping (#24620) (Thanks @jborean93!) -- Fallback to AppLocker after `WldpCanExecuteFile` (#24912) -- Move .NET method invocation logging to after the needed type conversion is done for method arguments (#25022) -- Fix share completion with provider and spaces (#19440) (Thanks @MartinGC94!) - -### General Cmdlet Updates and Fixes - -- Exclude `-OutVariable` assignments within the same `CommandAst` when inferring variables (#25224) (Thanks @MartinGC94!) -- Fix infinite loop in variable type inference (#25206) (Thanks @MartinGC94!) -- Update `Microsoft.PowerShell.PSResourceGet` version in `PSGalleryModules.csproj` (#25135) -- Add tooltips for hashtable key completions (#17864) (Thanks @MartinGC94!) -- Fix type inference of parameters in classic functions (#25172) (Thanks @MartinGC94!) -- Improve assignment type inference (#21143) (Thanks @MartinGC94!) -- Fix `TypeName.GetReflectionType()` to work when the `TypeName` instance represents a generic type definition within a `GenericTypeName` (#24985) -- Remove the old fuzzy suggestion and fix the local script filename suggestion (#25177) -- Improve variable type inference (#19830) (Thanks @MartinGC94!) -- Fix parameter completion when script requirements fail (#17687) (Thanks @MartinGC94!) -- Improve the completion for attribute arguments (#25129) (Thanks @MartinGC94!) -- Fix completion that relies on pseudobinding in script blocks (#25122) (Thanks @MartinGC94!) -- Don't complete duplicate command names (#21113) (Thanks @MartinGC94!) -- Make `SystemPolicy` public APIs visible but non-op on Unix platforms so that they can be included in `PowerShellStandard.Library` (#25051) -- Set standard handles explicitly when starting a process with `-NoNewWindow` (#25061) -- Fix tooltip for variable expansion and include desc (#25112) (Thanks @jborean93!) -- Add type inference for functions without OutputType attribute and anonymous functions (#21127) (Thanks @MartinGC94!) -- Add completion for variables assigned by command redirection (#25104) (Thanks @MartinGC94!) -- Handle type inference for redirected commands (#21131) (Thanks @MartinGC94!) -- Allow empty prefix string in `Import-Module -Prefix` to override default prefix in manifest (#20409) (Thanks @MartinGC94!) -- Update variable/property assignment completion so it can fallback to type inference (#21134) (Thanks @MartinGC94!) -- Use `Get-Help` approach to find `about_*.help.txt` files with correct locale for completions (#24194) (Thanks @MartinGC94!) -- Use script filepath when completing relative paths for using statements (#20017) (Thanks @MartinGC94!) -- Fix completion of variables assigned inside Do loops (#25076) (Thanks @MartinGC94!) -- Fix completion of provider paths when a path returns itself instead of its children (#24755) (Thanks @MartinGC94!) -- Enable completion of scoped variables without specifying scope (#20340) (Thanks @MartinGC94!) -- Fix issue with incomplete results when completing paths with wildcards in non-filesystem providers (#24757) (Thanks @MartinGC94!) -- Allow DSC parsing through OS architecture translation layers (#24852) (Thanks @bdeb1337!) - -### Code Cleanup - -
    - - - -

    We thank the following contributors!

    -

    @ArmaanMcleod, @pressRtowin

    - -
    - -
      -
    • Refactor and add comments to CompletionRequiresQuotes to clarify implementation (#25223) (Thanks @ArmaanMcleod!)
    • -
    • Add QuoteCompletionText method to CompletionHelpers class (#25180) (Thanks @ArmaanMcleod!)
    • -
    • Remove CompletionHelpers escape parameter from CompletionRequiresQuotes (#25178) (Thanks @ArmaanMcleod!)
    • -
    • Refactor CompletionHelpers HandleDoubleAndSingleQuote to have less nesting logic (#25179) (Thanks @ArmaanMcleod!)
    • -
    • Make the use of Oxford commas consistent (#25139)(#25140)(Thanks @pressRtowin!)
    • -
    • Move common completion methods to CompletionHelpers class (#25138) (Thanks @ArmaanMcleod!)
    • -
    • Return Array.Empty instead of collection [] (#25137) (Thanks @ArmaanMcleod!)
    • -
    - -
    - -### Tools - -- Check GH token availability for Get-Changelog (#25133) - -### Tests - -- Add XUnit test for `HandleDoubleAndSingleQuote` in CompletionHelpers class (#25181) (Thanks @ArmaanMcleod!) - -### Build and Packaging Improvements - -
    - -
      -
    • Switch to ubuntu-lastest for CI (#25247)
    • -
    • Update outdated package references (#25026)(#25232)
    • -
    • Bump Microsoft.PowerShell.ThreadJob and ThreadJob modules (#25232)
    • -
    • Bump github/codeql-action from 3.27.9 to 3.28.13 (#25218)(#25231)
    • -
    • Update .NET SDK to 10.0.100-preview.2 (#25154)(#25225)
    • -
    • Remove obsolete template from Windows Packaging CI (#25226)
    • -
    • Bump actions/upload-artifact from 4.5.0 to 4.6.2 (#25220)
    • -
    • Bump agrc/reminder-action from 1.0.15 to 1.0.16 (#25222)
    • -
    • Bump actions/checkout from 2 to 4 (#25221)
    • -
    • Add NoWarn NU1605 to System.ServiceModel.* (#25219)
    • -
    • Bump actions/github-script from 6 to 7 (#25217)
    • -
    • Bump ossf/scorecard-action from 2.4.0 to 2.4.1 (#25216)
    • -
    • Bump super-linter/super-linter from 7.2.1 to 7.3.0 (#25215)
    • -
    • Bump agrc/create-reminder-action from 1.1.16 to 1.1.17 (#25214)
    • -
    • Remove dependabot updates that don't work (#25213)
    • -
    • Update GitHub Actions to work in private GitHub repo (#25197)
    • -
    • Cleanup old release pipelines (#25201)
    • -
    • Update package pipeline windows image version (#25191)
    • -
    • Skip additional packages when generating component manifest (#25102)
    • -
    • Only build Linux for packaging changes (#25103)
    • -
    • Remove Az module installs and AzureRM uninstalls in pipeline (#25118)
    • -
    • Add GitHub Actions workflow to verify PR labels (#25145)
    • -
    • Add back-port workflow using dotnet/arcade (#25106)
    • -
    • Make Component Manifest Updater use neutral target in addition to RID target (#25094)
    • -
    • Make sure the vPack pipeline does not produce an empty package (#24988)
    • -
    - -
    - -### Documentation and Help Content - -- Add 7.4.9 changelog (#25169) -- Create changelog for 7.4.8 (#25089) - -[7.6.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.3...v7.6.0-preview.4 - -## [7.6.0-preview.3] - -### Breaking Changes - -- Remove trailing space from event source name (#24192) (Thanks @MartinGC94!) - -### General Cmdlet Updates and Fixes - -- Add completion single/double quote support for `-Noun` parameter for `Get-Command` (#24977) (Thanks @ArmaanMcleod!) -- Stringify `ErrorRecord` with empty exception message to empty string (#24949) (Thanks @MatejKafka!) -- Add completion single/double quote support for `-PSEdition` parameter for `Get-Module` (#24971) (Thanks @ArmaanMcleod!) -- Error when `New-Item -Force` is passed an invalid directory name (#24936) (Thanks @kborowinski!) -- Allow `Start-Transcript`to use `$Transcript` which is a `PSObject` wrapped string to specify the transcript path (#24963) (Thanks @kborowinski!) -- Add quote handling in `Verb`, `StrictModeVersion`, `Scope` & `PropertyType` Argument Completers with single helper method (#24839) (Thanks @ArmaanMcleod!) -- Improve `Start-Process -Wait` polling efficiency (#24711) (Thanks @jborean93!) -- Convert `InvalidCommandNameCharacters` in `AnalysisCache` to `SearchValues` for more efficient char searching (#24880) (Thanks @ArmaanMcleod!) -- Convert `s_charactersRequiringQuotes` in Completion Completers to `SearchValues` for more efficient char searching (#24879) (Thanks @ArmaanMcleod!) - -### Code Cleanup - -
    - - - -

    We thank the following contributors!

    -

    @xtqqczze, @fMichaleczek, @ArmaanMcleod

    - -
    - -
      -
    • Fix RunspacePool, RunspacePoolInternal and RemoteRunspacePoolInternal IDisposable implementation (#24720) (Thanks @xtqqczze!)
    • -
    • Remove redundant Attribute suffix (#24940) (Thanks @xtqqczze!)
    • -
    • Fix formatting of the XML comment for SteppablePipeline.Clean() (#24941)
    • -
    • Use Environment.ProcessId in SpecialVariables.PID (#24926) (Thanks @fMichaleczek!)
    • -
    • Replace char[] array in CompletionRequiresQuotes with cached SearchValues (#24907) (Thanks @ArmaanMcleod!)
    • -
    • Update IndexOfAny calls with invalid path/filename to SearchValues<char> for more efficient char searching (#24896) (Thanks @ArmaanMcleod!)
    • -
    • Seal internal types in PlatformInvokes (#24826) (Thanks @xtqqczze!)
    • -
    - -
    - -### Tools - -- Update CODEOWNERS (#24989) - -### Build and Packaging Improvements - -
    - - - -

    We thank the following contributors!

    -

    @xtqqczze, @KyZy7

    - -
    - -
      -
    • Update branch for release - Transitive - false - none (#24995)
    • -
    • Add setup dotnet action to the build composite action (#24996)
    • -
    • Give the pipeline runs meaningful names (#24987)
    • -
    • Fix V-Pack download package name (#24866)
    • -
    • Set LangVersion compiler option to 13.0 in Test.Common.props (#24621) (Thanks @xtqqczze!)
    • -
    • Fix release branch filters (#24933)
    • -
    • Fix GitHub Action filter overmatching (#24929)
    • -
    • Add UseDotnet task for installing dotnet (#24905)
    • -
    • Convert powershell/PowerShell-CI-macos to GitHub Actions (#24914)
    • -
    • Convert powershell/PowerShell-CI-linux to GitHub Actions (#24913)
    • -
    • Convert powershell/PowerShell-Windows-CI to GitHub Actions (#24899)
    • -
    • Fix MSIX stage in release pipeline (#24900)
    • -
    • Update .NET SDK (#24906)
    • -
    • Update metadata.json (#24862)
    • -
    • PMC parse state correctly from update command's response (#24850)
    • -
    • Add EV2 support for publishing PowerShell packages to PMC (#24841)
    • -
    • Remove AzDO credscan as it is now in GitHub (#24842)
    • -
    • Add *.props and sort path filters for windows CI (#24822)
    • -
    • Use work load identity service connection to download makeappx tool from storage account (#24817)
    • -
    • Update path filters for Windows CI (#24809)
    • -
    • Update outdated package references (#24758)
    • -
    • Update metadata.json (#24787) (Thanks @KyZy7!)
    • -
    • Add tool package download in publish nuget stage (#24790)
    • -
    • Fix Changelog content grab during GitHub Release (#24788)
    • -
    • Update metadata.json (#24764)
    • -
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#24767)
    • -
    • Add a parameter that skips verify packages step (#24763)
    • -
    - -
    - -### Documentation and Help Content - -- Add 7.4.7 Changelog (#24844) -- Create changelog for v7.5.0 (#24808) -- Update Changelog for v7.6.0-preview.2 (#24775) - -[7.6.0-preview.3]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.2...v7.6.0-preview.3 - -## [7.6.0-preview.2] - 2025-01-14 - -### General Cmdlet Updates and Fixes - -- Add the `AIShell` module to telemetry collection list (#24747) -- Add helper in `EnumSingleTypeConverter` to get enum names as array (#17785) (Thanks @fflaten!) -- Return correct FileName property for `Get-Item` when listing alternate data streams (#18019) (Thanks @kilasuit!) -- Add `-ExcludeModule` parameter to `Get-Command` (#18955) (Thanks @MartinGC94!) -- Update Named and Statement block type inference to not consider AssignmentStatements and Increment/decrement operators as part of their output (#21137) (Thanks @MartinGC94!) -- Update `DnsNameList` for `X509Certificate2` to use `X509SubjectAlternativeNameExtension.EnumerateDnsNames` Method (#24714) (Thanks @ArmaanMcleod!) -- Add completion of modules by their shortname (#20330) (Thanks @MartinGC94!) -- Fix `Get-ItemProperty` to report non-terminating error for cast exception (#21115) (Thanks @ArmaanMcleod!) -- Add `-PropertyType` argument completer for `New-ItemProperty` (#21117) (Thanks @ArmaanMcleod!) -- Fix a bug in how `Write-Host` handles `XmlNode` object (#24669) (Thanks @brendandburns!) - -### Code Cleanup - -
    - - - -

    We thank the following contributors!

    -

    @xtqqczze

    - -
    - -
      -
    • Seal ClientRemoteSessionDSHandlerImpl (#21218) (Thanks @xtqqczze!)
    • -
    • Seal internal type ClientRemoteSessionDSHandlerImpl (#24705) (Thanks @xtqqczze!)
    • -
    • Seal classes in RemotingProtocol2 (#21164) (Thanks @xtqqczze!)
    • -
    - -
    - -### Tools - -- Added Justin Chung as PowerShell team memeber on releaseTools.psm1 (#24672) - -### Tests - -- Skip CIM ETS member test on older Windows platforms (#24681) - -### Build and Packaging Improvements - -
    - - - -

    Updated SDK to 9.0.101

    - -
    - -
      -
    • Update branch for release - Transitive - false - none (#24754)
    • -
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#24767)
    • -
    • Add a parameter that skips verify packages step (#24763)
    • -
    • Make the AssemblyVersion not change for servicing releases (#24667)
    • -
    • Fixed release pipeline errors and switched to KS3 (#24751)
    • -
    • Update outdated package references (#24580)
    • -
    • Bump actions/upload-artifact from 4.4.3 to 4.5.0 (#24689)
    • -
    • Update .NET feed with new domain as azureedge is retiring (#24703)
    • -
    • Bump super-linter/super-linter from 7.2.0 to 7.2.1 (#24678)
    • -
    • Bump github/codeql-action from 3.27.7 to 3.27.9 (#24674)
    • -
    • Bump actions/dependency-review-action from 4.4.0 to 4.5.0 (#24607)
    • -
    - -
    - -### Documentation and Help Content - -- Update cmdlets WG members (#24275) (Thanks @kilasuit!) - -[7.6.0-preview.2]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.1...v7.6.0-preview.2 - -## [7.6.0-preview.1] - 2024-12-16 - -### Breaking Changes - -- Treat large Enum values as numbers in `ConvertTo-Json` (#20999) (Thanks @jborean93!) - -### General Cmdlet Updates and Fixes - -- Add proper error for running `Get-PSSession -ComputerName` on Unix (#21009) (Thanks @jborean93!) -- Resolve symbolic link target relative to the symbolic link instead of the working directory (#15235) (#20943) (Thanks @MatejKafka!) -- Fix up buffer management getting network roots (#24600) (Thanks @jborean93!) -- Support `PSObject` wrapped values in `ArgumentToEncodingTransformationAttribute` (#24555) (Thanks @jborean93!) -- Update PSReadLine to 2.3.6 (#24380) -- Add telemetry to track the use of features (#24247) -- Handle global tool specially when prepending `PSHome` to `PATH` (#24228) -- Fix how processor architecture is validated in `Import-Module` (#24265) -- Make features `PSCommandNotFoundSuggestion`, `PSCommandWithArgs`, and `PSModuleAutoLoadSkipOfflineFiles` stable (#24246) -- Write type data to the pipeline instead of collecting it (#24236) (Thanks @MartinGC94!) -- Add support to `Get-Error` to handle BoundParameters (#20640) -- Fix `Get-FormatData` to not cast a type incorrectly (#21157) -- Delay progress bar in `Copy-Item` and `Remove-Item` cmdlets (#24013) (Thanks @TheSpyGod!) -- Add `-Force` parameter to `Resolve-Path` and `Convert-Path` cmdlets to support wildcard hidden files (#20981) (Thanks @ArmaanMcleod!) -- Use host exe to determine `$PSHOME` location when `SMA.dll` location is not found (#24072) -- Fix `Test-ModuleManifest` so it can use a UNC path (#24115) - -### Code Cleanup - -
    - - - -

    We thank the following contributors!

    -

    @eltociear, @JayBazuzi

    - -
    - -
      -
    • Fix typos in ShowModuleControl.xaml.cs (#24248) (Thanks @eltociear!)
    • -
    • Fix a typo in the build doc (#24172) (Thanks @JayBazuzi!)
    • -
    - -
    - -### Tools - -- Fix devcontainer extensions key (#24359) (Thanks @ThomasNieto!) -- Support new backport branch format (#24378) -- Update markdownLink.yml to not run on release branches (#24323) -- Remove old code that downloads msix for win-arm64 (#24175) - -### Tests - -- Fix cleanup in PSResourceGet test (#24339) - -### Build and Packaging Improvements - -
    - - - -

    We thank the following contributors!

    -

    @MartinGC94, @jborean93, @xtqqczze, @alerickson, @iSazonov, @rzippo

    - -
    - -
      -
    • Deploy Box update (#24632)
    • -
    • Remove Regex use (#24235) (Thanks @MartinGC94!)
    • -
    • Improve cim ETS member inference completion (#24235) (Thanks @MartinGC94!)
    • -
    • Emit ProgressRecord in CLIXML minishell output (#21373) (Thanks @jborean93!)
    • -
    • Assign the value returned by the MaybeAdd method
    • (#24652) -
    • Add support for interface static abstract props (#21061) (Thanks @jborean93!)
    • -
    • Change call to optional add in the binder expression (#24451) (Thanks @jborean93!)
    • -
    • Turn off AMSI member invocation on nix release builds (#24451) (Thanks @jborean93!)
    • -
    • Bump github/codeql-action from 3.27.0 to 3.27.6 (#24639)
    • -
    • Update src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs (#24239) (Thanks @jborean93!)
    • -
    • Apply suggestions from code review (#24239) (Thanks @jborean93!)
    • -
    • Add remote runspace check for PushRunspace (#24239) (Thanks @jborean93!)
    • -
    • Set LangVersion compiler option to 13.0 (#24619) (Thanks @xtqqczze!)
    • -
    • Set LangVersion compiler option to 13.0 (#24617) (Thanks @xtqqczze!)
    • -
    • Update metadata.json for PowerShell 7.5 RC1 release (#24589)
    • -
    • Update nuget publish to use Deploy Box (#24596)
    • -
    • Added Deploy Box Product Pathway to GitHub Release and NuGet Release Pipelines (#24583)
    • -
    • Update machine pool for copy blob and upload buildinfo stage (#24587)
    • -
    • Bump .NET 9 and dependencies (#24573)
    • -
    • Bump actions/dependency-review-action from 4.3.4 to 4.4.0 (#24503)
    • -
    • Bump actions/checkout from 4.2.1 to 4.2.2 (#24488)
    • -
    • Bump agrc/reminder-action from 1.0.14 to 1.0.15 (#24384)
    • -
    • Bump actions/upload-artifact from 4.4.0 to 4.4.3 (#24410)
    • -
    • Update branch for release (#24534)
    • -
    • Revert "Update package references (#24414)" (#24532)
    • -
    • Add a way to use only NuGet feed sources (#24528)
    • -
    • Update PSResourceGet to v1.1.0-RC2 (#24512) (Thanks @alerickson!)
    • -
    • Bump .NET to 9.0.100-rc.2.24474.11 (#24509)
    • -
    • Fix seed max value for Container Linux CI (#24510)
    • -
    • Update metadata.json for 7.2.24 and 7.4.6 releases (#24484)
    • -
    • Download package from package build for generating vpack (#24481)
    • -
    • Keep the roff file when gzipping it. (#24450)
    • -
    • Delete the msix blob if it's already there (#24353)
    • -
    • Add PMC mapping for debian 12 (bookworm) (#24413)
    • -
    • Checkin generated manpage (#24423)
    • -
    • Add CodeQL scanning to APIScan build (#24303)
    • -
    • Update package references (#24414)
    • -
    • Update vpack pipeline (#24281)
    • -
    • Bring changes from v7.5.0-preview.5 Release Branch to Master (#24369)
    • -
    • Bump agrc/create-reminder-action from 1.1.15 to 1.1.16 (#24375)
    • -
    • Add BaseUrl to buildinfo json file (#24376)
    • -
    • Update metadata.json (#24352)
    • -
    • Copy to static site instead of making blob public (#24269)
    • -
    • Update Microsoft.PowerShell.PSResourceGet to 1.1.0-preview2 (#24300) (Thanks @alerickson!)
    • -
    • add updated libicu dependency for debian packages (#24301)
    • -
    • add mapping to azurelinux repo (#24290)
    • -
    • Remove the MD5 branch in the strong name signing token calculation (#24288)
    • -
    • Bump .NET 9 to 9.0.100-rc.1.24452.12 (#24273)
    • -
    • Ensure the official build files CodeQL issues (#24278)
    • -
    • Update experimental-feature json files (#24271)
    • -
    • Make some release tests run in a hosted pools (#24270)
    • -
    • Do not build the exe for Global tool shim project (#24263)
    • -
    • Update and add new NuGet package sources for different environments. (#24264)
    • -
    • Bump skitionek/notify-microsoft-teams (#24261)
    • -
    • Create new pipeline for compliance (#24252)
    • -
    • Capture environment better (#24148)
    • -
    • Add specific path for issues in tsaconfig (#24244)
    • -
    • Use Managed Identity for APIScan authentication (#24243)
    • -
    • Add windows signing for pwsh.exe (#24219)
    • -
    • Bump super-linter/super-linter from 7.0.0 to 7.1.0 (#24223)
    • -
    • Update the URLs used in nuget.config files (#24203)
    • -
    • Check Create and Submit in vPack build by default (#24181)
    • -
    • Replace PSVersion source generator with incremental one (#23815) (Thanks @iSazonov!)
    • -
    • Save man files in /usr/share/man instead of /usr/local/share/man (#23855) (Thanks @rzippo!)
    • -
    • Bump super-linter/super-linter from 6.8.0 to 7.0.0 (#24169)
    • -
    - -
    - -### Documentation and Help Content - -- Updated Third Party Notices (#24666) -- Update `HelpInfoUri` for 7.5 (#24610) -- Update changelog for v7.4.6 release (#24496) -- Update to the latest NOTICES file (#24259) -- Update the changelog `preview.md` (#24213) -- Update changelog readme with 7.4 (#24182) (Thanks @ThomasNieto!) -- Fix Markdown linting error (#24204) -- Updated changelog for v7.2.23 (#24196) (Internal 32131) -- Update changelog and `metadata.json` for v7.4.5 release (#24183) -- Bring 7.2 changelogs back to master (#24158) - -[7.6.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-rc.1...v7.6.0-preview.1 From 8947ed62e6293a425a5b97e4d9791476ea7bf30c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:58:55 +0000 Subject: [PATCH 318/378] release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27074) --- .../templates/release-upload-buildinfo.yml | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c470af1fd6e..9e3d6a6accb 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -51,14 +51,17 @@ jobs: Import-Module "$toolsDirectory/ci.psm1" $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" $fileName = Split-Path $jsonFile -Leaf + # The build itself has already determined if it is preview or stable/LTS, + # we just need to check via the file name + $isPreview = $fileName -eq "preview.json" + $isStable = $fileName -eq "stable.json" $dateTime = [datetime]::UtcNow $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' - - $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' + # Note: version tags in metadata.json (e.g. StableReleaseTag) may not reflect the current release being + # published, so they must not be used to gate channel decisions. Use the explicit publish flags instead. $stableRelease = $metadata.StableRelease.PublishToChannels $ltsRelease = $metadata.LTSRelease.PublishToChannels @@ -73,7 +76,7 @@ jobs: $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($fileName -eq "preview.json") { + if ($isPreview) { Set-BuildVariable -Name UploadPreview -Value YES } else { Set-BuildVariable -Name UploadPreview -Value NO @@ -82,9 +85,7 @@ jobs: Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile ## Create 'lts.json' if marked as a LTS release. - if ($fileName -eq "stable.json") { - [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag - [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + if ($isStable) { if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force @@ -94,18 +95,24 @@ jobs: Set-BuildVariable -Name UploadLTS -Value NO } - ## Only update the stable.json if the current version is greater than the stable version. - if ($currentVersion -gt $stableVersion) { - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + ## Gate stable.json upload on the metadata publish flag. + if ($stableRelease) { + Set-BuildVariable -Name StableBuildInfoFile -Value $targetFile Set-BuildVariable -Name UploadStable -Value YES } else { Set-BuildVariable -Name UploadStable -Value NO } + ## Always publish the version-specific {Major}-{Minor}.json for non-preview builds. + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name VersionSpecificBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadVersionSpecific -Value YES + } else { Set-BuildVariable -Name UploadStable -Value NO + Set-BuildVariable -Name UploadVersionSpecific -Value NO } displayName: Create json files @@ -146,4 +153,12 @@ jobs: Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) + + #version-specific + if ($env:UploadVersionSpecific -eq 'YES') { + $jsonFile = "$env:VersionSpecificBuildInfoFile" + $blobName = Get-Item $jsonFile | Split-Path -Leaf + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force + } + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'), eq(variables['UploadVersionSpecific'], 'YES'))) From 1e5c02074d6d98a1b11851ddcc09332aca6c1aa1 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 20 Mar 2026 15:44:53 -0700 Subject: [PATCH 319/378] Update the `PhoneProductId` to be the official LTS id used by Store (#27077) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index baab911f60d..d420ceb620d 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4314,7 +4314,7 @@ function New-MSIXPackage Write-Verbose "Using Preview assets" -Verbose } elseif ($LTS) { # This is the PhoneProductId for the "Microsoft.PowerShell-LTS" package. - $PhoneProductId = "a9af273a-c636-47ac-bc2a-775edf80b2b9" + $PhoneProductId = "b7a4b003-3704-47a9-b018-cfcc9801f4fc" Write-Verbose "Using LTS assets" -Verbose } From c11d721165e823f74845db09e9d14a88d5b62373 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:27:35 -0400 Subject: [PATCH 320/378] Bump github/codeql-action from 4.32.6 to 4.34.1 (#27087) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 21966cb855c..dfe565b0319 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 7e868e10dbf..7bd7bf6314d 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: sarif_file: results.sarif From f9be17e6b5c9ac58c187cb29c43c1af65967e8c8 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:37:51 -0500 Subject: [PATCH 321/378] Separate Official and NonOfficial templates for ADO pipelines (#26897) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/agents/SplitADOPipelines.agent.md | 164 ++++++++ ...Shell-Coordinated_Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Release-Azure-NonOfficial.yml | 76 ++++ .../PowerShell-Release-NonOfficial.yml | 106 ++++++ .../PowerShell-vPack-NonOfficial.yml | 88 +++++ ...werShell-Coordinated_Packages-Official.yml | 247 +----------- .pipelines/PowerShell-Packages-Official.yml | 227 +---------- .../PowerShell-Release-Official-Azure.yml | 34 +- .pipelines/PowerShell-Release-Official.yml | 358 +----------------- .pipelines/PowerShell-vPack-Official.yml | 268 +------------ .pipelines/templates/release-MSIX-Publish.yml | 2 +- .pipelines/templates/release-githubNuget.yml | 4 +- ...PowerShell-Coordinated_Packages-Stages.yml | 202 ++++++++++ .../stages/PowerShell-Packages-Stages.yml | 186 +++++++++ .../stages/PowerShell-Release-Stages.yml | 323 ++++++++++++++++ .../stages/PowerShell-vPack-Stages.yml | 236 ++++++++++++ ...erShell-Coordinated_Packages-Variables.yml | 67 ++++ .../PowerShell-Packages-Variables.yml | 50 +++ .../PowerShell-Release-Azure-Variables.yml | 35 ++ .../PowerShell-Release-Variables.yml | 41 ++ .../variables/PowerShell-vPack-Variables.yml | 39 ++ .../release-shared.yml | 0 23 files changed, 1858 insertions(+), 1089 deletions(-) create mode 100644 .github/agents/SplitADOPipelines.agent.md create mode 100644 .pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml create mode 100644 .pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Release-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-vPack-Stages.yml create mode 100644 .pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-vPack-Variables.yml rename .pipelines/templates/{variable => variables}/release-shared.yml (100%) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md new file mode 100644 index 00000000000..8322f473e7b --- /dev/null +++ b/.github/agents/SplitADOPipelines.agent.md @@ -0,0 +1,164 @@ +--- +name: SplitADOPipelines +description: This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. +tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] +--- + +This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. + +A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. + +First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this + +```yaml +parameters: + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} +``` + +Followed by: + +```yaml +extends: + template: ${{ variables.templateFile }} +``` + +This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. + +## Refactoring Steps + +### Step 1: Extract Shared Templates + +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): + +1. Create a `./pipelines/templates` directory if it doesn't exist +2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` + +**IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. + +### Step 2: Create Official Pipeline (In-Place Refactoring) + +The original toggle-based file becomes the Official pipeline: + +1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +2. Remove the toggle switch parameter (`templateFile` parameter) +3. Hard-code the Official template reference: + ```yaml + extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates + ``` +4. Replace the `variables:` section with a template reference: + ```yaml + variables: + - template: templates/PowerShell-Packages-Variables.yml + ``` +5. Replace the `stages:` section with a template reference: + ```yaml + stages: + - template: templates/PowerShell-Packages-Stages.yml + ``` + +### Step 3: Create NonOfficial Pipeline + +1. Create `./pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +3. Copy the structure from the refactored Official pipeline +4. Hard-code the NonOfficial template reference: + ```yaml + extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + ``` +5. Reference the same shared templates: + ```yaml + variables: + - template: ../templates/PowerShell-Packages-Variables.yml + + stages: + - template: ../templates/PowerShell-Packages-Stages.yml + ``` + +**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. + +### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies + +After creating NonOfficial pipelines, ensure they consume artifacts from other **NonOfficial** pipelines, not Official ones. + +1. **Check the `resources:` section** in each NonOfficial pipeline for `pipelines:` dependencies +2. **Identify Official pipeline references** that need to be changed to NonOfficial +3. **Update the `source:` field** to point to the NonOfficial version + +**Example Problem:** NonOfficial pipeline pointing to Official dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-Official' # ❌ Wrong - Official! +``` + +**Solution:** Update to NonOfficial dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-NonOfficial' # ✅ Correct - NonOfficial! +``` + +**IMPORTANT**: The `source:` field must match the **exact ADO pipeline definition name** as it appears in Azure DevOps, not necessarily the file name. + +### Step 5: Configure Release Environment Parameters (NonAzure Only) + +**This step only applies if the pipeline uses `category: NonAzure` in the release configuration.** + +If you detect this pattern in the original pipeline: + +```yaml +extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates # or NonOfficial + parameters: + release: + category: NonAzure +``` + +Then you must configure the `ob_release_environment` parameter when referencing the stages template. + +#### Official Pipeline Configuration + +In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): + +```yaml +stages: + - template: templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Production +``` + +#### NonOfficial Pipeline Configuration + +In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): + +```yaml +stages: + - template: ../templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Test +``` + +#### Update Stages Template to Accept Parameter + +The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: + +```yaml +parameters: + - name: ob_release_environment + type: string + +stages: + # ... rest of stages configuration using ${{ parameters.ob_release_environment }} +``` + +**IMPORTANT**: +- Only configure this for pipelines with `category: NonAzure` +- Official pipelines always use `ob_release_environment: Production` +- NonOfficial pipelines always use `ob_release_environment: Test` +- The stages template must accept this parameter and use it in the appropriate stage configurations diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml new file mode 100644 index 00000000000..55d4c4557d8 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Debugging - Skip Signing + type: string + default: 'NO' + - name: RUN_TEST_AND_RELEASE + displayName: Debugging - Run Test and Release Artifacts Stage + type: boolean + default: true + - name: RUN_WINDOWS + displayName: Debugging - Enable Windows Stage + type: boolean + default: true + - name: ENABLE_MSBUILD_BINLOGS + displayName: Debugging - Enable MSBuild Binary Logs + type: boolean + default: false + - name: FORCE_CODEQL + displayName: Debugging - Enable CodeQL and set cadence to 1 hour + type: boolean + default: false + +name: bins-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance + ref: master + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +variables: + - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + customTags: 'ES365AIMigrationTooling' + featureFlags: + LinuxHostVersion: + Network: KS3 + WindowsHostVersion: + Network: KS3 + incrementalSDLBinaryAnalysis: true + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: true # This enables TSA bug filing only for CodeQL 3000 + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml new file mode 100644 index 00000000000..81f343a04a0 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: ForceAzureBlobDelete + displayName: Delete Azure Blob + type: string + values: + - true + - false + default: false + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: disableNetworkIsolation + type: boolean + default: false + +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} + +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + cloudvault: + enabled: false + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + LinuxHostVersion: + Network: KS3 + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + disableNetworkIsolation: ${{ variables.disableNetworkIsolation }} + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml new file mode 100644 index 00000000000..681babb2220 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -0,0 +1,76 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: skipPublish + displayName: Skip PMC Publish + type: boolean + default: false + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + +name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: Netlock + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: /.pipelines/templates/release-prep-for-ev2.yml@self + parameters: + skipPublish: ${{ parameters.skipPublish }} + + - template: /.pipelines/templates/release-publish-pmc.yml@self diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml new file mode 100644 index 00000000000..ca5a6383f33 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -0,0 +1,106 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: SkipPublish + displayName: Skip Publishing to Nuget + type: boolean + default: false + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false + - name: skipMSIXPublish + displayName: Skip MSIX Publish + type: boolean + default: false + +name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + - repository: PSInternalTools + type: git + name: PowerShellCore/Internal-PowerShellTeam-Tools + ref: refs/heads/master + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + # NOTE: The alias name "PSPackagesOfficial" is intentionally reused here even + # for the NonOfficial pipeline source. Downstream shared templates (for example, + # release-validate-sdk.yml and release-upload-buildinfo.yml) reference artifacts + # using `download: PSPackagesOfficial`, so changing this alias would break them. + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + release: + category: NonAzure + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + # suppression: + # suppressionFile: $(Build.SourcesDirectory)\.gdn\global.gdnsuppress + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Test + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml new file mode 100644 index 00000000000..642b169adaf --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -0,0 +1,88 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'createVPack' + displayName: 'Create and Submit VPack' + type: boolean + default: true +- name: vPackName + type: string + displayName: 'VPack Name:' + default: 'PowerShell.BuildTool' + values: + - PowerShell.BuildTool + - PowerShell + - PowerShellDoNotUse +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" + +name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) + +variables: + - template: ../templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/Microsoft.NonOfficial.yml@onebranchTemplates + parameters: + platform: + name: 'windows_undocked' # windows undocked + + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + + cloudvault: + enabled: false + + globalSdl: + useCustomPolicy: true # for signing code + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config/tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 12460e2861c..82f129a0a5e 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -30,7 +30,7 @@ parameters: type: boolean default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) resources: repositories: @@ -45,57 +45,13 @@ resources: ref: refs/heads/main variables: - - name: PS_RELEASE_BUILD - value: 1 - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - name: BUILDSECMON_OPT_IN - value: true - - name: __DOTNET_RUNTIME_FEED - value: ${{ parameters.InternalSDKBlobURL }} - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: SKIP_SIGNING - value: ${{ parameters.SKIP_SIGNING }} - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: ENABLE_MSBUILD_BINLOGS - value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} - - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: - # Cadence is hours before CodeQL will allow a re-upload of the database - - name: CodeQL.Cadence - value: 1 - - name: CODEQL_ENABLED - ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: - value: true - ${{ else }}: - value: false - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true - # Disable BinSkim at job level to override NonOfficial template defaults - - name: ob_sdl_binskim_enabled - value: false - - name: ps_official_build - value: true + - template: templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} extends: template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates @@ -135,185 +91,8 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - jobs: - - job: SetVars - displayName: Set Variables - pool: - type: linux - - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_codeql_compiled_enabled - value: false - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_signing_setup_enabled - value: false - - name: ob_sdl_sbom_enabled - value: false - - steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - pwsh: | - Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture environment variables - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - stage: macos - displayName: macOS - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: x64 - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: arm64 - - - stage: linux - displayName: linux - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64_minSize' - BuildConfiguration: 'minSize' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm' - JobName: 'linux_arm' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm64' - JobName: 'linux_arm64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-x64' - JobName: 'linux_fxd_x64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-arm64' - JobName: 'linux_fxd_arm64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-noopt-linux-musl-x64' - JobName: 'linux_fxd_x64_alpine' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent' - JobName: 'linux_fxd' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-musl-x64' - JobName: 'linux_x64_alpine' - - - stage: windows - displayName: windows - build and sign - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) - jobs: - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: release - JobName: build_windows_x64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: minSize - JobName: build_windows_x64_minSize_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x86 - JobName: build_windows_x86_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: arm64 - JobName: build_windows_arm64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependent - JobName: build_windows_fxdependent_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependentWinDesktop - JobName: build_windows_fxdependentWinDesktop_release - - - stage: test_and_release_artifacts - displayName: Test and Release Artifacts - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) - jobs: - - template: /.pipelines/templates/testartifacts.yml@self - - - job: release_json - displayName: Create and Upload release.json - pool: - type: windows - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - steps: - - checkout: self - clean: true - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - template: /.pipelines/templates/rebuild-branch-check.yml@self - - powershell: | - $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - - # Use the rebuild branch check from the template - $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' - - # Don't mark as LTS release for rebuild branches - $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch - - if ($isRebuildBranch) { - Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose - } - - @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" - Get-Content "$(Build.StagingDirectory)\release.json" - - if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { - New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" - } - - Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force - displayName: Create and upload release.json file to build artifact - retryCountOnTaskFailure: 2 - - template: /.pipelines/templates/step/finalize.yml@self + - template: templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: true diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index a13ef12378a..8afce29ede7 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -28,44 +28,15 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] # needed for onebranch.pipeline.version task - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: ForceAzureBlobDelete - value: ${{ parameters.ForceAzureBlobDelete }} - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - group: MSIXSigningProfile - - name: disableNetworkIsolation - value: ${{ parameters.disableNetworkIsolation }} + - template: templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} resources: pipelines: @@ -121,184 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - displayName: 'Prep BuildInfo+Az' - jobs: - - template: /.pipelines/templates/checkAzureContainer.yml@self - - - stage: mac_package - displayName: 'macOS Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: x64 - - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: arm64 - - - stage: windows_package_build - displayName: 'Win Pkg (unsigned)' - dependsOn: [] - jobs: - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: minsize - - - stage: windows_package_sign - displayName: 'Win Pkg Sign' - dependsOn: [windows_package_build] - jobs: - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: minsize - - - stage: linux_package - displayName: 'Linux Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: deb - jobName: deb - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' - packageType: rpm-fxdependent #mariner-x64 - jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' - packageType: rpm-fxdependent-arm64 #mariner-arm64 - jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: rpm - jobName: rpm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm' - signedDrop: 'drop_linux_sign_linux_arm' - packageType: tar-arm - jobName: tar_arm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm64' - signedDrop: 'drop_linux_sign_linux_arm64' - packageType: tar-arm64 - jobName: tar_arm64 - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_alpine' - signedDrop: 'drop_linux_sign_linux_x64_alpine' - packageType: tar-alpine - jobName: tar_alpine - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd' - signedDrop: 'drop_linux_sign_linux_fxd' - packageType: fxdependent - jobName: fxdependent - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: tar - jobName: tar - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' - signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' - packageType: tar-alpine-fxdependent - jobName: tar_alpine_fxd - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_minSize' - signedDrop: 'drop_linux_sign_linux_x64_minSize' - packageType: min-size - jobName: minSize - - - stage: nupkg - displayName: 'NuGet Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/nupkg.yml@self - - - stage: msixbundle - displayName: 'MSIX Bundle+Sign' - dependsOn: [windows_package_build] # Only depends on unsigned packages - jobs: - - template: /.pipelines/templates/package-create-msix.yml@self - parameters: - OfficialBuild: true - - - stage: upload - displayName: 'Upload' - dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON - jobs: - - template: /.pipelines/templates/uploadToAzure.yml@self - - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [upload] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self + - template: templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 81543420460..24040a2463d 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -14,38 +14,12 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: string default: 'NO' -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\.config\tsaoptions.json - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: PoolNames + - template: templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} resources: repositories: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index fa14b9b0acb..3528e6b1471 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -30,43 +30,13 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: PoolNames - - name: releaseEnvironment - value: 'Production' - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true + - template: templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} resources: repositories: @@ -124,315 +94,9 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: setReleaseTagAndChangelog - displayName: 'Set Release Tag and Upload Changelog' - jobs: - - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self - - - stage: validateSdk - displayName: 'Validate SDK' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "windowsSDK" - displayName: "Windows SDK Validation" - imageName: PSMMS2019-Secure - poolName: $(windowsPool) - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "MacOSSDK" - displayName: "MacOS SDK Validation" - imageName: macOS-latest - poolName: Azure Pipelines - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "LinuxSDK" - displayName: "Linux SDK Validation" - imageName: PSMMSUbuntu22.04-Secure - poolName: $(ubuntuPool) - - - stage: gbltool - displayName: 'Validate Global tools' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "WindowsGlobalTools" - displayName: "Windows Global Tools Validation" - jobtype: windows - - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "LinuxGlobalTools" - displayName: "Linux Global Tools Validation" - jobtype: linux - globalToolExeName: 'pwsh' - globalToolPackageName: 'PowerShell.Linux.x64' - - - stage: fxdpackages - displayName: 'Validate FXD Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxd' - displayName: 'Validate Win Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependent' - packageNamePattern: '**/*win-fxdependent.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxdDesktop' - displayName: 'Validate WinDesktop Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' - packageNamePattern: '**/*win-fxdependentwinDesktop.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxfxd' - displayName: 'Validate Linux Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxArm64fxd' - displayName: 'Validate Linux ARM64 Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - # this is really an architecture independent package - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - arm64: 'yes' - enableCredScan: false - - - stage: ManualValidation - dependsOn: [] - displayName: Manual Validation - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate Windows Packages - jobName: ValidateWinPkg - instructions: | - Validate zip package on windows - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate OSX Packages - jobName: ValidateOsxPkg - instructions: | - Validate tar.gz package on osx-arm64 - - - stage: ReleaseAutomation - dependsOn: [] - displayName: 'Release Automation' - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start Release Automation - jobName: StartRA - instructions: | - Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Triage results - jobName: TriageRA - dependsOnJob: StartRA - instructions: | - Triage ReleaseAutomation results - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Signoff Tests - dependsOnJob: TriageRA - jobName: SignoffTests - instructions: | - Signoff ReleaseAutomation results - - - stage: UpdateChangeLog - displayName: Update the changelog - dependsOn: - - ManualValidation - - ReleaseAutomation - - fxdpackages - - gbltool - - validateSdk - - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure the changelog is updated - jobName: MergeChangeLog - instructions: | - Update and merge the changelog for the release. - This step is required for creating GitHub draft release. - - - stage: PublishGitHubReleaseAndNuget - displayName: Publish GitHub and Nuget Release - dependsOn: - - setReleaseTagAndChangelog - - UpdateChangeLog - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-githubNuget.yml@self - parameters: - skipPublish: ${{ parameters.SkipPublish }} - - - stage: PushGitTagAndMakeDraftPublic - displayName: Push Git Tag and Make Draft Public - dependsOn: PublishGitHubReleaseAndNuget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Push Git Tag - jobName: PushGitTag - instructions: | - Push the git tag to upstream - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make Draft Public - dependsOnJob: PushGitTag - jobName: DraftPublic - instructions: | - Make the GitHub Release Draft Public - - - stage: BlobPublic - displayName: Make Blob Public - dependsOn: - - UpdateChangeLog - - PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/release-MakeBlobPublic.yml@self - parameters: - SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - - - stage: PublishPMC - displayName: Publish PMC - dependsOn: PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Publish to PMC - jobName: ReleaseToPMC - instructions: | - Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC - - - stage: UpdateDotnetDocker - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Update DotNet SDK Docker images - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Update .NET SDK docker images - jobName: DotnetDocker - instructions: | - Create PR for updating dotnet-docker images to use latest PowerShell version. - 1. Fork and clone https://github.com/dotnet/dotnet-docker.git - 2. git checkout upstream/nightly -b updatePS - 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas - 4. create PR targeting nightly branch - - - stage: UpdateWinGet - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Add manifest entry to winget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Add manifest entry to winget - jobName: UpdateWinGet - instructions: | - This is typically done by the community 1-2 days after the release. - - - stage: PublishMsix - dependsOn: - - setReleaseTagAndChangelog - - PushGitTagAndMakeDraftPublic - displayName: Publish MSIX to store - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-MSIX-Publish.yml@self - parameters: - skipMSIXPublish: ${{ parameters.skipMSIXPublish }} - - - stage: PublishVPack - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release vPack - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start 2 vPack Release pipelines - jobName: PublishVPack - instructions: | - 1. Kick off PowerShell-vPack-Official pipeline - 2. Kick off PowerShell-MSIXBundle-VPack pipeline - - # Need to verify if the Az PS / CLI team still uses this. Skippinng for this release. - # - stage: ReleaseDeps - # dependsOn: GitHubTasks - # displayName: Update pwsh.deps.json links - # jobs: - # - template: templates/release-UpdateDepsJson.yml - - - stage: UploadBuildInfoJson - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Upload BuildInfo.json - jobs: - - template: /.pipelines/templates/release-upload-buildinfo.yml@self - - - stage: ReleaseSymbols - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release Symbols - jobs: - - template: /.pipelines/templates/release-symbols.yml@self - - - stage: ChangesToMaster - displayName: Ensure changes are in GH master - dependsOn: - - PublishPMC - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure changes are in master - jobName: MergeToMaster - instructions: | - Make sure that changes README.md and metadata.json are merged into master on GitHub. - - - stage: ReleaseToMU - displayName: Release to MU - dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Release to MU - instructions: | - Notify the PM team to start the process of releasing to MU. - - - stage: ReleaseClose - displayName: Finish Release - dependsOn: - - ReleaseToMU - - ReleaseSymbols - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Retain Build - jobName: RetainBuild - instructions: | - Retain the build - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Delete release branch - jobName: DeleteBranch - instructions: | - Delete release + - template: templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Production + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index c49560bf2b8..13087fbbf65 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -30,37 +30,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: BuildSolution - value: $(Build.SourcesDirectory)\dirs.proj - - name: BuildConfiguration - value: Release - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: Codeql.Enabled - value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: Azure Blob variable group - - group: certificate_logical_to_actual # used within signing task - - group: DotNetPrivateBuildAccess - - group: certificate_logical_to_actual - - name: netiso - value: ${{ parameters.netiso }} -# We shouldn't be using PATs anymore -# - group: mscodehub-feed-read-general + - template: templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} resources: repositories: @@ -105,232 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - stage: BuildStage - jobs: - - job: BuildJob - pool: - type: windows - - strategy: - matrix: - x86: - architecture: x86 - - x64: - architecture: x64 - - arm64: - architecture: arm64 - - variables: - ArtifactPlatform: 'windows' - ob_artifactBaseName: drop_build_$(architecture) - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_owneralias: tplunk - ob_createvpack_versionAs: parts - ob_createvpack_propsFile: true - ob_createvpack_verbose: true - ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' - ob_createvpack_description: PowerShell $(architecture) $(version) - # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ - ob_createvpack_majorVer: $(pwshMajorVersion) - ob_createvpack_minorVer: $(pwshMinorVersion) - ob_createvpack_patchVer: $(pwshPatchVersion) - ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: - ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) - ${{ else }}: - ob_createvpack_prereleaseVer: $(Build.SourceVersion) - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s - env: - ob_restore_phase: true - - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - pwsh: | - $version = '$(Version)' - Write-Verbose -Verbose "Version: $version" - if(!$version) { - throw "Version is not set." - } - - $mainVersionParts = $version -split '-' - - Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" - $versionParts = $mainVersionParts[0] -split '[.]'; - $major = $versionParts[0] - $minor = $versionParts[1] - $patch = $versionParts[2] - - $previewPart = $mainVersionParts[1] - Write-Verbose -Verbose "previewPart: $previewPart" - - Write-Host "major: $major; minor: $minor; patch: $patch;" - - $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - if($previewPart) { - $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" - } else { - Write-Verbose -Verbose "No prerelease part found in version string." - } - displayName: Set ob_createvpack_*Ver - env: - ob_restore_phase: true - - # Validate pwsh*Version variables - - pwsh: | - $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") - foreach ($var in $variables) { - if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { - throw "Required variable '`$env:$var' is not set." - } - } - displayName: Validate pwsh*Version variables - env: - ob_restore_phase: true - - - pwsh: | - if($env:RELEASETAGVAR -match '-') { - throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" - } - displayName: Stop any preview release - env: - ob_restore_phase: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.ToolsDirectory)/dotnet - - ### BUILD ### - - - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(repoRoot) - - - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - inputs: - Enabled: true - AnalyzeInPipeline: false # Do not upload results - Language: csharp - - - task: UseDotNet@2 - displayName: 'Install .NET based on global.json' - inputs: - useGlobalJson: true - workingDirectory: $(repoRoot) - env: - ob_restore_phase: true - - - pwsh: | - # Need to set PowerShellRoot variable for obp-file-signing template - $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $Architecture = '$(Architecture)' - $runtime = switch ($Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - } - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" - Import-Module -Name $(repoRoot)/build.psm1 -Force - $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force - - Start-PSBootstrap -Scenario Package - $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose - - $ReleaseTagParam = @{} - - if ($env:RELEASETAGVAR) { - $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR - } - - Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam - - $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' - Write-Verbose -Verbose "refFolderPath: $refFolderPath" - $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' - $null = New-Item -ItemType Directory -Path $outputPath -Force - $psOptPath = "$outputPath/psoptions.json" - Save-PSOptions -PSOptionsPath $psOptPath - - Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" - displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\src' - ob_restore_phase: true - - - template: /.pipelines/templates/obp-file-signing.yml@self - parameters: - binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' - SigningProfile: $(windows_build_tools_cert_id) - OfficialBuild: false - vPackScenario: true - - ### END OF BUILD ### - - - pwsh: | - Get-ChildItem env:/ob_createvpack_*Ver - Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host - displayName: Debug Output Directory and Version - condition: succeededOrFailed() - - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture Environment - condition: succeededOrFailed() - - - pwsh: | - $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" - } - $vpackFiles - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - template: templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index a92c71f826b..aaef3c6f269 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -21,7 +21,7 @@ jobs: value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] - name: PREVIEW value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 206079c555f..95698554c40 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -17,7 +17,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] @@ -167,7 +167,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] diff --git a/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml new file mode 100644 index 00000000000..cd0a4ebc065 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml @@ -0,0 +1,202 @@ +parameters: + - name: RUN_WINDOWS + type: boolean + default: true + - name: RUN_TEST_AND_RELEASE + type: boolean + default: true + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + jobs: + - job: SetVars + displayName: Set Variables + pool: + type: linux + + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_codeql_compiled_enabled + value: false + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_sbom_enabled + value: false + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment variables + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + +- stage: macos + displayName: macOS - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: x64 + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: arm64 + +- stage: linux + displayName: linux - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64_minSize' + BuildConfiguration: 'minSize' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm' + JobName: 'linux_arm' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm64' + JobName: 'linux_arm64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-x64' + JobName: 'linux_fxd_x64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-arm64' + JobName: 'linux_fxd_arm64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-noopt-linux-musl-x64' + JobName: 'linux_fxd_x64_alpine' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent' + JobName: 'linux_fxd' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-musl-x64' + JobName: 'linux_x64_alpine' + +- stage: windows + displayName: windows - build and sign + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: release + JobName: build_windows_x64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: minSize + JobName: build_windows_x64_minSize_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x86 + JobName: build_windows_x86_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: arm64 + JobName: build_windows_arm64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependent + JobName: build_windows_fxdependent_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependentWinDesktop + JobName: build_windows_fxdependentWinDesktop_release + +- stage: test_and_release_artifacts + displayName: Test and Release Artifacts + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) + jobs: + - template: /.pipelines/templates/testartifacts.yml@self + + - job: release_json + displayName: Create and Upload release.json + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + steps: + - checkout: self + clean: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self + - powershell: | + $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" + Get-Content "$(Build.StagingDirectory)\release.json" + + if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { + New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" + } + + Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force + displayName: Create and upload release.json file to build artifact + retryCountOnTaskFailure: 2 + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml new file mode 100644 index 00000000000..ff40941e31b --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -0,0 +1,186 @@ +parameters: + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + displayName: 'Prep BuildInfo+Az' + jobs: + - template: /.pipelines/templates/checkAzureContainer.yml@self + +- stage: mac_package + displayName: 'macOS Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: x64 + + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: arm64 + +- stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] + jobs: + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + +- stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: minsize + +- stage: linux_package + displayName: 'Linux Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: deb + jobName: deb + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' + packageType: rpm-fxdependent #mariner-x64 + jobName: mariner_x64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' + packageType: rpm-fxdependent-arm64 #mariner-arm64 + jobName: mariner_arm64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: rpm + jobName: rpm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm' + signedDrop: 'drop_linux_sign_linux_arm' + packageType: tar-arm + jobName: tar_arm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm64' + signedDrop: 'drop_linux_sign_linux_arm64' + packageType: tar-arm64 + jobName: tar_arm64 + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_alpine' + signedDrop: 'drop_linux_sign_linux_x64_alpine' + packageType: tar-alpine + jobName: tar_alpine + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd' + signedDrop: 'drop_linux_sign_linux_fxd' + packageType: fxdependent + jobName: fxdependent + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: tar + jobName: tar + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' + signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' + packageType: tar-alpine-fxdependent + jobName: tar_alpine_fxd + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_minSize' + signedDrop: 'drop_linux_sign_linux_x64_minSize' + packageType: min-size + jobName: minSize + +- stage: nupkg + displayName: 'NuGet Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/nupkg.yml@self + +- stage: msixbundle + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages + jobs: + - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} + +- stage: upload + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON + jobs: + - template: /.pipelines/templates/uploadToAzure.yml@self + +- stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Release-Stages.yml b/.pipelines/templates/stages/PowerShell-Release-Stages.yml new file mode 100644 index 00000000000..52ce428a663 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Release-Stages.yml @@ -0,0 +1,323 @@ +parameters: + - name: releaseEnvironment + type: string + - name: SkipPublish + type: boolean + - name: SkipPSInfraInstallers + type: boolean + - name: skipMSIXPublish + type: boolean + +stages: +- stage: setReleaseTagAndChangelog + displayName: 'Set Release Tag and Upload Changelog' + jobs: + - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self + +- stage: validateSdk + displayName: 'Validate SDK' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "windowsSDK" + displayName: "Windows SDK Validation" + imageName: PSMMS2019-Secure + poolName: $(windowsPool) + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "MacOSSDK" + displayName: "MacOS SDK Validation" + imageName: macOS-latest + poolName: Azure Pipelines + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "LinuxSDK" + displayName: "Linux SDK Validation" + imageName: PSMMSUbuntu22.04-Secure + poolName: $(ubuntuPool) + +- stage: gbltool + displayName: 'Validate Global tools' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "WindowsGlobalTools" + displayName: "Windows Global Tools Validation" + jobtype: windows + + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "LinuxGlobalTools" + displayName: "Linux Global Tools Validation" + jobtype: linux + globalToolExeName: 'pwsh' + globalToolPackageName: 'PowerShell.Linux.x64' + +- stage: fxdpackages + displayName: 'Validate FXD Packages' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxd' + displayName: 'Validate Win Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependent' + packageNamePattern: '**/*win-fxdependent.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxdDesktop' + displayName: 'Validate WinDesktop Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' + packageNamePattern: '**/*win-fxdependentwinDesktop.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxfxd' + displayName: 'Validate Linux Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxArm64fxd' + displayName: 'Validate Linux ARM64 Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + # this is really an architecture independent package + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + arm64: 'yes' + enableCredScan: false + +- stage: ManualValidation + dependsOn: [] + displayName: Manual Validation + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate Windows Packages + jobName: ValidateWinPkg + instructions: | + Validate zip package on windows + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate OSX Packages + jobName: ValidateOsxPkg + instructions: | + Validate tar.gz package on osx-arm64 + +- stage: ReleaseAutomation + dependsOn: [] + displayName: 'Release Automation' + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start Release Automation + jobName: StartRA + instructions: | + Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Triage results + jobName: TriageRA + dependsOnJob: StartRA + instructions: | + Triage ReleaseAutomation results + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Signoff Tests + dependsOnJob: TriageRA + jobName: SignoffTests + instructions: | + Signoff ReleaseAutomation results + +- stage: UpdateChangeLog + displayName: Update the changelog + dependsOn: + - ManualValidation + - ReleaseAutomation + - fxdpackages + - gbltool + - validateSdk + + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure the changelog is updated + jobName: MergeChangeLog + instructions: | + Update and merge the changelog for the release. + This step is required for creating GitHub draft release. + +- stage: PublishGitHubReleaseAndNuget + displayName: Publish GitHub and Nuget Release + dependsOn: + - setReleaseTagAndChangelog + - UpdateChangeLog + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-githubNuget.yml@self + parameters: + skipPublish: ${{ parameters.SkipPublish }} + +- stage: PushGitTagAndMakeDraftPublic + displayName: Push Git Tag and Make Draft Public + dependsOn: PublishGitHubReleaseAndNuget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Push Git Tag + jobName: PushGitTag + instructions: | + Push the git tag to upstream + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make Draft Public + dependsOnJob: PushGitTag + jobName: DraftPublic + instructions: | + Make the GitHub Release Draft Public + +- stage: BlobPublic + displayName: Make Blob Public + dependsOn: + - UpdateChangeLog + - PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/release-MakeBlobPublic.yml@self + parameters: + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + +- stage: PublishPMC + displayName: Publish PMC + dependsOn: PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Publish to PMC + jobName: ReleaseToPMC + instructions: | + Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC + +- stage: UpdateDotnetDocker + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Update DotNet SDK Docker images + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Update .NET SDK docker images + jobName: DotnetDocker + instructions: | + Create PR for updating dotnet-docker images to use latest PowerShell version. + 1. Fork and clone https://github.com/dotnet/dotnet-docker.git + 2. git checkout upstream/nightly -b updatePS + 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas + 4. create PR targeting nightly branch + +- stage: UpdateWinGet + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Add manifest entry to winget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Add manifest entry to winget + jobName: UpdateWinGet + instructions: | + This is typically done by the community 1-2 days after the release. + +- stage: PublishMsix + dependsOn: + - setReleaseTagAndChangelog + - PushGitTagAndMakeDraftPublic + displayName: Publish MSIX to store + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-MSIX-Publish.yml@self + parameters: + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} + +- stage: PublishVPack + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release vPack + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start 2 vPack Release pipelines + jobName: PublishVPack + instructions: | + 1. Kick off PowerShell-vPack-Official pipeline + 2. Kick off PowerShell-MSIXBundle-VPack pipeline + +# Need to verify if the Az PS / CLI team still uses this. Skipping for this release. +# - stage: ReleaseDeps +# dependsOn: GitHubTasks +# displayName: Update pwsh.deps.json links +# jobs: +# - template: templates/release-UpdateDepsJson.yml + +- stage: UploadBuildInfoJson + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Upload BuildInfo.json + jobs: + - template: /.pipelines/templates/release-upload-buildinfo.yml@self + +- stage: ReleaseSymbols + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release Symbols + jobs: + - template: /.pipelines/templates/release-symbols.yml@self + +- stage: ChangesToMaster + displayName: Ensure changes are in GH master + dependsOn: + - PublishPMC + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure changes are in master + jobName: MergeToMaster + instructions: | + Make sure that changes README.md and metadata.json are merged into master on GitHub. + +- stage: ReleaseToMU + displayName: Release to MU + dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Release to MU + instructions: | + Notify the PM team to start the process of releasing to MU. + +- stage: ReleaseClose + displayName: Finish Release + dependsOn: + - ReleaseToMU + - ReleaseSymbols + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Retain Build + jobName: RetainBuild + instructions: | + Retain the build + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Delete release branch + jobName: DeleteBranch + instructions: | + Delete release branch diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml new file mode 100644 index 00000000000..f0d49e8b489 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -0,0 +1,236 @@ +parameters: + - name: createVPack + type: boolean + - name: vPackName + type: string + +stages: +- stage: BuildStage + jobs: + - job: BuildJob + pool: + type: windows + + strategy: + matrix: + x86: + architecture: x86 + + x64: + architecture: x64 + + arm64: + architecture: arm64 + + variables: + ArtifactPlatform: 'windows' + ob_artifactBaseName: drop_build_$(architecture) + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_owneralias: tplunk + ob_createvpack_versionAs: parts + ob_createvpack_propsFile: true + ob_createvpack_verbose: true + ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' + ob_createvpack_description: PowerShell $(architecture) $(version) + # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ + ob_createvpack_majorVer: $(pwshMajorVersion) + ob_createvpack_minorVer: $(pwshMinorVersion) + ob_createvpack_patchVer: $(pwshPatchVersion) + ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: + ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) + ${{ else }}: + ob_createvpack_prereleaseVer: $(Build.SourceVersion) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s + env: + ob_restore_phase: true + + - template: .pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $version = '$(Version)' + Write-Verbose -Verbose "Version: $version" + if(!$version) { + throw "Version is not set." + } + + $mainVersionParts = $version -split '-' + + Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" + $versionParts = $mainVersionParts[0] -split '[.]'; + $major = $versionParts[0] + $minor = $versionParts[1] + $patch = $versionParts[2] + + $previewPart = $mainVersionParts[1] + Write-Verbose -Verbose "previewPart: $previewPart" + + Write-Host "major: $major; minor: $minor; patch: $patch;" + + $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + if($previewPart) { + $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" + } else { + Write-Verbose -Verbose "No prerelease part found in version string." + } + displayName: Set ob_createvpack_*Ver + env: + ob_restore_phase: true + + # Validate pwsh*Version variables + - pwsh: | + $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") + foreach ($var in $variables) { + if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { + throw "Required variable '`$env:$var' is not set." + } + } + displayName: Validate pwsh*Version variables + env: + ob_restore_phase: true + + - pwsh: | + if($env:RELEASETAGVAR -match '-') { + throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + packageType: sdk + version: 3.1.x + installationPath: $(Agent.ToolsDirectory)/dotnet + + ### BUILD ### + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(repoRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: false # Do not upload results + Language: csharp + + - task: UseDotNet@2 + displayName: 'Install .NET based on global.json' + inputs: + useGlobalJson: true + workingDirectory: $(repoRoot) + env: + ob_restore_phase: true + + - pwsh: | + # Need to set PowerShellRoot variable for obp-file-signing template + $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $Architecture = '$(Architecture)' + $runtime = switch ($Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + } + + $params = @{} + if ($env:BuildConfiguration -eq 'minSize') { + $params['ForMinimalSize'] = $true + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(repoRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR + } + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\src' + ob_restore_phase: true + + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + SigningProfile: $(windows_build_tools_cert_id) + OfficialBuild: false + vPackScenario: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem env:/ob_createvpack_*Ver + Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture Environment + condition: succeededOrFailed() + + - pwsh: | + $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" + } + $vpackFiles + displayName: Debug Output Directory and Version + condition: succeededOrFailed() diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml new file mode 100644 index 00000000000..de3ac0ba1b6 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -0,0 +1,67 @@ +parameters: + - name: InternalSDKBlobURL + type: string + default: ' ' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + type: string + default: 'NO' + - name: ENABLE_MSBUILD_BINLOGS + type: boolean + default: false + - name: FORCE_CODEQL + type: boolean + default: false + +variables: + - name: PS_RELEASE_BUILD + value: 1 + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - name: BUILDSECMON_OPT_IN + value: true + - name: __DOTNET_RUNTIME_FEED + value: ${{ parameters.InternalSDKBlobURL }} + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: WindowsContainerImage + value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: SKIP_SIGNING + value: ${{ parameters.SKIP_SIGNING }} + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: ENABLE_MSBUILD_BINLOGS + value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: + # Cadence is hours before CodeQL will allow a re-upload of the database + - name: CodeQL.Cadence + value: 1 + - name: CODEQL_ENABLED + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: true + ${{ else }}: + value: false + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true + # Disable BinSkim at job level to override NonOfficial template defaults + - name: ob_sdl_binskim_enabled + value: false diff --git a/.pipelines/templates/variables/PowerShell-Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml new file mode 100644 index 00000000000..7d1818909b5 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml @@ -0,0 +1,50 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ForceAzureBlobDelete + type: string + default: 'false' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: disableNetworkIsolation + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] # needed for onebranch.pipeline.version task + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: ForceAzureBlobDelete + value: ${{ parameters.ForceAzureBlobDelete }} + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - group: MSIXSigningProfile + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} diff --git a/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml new file mode 100644 index 00000000000..3b47e5eff2b --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml @@ -0,0 +1,35 @@ +parameters: + - name: debug + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\.config\tsaoptions.json + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: PoolNames diff --git a/.pipelines/templates/variables/PowerShell-Release-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Variables.yml new file mode 100644 index 00000000000..930c559eafe --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Variables.yml @@ -0,0 +1,41 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: PoolNames + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml new file mode 100644 index 00000000000..276911a35b3 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -0,0 +1,39 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: netiso + type: string + default: 'R1' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: Azure Blob variable group + - group: certificate_logical_to_actual # used within signing task + - group: DotNetPrivateBuildAccess + - name: netiso + value: ${{ parameters.netiso }} +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variables/release-shared.yml similarity index 100% rename from .pipelines/templates/variable/release-shared.yml rename to .pipelines/templates/variables/release-shared.yml From a17f1761eca57d90856062e35add0f013a1c703f Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:56:16 -0500 Subject: [PATCH 322/378] Select New MSIX Package Name (#27096) Co-authored-by: Justin Chung --- .pipelines/templates/packaging/windows/package.yml | 2 +- .pipelines/templates/packaging/windows/sign.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 92926e6aa59..1cc0e9d0e94 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -220,7 +220,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml index 4a095ba7694..f7a2e5e03e8 100644 --- a/.pipelines/templates/packaging/windows/sign.yml +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -202,7 +202,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose From 79526d2460d9df3b0e6bdd254cdd577d26ffe4a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:06:36 -0700 Subject: [PATCH 323/378] Bump github/codeql-action from 4.34.1 to 4.35.1 (#27120) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index dfe565b0319..0fe64afb19a 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 7bd7bf6314d..b84ed640102 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: sarif_file: results.sarif From 27c53eaf4508d22dc6ae46841d6a1823ba07cd6b Mon Sep 17 00:00:00 2001 From: cui Date: Wed, 1 Apr 2026 01:08:09 +0800 Subject: [PATCH 324/378] PSStyle: validate background index against `BackgroundColorMap` (#27106) --- .../FormatAndOutput/common/PSStyle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/PSStyle.cs b/src/System.Management.Automation/FormatAndOutput/common/PSStyle.cs index 3f927afd7d5..534f9541195 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/PSStyle.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/PSStyle.cs @@ -892,7 +892,7 @@ public static string MapColorPairToEscapeSequence(ConsoleColor foregroundColor, throw new ArgumentOutOfRangeException(paramName: nameof(foregroundColor)); } - if (backIndex < 0 || backIndex >= ForegroundColorMap.Length) + if (backIndex < 0 || backIndex >= BackgroundColorMap.Length) { throw new ArgumentOutOfRangeException(paramName: nameof(backgroundColor)); } From f3fcee88f19150cd3561d625e484e384ad80648a Mon Sep 17 00:00:00 2001 From: scuzqy <80660355+scuzqy@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:17:39 +0800 Subject: [PATCH 325/378] Fix `Remove-Item` confirmation message to use provider path instead (#27123) --- .../commands/management/Navigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs index f4ba55202ed..6ab8f1d652d 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Navigation.cs @@ -2718,7 +2718,7 @@ protected override void ProcessRecord() { // Get the localized prompt string - string prompt = StringUtil.Format(NavigationResources.RemoveItemWithChildren, resolvedPath.Path); + string prompt = StringUtil.Format(NavigationResources.RemoveItemWithChildren, providerPath); // Confirm the user wants to remove all children and the item even if // they did not specify -recurse From 30f70ee772e70278290ba5c7e6a4bb46a59fd184 Mon Sep 17 00:00:00 2001 From: reabr <91016230+reabr@users.noreply.github.com> Date: Tue, 31 Mar 2026 21:52:55 +0330 Subject: [PATCH 326/378] Add verbose message to `Get-Service` when properties cannot be returned (#27109) --- .../commands/management/Service.cs | 36 +++++++++++- .../resources/ServiceResources.resx | 57 ++++++++++--------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs index 739baa15bab..a00f9583d6a 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs @@ -674,13 +674,30 @@ protected override void ProcessRecord() #endregion Overrides #nullable enable + + /// + /// Writes a verbose message when a service property query fails. + /// + /// Name of the service. + /// Name of the property that failed to be queried. + private void WriteServicePropertyError(string serviceName, string propertyName) + { + Win32Exception e = new(Marshal.GetLastWin32Error()); + WriteVerbose( + StringUtil.Format( + ServiceResources.CouldNotGetServiceProperty, + serviceName, + propertyName, + e.Message)); + } + /// /// Adds UserName, Description, BinaryPathName, DelayedAutoStart and StartupType to a ServiceController object. /// /// Handle to the local SCManager instance. /// /// ServiceController as PSObject with UserName, Description and StartupType added. - private static PSObject AddProperties(nint scManagerHandle, ServiceController service) + private PSObject AddProperties(nint scManagerHandle, ServiceController service) { NakedWin32Handle hService = nint.Zero; @@ -709,6 +726,10 @@ private static PSObject AddProperties(nint scManagerHandle, ServiceController se { description = descriptionInfo.lpDescription; } + else + { + WriteServicePropertyError(service.ServiceName, nameof(NativeMethods.SERVICE_DESCRIPTIONW)); + } if (NativeMethods.QueryServiceConfig2( hService, @@ -717,6 +738,10 @@ private static PSObject AddProperties(nint scManagerHandle, ServiceController se { isDelayedAutoStart = autostartInfo.fDelayedAutostart; } + else + { + WriteServicePropertyError(service.ServiceName, nameof(NativeMethods.SERVICE_DELAYED_AUTO_START_INFO)); + } if (NativeMethods.QueryServiceConfig( hService, @@ -731,6 +756,15 @@ private static PSObject AddProperties(nint scManagerHandle, ServiceController se isDelayedAutoStart.Value); } } + else + { + WriteServicePropertyError(service.ServiceName, nameof(NativeMethods.QUERY_SERVICE_CONFIG)); + } + } + else + { + // handle when OpenServiceW itself fails: + WriteServicePropertyError(service.ServiceName, nameof(NativeMethods.SERVICE_QUERY_CONFIG)); } } finally diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx index e1213c3fb05..c19f753529f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ServiceResources.resx @@ -1,17 +1,17 @@ - @@ -213,4 +213,7 @@ The startup type '{0}' is not supported by {1}. + + Could not retrieve property '{1}' for service '{0}': {2} + From 1216cb7bedf37c0763acae0180d9bbb3118b881e Mon Sep 17 00:00:00 2001 From: Staffan Gustafsson Date: Tue, 31 Mar 2026 20:35:05 +0200 Subject: [PATCH 327/378] Add comment-based help documentation to `build.psm1` functions (#27122) --- build.psm1 | 847 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 822 insertions(+), 25 deletions(-) diff --git a/build.psm1 b/build.psm1 index ec91f2cf314..737b3e6182f 100644 --- a/build.psm1 +++ b/build.psm1 @@ -35,6 +35,16 @@ $tagsUpToDate = $false # This function is used during the setup phase in tools/ci.psm1 function Sync-PSTags { + <# + .SYNOPSIS + Syncs git tags from the PowerShell/PowerShell upstream remote. + .DESCRIPTION + Ensures that tags from the PowerShell/PowerShell upstream remote have been fetched. + Functions like Get-PSCommitId and Get-PSLatestTag require tags to be current. + This is called during the setup phase in tools/ci.psm1. + .PARAMETER AddRemoteIfMissing + If specified, adds the upstream remote automatically when it is not present. + #> param( [Switch] $AddRemoteIfMissing @@ -78,6 +88,15 @@ function Sync-PSTags # Gets the latest tag for the current branch function Get-PSLatestTag { + <# + .SYNOPSIS + Gets the latest git tag reachable from the current HEAD. + .DESCRIPTION + Returns the most recent annotated git tag. Run Sync-PSTags first to ensure tags + are up to date; otherwise a warning is emitted. + .OUTPUTS + System.String. The latest tag string, e.g. 'v7.5.0'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -92,6 +111,17 @@ function Get-PSLatestTag function Get-PSVersion { + <# + .SYNOPSIS + Returns the PowerShell version string for the current commit. + .DESCRIPTION + Derives the version from the latest git tag, optionally omitting the commit-ID suffix. + .PARAMETER OmitCommitId + When specified, returns only the bare version (e.g. '7.5.0') from the latest tag, + without the commit-count and hash suffix appended by git describe. + .OUTPUTS + System.String. A version string such as '7.5.0' or '7.5.0-15-gabcdef1234'. + #> [CmdletBinding()] param( [switch] @@ -109,6 +139,16 @@ function Get-PSVersion function Get-PSCommitId { + <# + .SYNOPSIS + Returns the PowerShell commit-ID string produced by git describe. + .DESCRIPTION + Returns the full git describe string including the tag, number of commits since + the tag, and the abbreviated commit hash (e.g. 'v7.5.0-15-gabcdef1234567890'). + Run Sync-PSTags first; otherwise a warning is emitted. + .OUTPUTS + System.String. A git describe string such as 'v7.5.0-15-gabcdef1234567890'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -123,6 +163,19 @@ function Get-PSCommitId function Get-EnvironmentInformation { + <# + .SYNOPSIS + Collects information about the current operating environment. + .DESCRIPTION + Returns a PSCustomObject containing OS-identity flags, architecture, admin status, + NuGet package root paths, and Linux distribution details. The object is used + throughout the build module to make platform-conditional decisions. + .OUTPUTS + System.Management.Automation.PSCustomObject. An object with properties such as + IsWindows, IsLinux, IsMacOS, IsAdmin, OSArchitecture, and distribution-specific flags + (IsUbuntu, IsDebian, IsRedHatFamily, etc.). + #> + param() $environment = @{'IsWindows' = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT} # PowerShell will likely not be built on pre-1709 nanoserver if ('System.Management.Automation.Platform' -as [type]) { @@ -281,6 +334,54 @@ function Test-IsReleaseCandidate $optimizedFddRegex = 'fxdependent-(linux|win|win7|osx)-(x64|x86|arm64|arm)' function Start-PSBuild { + <# + .SYNOPSIS + Builds PowerShell from source using dotnet publish. + .DESCRIPTION + Compiles the PowerShell source tree for the specified runtime and configuration. + Optionally restores NuGet packages, regenerates resources, generates the type catalog, + and restores Gallery modules. Saves build options so subsequent commands can reuse them. + .PARAMETER StopDevPowerShell + Stops any running dev pwsh process before building to prevent file-in-use errors. + .PARAMETER Restore + Forces NuGet package restore even when packages already exist. + .PARAMETER Output + Path to the output directory. Defaults to the standard build location. + .PARAMETER ResGen + Regenerates C# bindings for resx resource files before building. + .PARAMETER TypeGen + Regenerates the CorePsTypeCatalog.cs type-catalog file before building. + .PARAMETER Clean + Runs 'git clean -fdX' to remove untracked and ignored files before building. + .PARAMETER PSModuleRestore + Restores PowerShell Gallery modules to the build output directory (legacy parameter set). + .PARAMETER NoPSModuleRestore + Skips restoring PowerShell Gallery modules to the build output directory. + .PARAMETER CI + Indicates a CI build; restores the Pester module to the output directory. + .PARAMETER ForMinimalSize + Produces a build optimized for minimal binary size (linux-x64, win7-x64, or osx-x64 only). + .PARAMETER SkipExperimentalFeatureGeneration + Skips the step that runs the built pwsh to produce the experimental-features list. + .PARAMETER SMAOnly + Rebuilds only System.Management.Automation.dll for rapid engine iteration. + .PARAMETER UseNuGetOrg + Uses nuget.org instead of the private PowerShell feed for package restore. + .PARAMETER Runtime + The .NET runtime identifier (RID) to target, e.g. 'win7-x64' or 'linux-x64'. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER ReleaseTag + A git tag in 'vX.Y.Z[-preview.N|-rc.N]' format to embed as the release version. + .PARAMETER Detailed + Passes '--verbosity d' to dotnet for detailed build output. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER SkipRoslynAnalyzers + Skips Roslyn analyzer execution during the build. + .PARAMETER PSOptionsPath + When supplied, saves the resolved build options to this JSON file path. + #> [CmdletBinding(DefaultParameterSetName="Default")] param( # When specified this switch will stops running dev powershell @@ -763,6 +864,20 @@ Fix steps: } function Switch-PSNugetConfig { + <# + .SYNOPSIS + Switches the NuGet configuration between public, private, and NuGet.org-only sources. + .DESCRIPTION + Regenerates nuget.config files in the repository root, src/Modules, and test/tools/Modules + to point to the specified feed source. Optionally stores authenticated credentials. + .PARAMETER Source + The feed set to activate: 'Public' (nuget.org + dotnet feed), 'Private' (PowerShell ADO + feed), or 'NuGetOnly' (nuget.org only). + .PARAMETER UserName + Username for authenticated private feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated private feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName = 'user')] [Parameter(Mandatory = $true, ParameterSetName = 'nouser')] @@ -814,6 +929,18 @@ function Switch-PSNugetConfig { function Test-ShouldGenerateExperimentalFeatures { + <# + .SYNOPSIS + Determines whether experimental-feature JSON files should be generated on this host. + .DESCRIPTION + Returns $true only when the current runtime identifier matches the host OS and + architecture, the build is not a release build (PS_RELEASE_BUILD not set), and the + runtime is not fxdependent. + .PARAMETER Runtime + The .NET runtime identifier (RID) being targeted by the build. + .OUTPUTS + System.Boolean. $true if the experimental-feature list should be generated. + #> param( [Parameter(Mandatory)] $Runtime @@ -853,6 +980,23 @@ function Test-ShouldGenerateExperimentalFeatures function Restore-PSPackage { + <# + .SYNOPSIS + Restores NuGet packages for the PowerShell project directories. + .DESCRIPTION + Runs 'dotnet restore' on the main PowerShell project directories with up to five + retries on transient failures. Honors the target runtime identifier and build verbosity. + .PARAMETER ProjectDirs + Explicit list of project directories to restore. Defaults to the standard PS project set. + .PARAMETER Options + PSOptions object specifying runtime and configuration. Defaults to Get-PSOptions. + .PARAMETER Force + Forces restore even when project.assets.json already exists. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER PSModule + Restores in PSModule mode, omitting the runtime argument. + #> [CmdletBinding()] param( [ValidateNotNullOrEmpty()] @@ -967,6 +1111,16 @@ function Restore-PSPackage function Restore-PSModuleToBuild { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache into the build output Modules folder. + .DESCRIPTION + Resolves Gallery module packages referenced in PSGalleryModules.csproj and copies + them to the Modules subdirectory of the specified publish path. Also removes + .nupkg.metadata files left behind by the restore. + .PARAMETER PublishPath + The PowerShell build output directory whose Modules sub-folder receives the modules. + #> param( [Parameter(Mandatory)] [string] @@ -983,6 +1137,14 @@ function Restore-PSModuleToBuild function Restore-PSPester { + <# + .SYNOPSIS + Downloads and saves the Pester module (v4.x) from the PowerShell Gallery. + .DESCRIPTION + Uses Save-Module to install Pester up to version 4.99 into the target directory. + .PARAMETER Destination + Directory to save Pester into. Defaults to the Modules folder of the current build output. + #> param( [ValidateNotNullOrEmpty()] [string] $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules")) @@ -991,6 +1153,15 @@ function Restore-PSPester } function Compress-TestContent { + <# + .SYNOPSIS + Compresses the test directory into a zip archive for distribution. + .DESCRIPTION + Publishes PSTestTools and then zips the entire test/ directory to the given + destination path using System.IO.Compression.ZipFile. + .PARAMETER Destination + The path of the output zip file to create. + #> [CmdletBinding()] param( $Destination @@ -1005,6 +1176,30 @@ function Compress-TestContent { } function New-PSOptions { + <# + .SYNOPSIS + Creates a new PSOptions hashtable describing a PowerShell build configuration. + .DESCRIPTION + Computes the output path, project directory, and framework for a PowerShell build + based on the supplied runtime and configuration. The resulting hashtable is consumed + by Start-PSBuild, Restore-PSPackage, and related functions. + .PARAMETER Configuration + The build configuration: Debug (default), Release, CodeCoverage, or StaticAnalysis. + .PARAMETER Framework + The target .NET framework moniker. Defaults to 'net11.0'. + .PARAMETER Runtime + The .NET runtime identifier (RID). Detected automatically via 'dotnet --info' if omitted. + .PARAMETER Output + Optional path to the output directory. The executable name is appended automatically. + .PARAMETER SMAOnly + Targets only the System.Management.Automation project rather than the full host. + .PARAMETER PSModuleRestore + Indicates whether Start-PSBuild should restore PowerShell Gallery modules. + .PARAMETER ForMinimalSize + Produces a build targeting minimal binary size. + .OUTPUTS + System.Collections.Hashtable. A hashtable with build option properties. + #> [CmdletBinding()] param( [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] @@ -1152,6 +1347,17 @@ function New-PSOptions { # Get the Options of the last build function Get-PSOptions { + <# + .SYNOPSIS + Returns the PSOptions from the most recent Start-PSBuild call. + .DESCRIPTION + Retrieves the script-level $script:Options object. If no build has been run and + -DefaultToNew is specified, returns a fresh object from New-PSOptions. + .PARAMETER DefaultToNew + When specified, returns default options from New-PSOptions if no build has occurred. + .OUTPUTS + System.Collections.Hashtable. The current PSOptions hashtable, or $null. + #> param( [Parameter(HelpMessage='Defaults to New-PSOption if a build has not occurred.')] [switch] @@ -1167,6 +1373,15 @@ function Get-PSOptions { } function Set-PSOptions { + <# + .SYNOPSIS + Stores the supplied PSOptions as the active build options. + .DESCRIPTION + Writes the options hashtable to the script-scoped $script:Options variable, + making it available to subsequent Get-PSOptions calls. + .PARAMETER Options + The PSOptions hashtable to store. + #> param( [PSObject] $Options @@ -1176,6 +1391,17 @@ function Set-PSOptions { } function Get-PSOutput { + <# + .SYNOPSIS + Returns the path to the PowerShell executable produced by the build. + .DESCRIPTION + Looks up the Output path from the supplied options hashtable, the cached + script-level options, or a fresh New-PSOptions call, in that order of precedence. + .PARAMETER Options + An explicit options hashtable. If omitted, the most recent build options are used. + .OUTPUTS + System.String. The full path to the built pwsh or pwsh.exe executable. + #> [CmdletBinding()]param( [hashtable]$Options ) @@ -1189,6 +1415,21 @@ function Get-PSOutput { } function Get-PesterTag { + <# + .SYNOPSIS + Scans the Pester test tree and returns a summary of all tags in use. + .DESCRIPTION + Parses every *.tests.ps1 file under the specified base directory using the + PowerShell AST, validates that each Describe block has exactly one priority tag + (CI, Feature, or Scenario), and returns a summary object with tag counts and + any validation warnings. + .PARAMETER testbase + Root directory to search for test files. + Defaults to '$PSScriptRoot/test/powershell'. + .OUTPUTS + PSCustomObject (DescribeTagsInUse). Properties are tag names mapped to usage + counts, plus 'Result' (Pass/Fail) and 'Warnings' (string[]). + #> param ( [Parameter(Position=0)][string]$testbase = "$PSScriptRoot/test/powershell" ) $alltags = @{} $warnings = @() @@ -1255,6 +1496,13 @@ function Get-PesterTag { # testing PowerShell remote custom connections. function Publish-CustomConnectionTestModule { + <# + .SYNOPSIS + Builds and publishes the Microsoft.PowerShell.NamedPipeConnection test module. + .DESCRIPTION + Invokes the module's own build.ps1 script, copies the output to + test/tools/Modules, and then runs a clean build to remove intermediate artifacts. + #> Write-LogGroupStart -Title "Publish-CustomConnectionTestModule" $sourcePath = "${PSScriptRoot}/test/tools/NamedPipeConnection" $outPath = "${PSScriptRoot}/test/tools/NamedPipeConnection/out/Microsoft.PowerShell.NamedPipeConnection" @@ -1285,6 +1533,18 @@ function Publish-CustomConnectionTestModule } function Publish-PSTestTools { + <# + .SYNOPSIS + Builds and publishes all test tool projects to their bin directories. + .DESCRIPTION + Runs 'dotnet publish' for each test tool project (TestAlc, TestExe, UnixSocket, + WebListener, and on Windows TestService), copies Gallery test modules, and + publishes the NamedPipeConnection module. The tool bin directories are added to PATH + so that tests can locate the executables. + .PARAMETER runtime + The .NET runtime identifier (RID) used when publishing executables. + Defaults to the runtime from the current build options. + #> [CmdletBinding()] param( [string] @@ -1367,6 +1627,16 @@ function Publish-PSTestTools { } function Get-ExperimentalFeatureTests { + <# + .SYNOPSIS + Returns a mapping of experimental feature names to their associated test files. + .DESCRIPTION + Reads test/tools/TestMetadata.json and extracts the ExperimentalFeatures section, + returning a hashtable where keys are feature names and values are arrays of test paths. + .OUTPUTS + System.Collections.Hashtable. Keys are experimental feature names; values are + arrays of test file paths. + #> $testMetadataFile = Join-Path $PSScriptRoot "test/tools/TestMetadata.json" $metadata = Get-Content -Path $testMetadataFile -Raw | ConvertFrom-Json | ForEach-Object -MemberName ExperimentalFeatures $features = $metadata | Get-Member -MemberType NoteProperty | ForEach-Object -MemberName Name @@ -1379,6 +1649,57 @@ function Get-ExperimentalFeatureTests { } function Start-PSPester { + <# + .SYNOPSIS + Runs the Pester test suite against the built PowerShell. + .DESCRIPTION + Launches the built pwsh process with the Pester module and runs the specified + test paths. Automatically adjusts tag exclusions based on the current elevation + level, and emits NUnit XML results that are optionally published to Azure DevOps + or GitHub Actions. + .PARAMETER Path + One or more test file or directory paths to run. Defaults to test/powershell. + .PARAMETER OutputFormat + The Pester output format. Defaults to 'NUnitXml'. + .PARAMETER OutputFile + Path for the XML results file. Defaults to 'pester-tests.xml'. + .PARAMETER ExcludeTag + Tags to exclude from the run. Defaults to 'Slow'; adjusted for elevation level. + .PARAMETER Tag + Tags to include in the run. Defaults to 'CI' and 'Feature'. + .PARAMETER ThrowOnFailure + Throws an exception after the run if any tests failed. + .PARAMETER BinDir + Directory containing the built pwsh executable. Defaults to the current build output. + .PARAMETER powershell + Full path to the pwsh executable used for running tests. + .PARAMETER Pester + Path to the Pester module directory. + .PARAMETER Unelevate + Runs tests in an unelevated child process on Windows. + .PARAMETER Quiet + Suppresses most Pester output. + .PARAMETER Terse + Shows compact pass/fail indicators instead of full output lines. + .PARAMETER PassThru + Returns the Pester result object to the caller. + .PARAMETER Sudo + Runs tests under sudo on Unix (PassThru parameter set). + .PARAMETER IncludeFailingTest + Includes tests from tools/failingTests. + .PARAMETER IncludeCommonTests + Includes tests from test/common. + .PARAMETER ExperimentalFeatureName + Enables the named experimental feature for this test run via a temporary config file. + .PARAMETER Title + Title for the published test results. Defaults to 'PowerShell 7 Tests'. + .PARAMETER Wait + Waits for a debugger to attach before starting Pester (Debug builds only). + .PARAMETER SkipTestToolBuild + Skips rebuilding test tool executables before running tests. + .PARAMETER UseNuGetOrg + Switches NuGet config to public feeds before running tests. + #> [CmdletBinding(DefaultParameterSetName='default')] param( [Parameter(Position=0)] @@ -1428,7 +1749,7 @@ function Start-PSPester { if($IncludeCommonTests.IsPresent) { - $path = += "$PSScriptRoot/test/common" + $path += "$PSScriptRoot/test/common" } # we need to do few checks and if user didn't provide $ExcludeTag explicitly, we should alternate the default @@ -1744,6 +2065,20 @@ function Start-PSPester { function Publish-TestResults { + <# + .SYNOPSIS + Publishes test result files to Azure DevOps or GitHub Actions. + .DESCRIPTION + In an Azure DevOps build (TF_BUILD), uploads the result file via a ##vso command + and attaches it as a build artifact. In GitHub Actions, copies the file to the + testResults directory under $env:RUNNER_WORKSPACE. Does nothing outside of CI environments. + .PARAMETER Title + The run title shown in the CI testing tab. + .PARAMETER Path + Path to the NUnit or XUnit result file to publish. + .PARAMETER Type + The result file format: 'NUnit' (default) or 'XUnit'. + #> param( [Parameter(Mandatory)] [string] @@ -1804,6 +2139,17 @@ function Publish-TestResults function script:Start-UnelevatedProcess { + <# + .SYNOPSIS + Starts a process at an unelevated trust level on Windows. + .DESCRIPTION + Uses runas.exe /trustlevel:0x20000 to launch a process without elevation. + Only supported on Windows and non-arm64 architectures. + .PARAMETER process + The path to the executable to start. + .PARAMETER arguments + Arguments to pass to the executable. + #> param( [string]$process, [string[]]$arguments @@ -1814,7 +2160,7 @@ function script:Start-UnelevatedProcess throw "Start-UnelevatedProcess is currently not supported on non-Windows platforms" } - if (-not $environment.OSArchitecture -eq 'arm64') + if ($environment.OSArchitecture -eq 'arm64') { throw "Start-UnelevatedProcess is currently not supported on arm64 platforms" } @@ -1824,6 +2170,18 @@ function script:Start-UnelevatedProcess function Show-PSPesterError { + <# + .SYNOPSIS + Outputs a formatted error block for a single Pester test failure. + .DESCRIPTION + Accepts either an XmlElement from a NUnit result file or a PSCustomObject from + a Pester PassThru result, and writes a structured description/name/message/stack-trace + block to the log output. + .PARAMETER testFailure + An XML test-case element from a Pester NUnit result file (xml parameter set). + .PARAMETER testFailureObject + A Pester test-result PSCustomObject from a PassThru run (object parameter set). + #> [CmdletBinding(DefaultParameterSetName='xml')] param ( [Parameter(ParameterSetName='xml',Mandatory)] @@ -1866,6 +2224,18 @@ $stack_trace function Get-PesterFailureFileInfo { + <# + .SYNOPSIS + Parses a Pester stack-trace string and returns the source file path and line number. + .DESCRIPTION + Tries several common stack-trace formats produced by Pester 4 and Pester 5 (on + both Windows and Unix) and returns a hashtable with File and Line keys. + Returns $null values for both keys when no pattern matches. + .PARAMETER StackTraceString + The raw stack trace text from a Pester test failure. + .OUTPUTS + System.Collections.Hashtable. A hashtable with 'File' (string) and 'Line' (string). + #> [CmdletBinding()] param ( [Parameter(Mandatory)] @@ -1879,23 +2249,23 @@ function Get-PesterFailureFileInfo # "at , C:\path\to\file.ps1: line 123" # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) - + $result = @{ File = $null Line = $null } - + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { return $result } - + # Try pattern: "at line: 123 in " (Pester 4) if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { $result.Line = $matches[1] $result.File = $matches[2].Trim() return $result } - + # Try pattern: ", :123" (Pester 5 format) # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { @@ -1903,7 +2273,7 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: "at :123" (without comma) # Handle both absolute Unix and Windows paths if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { @@ -1911,24 +2281,33 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: ": line 123" if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { $result.File = $matches[1].Trim() $result.Line = $matches[2] return $result } - + # Try to extract just the file path if no line number found if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { $result.File = $matches[1].Trim() } - + return $result } function Test-XUnitTestResults { + <# + .SYNOPSIS + Validates an xUnit XML result file and throws if any tests failed. + .DESCRIPTION + Parses the specified xUnit result file, logs description, name, message, and + stack trace for each failed test, then throws an exception summarizing the count. + .PARAMETER TestResultsFile + Path to the xUnit XML result file to validate. + #> param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] @@ -1984,6 +2363,23 @@ function Test-XUnitTestResults # Throw if a test failed function Test-PSPesterResults { + <# + .SYNOPSIS + Validates Pester test results and throws if any tests failed. + .DESCRIPTION + In file mode, reads a NUnit XML result file and logs each failure before throwing. + In object mode, inspects a Pester PassThru result object. Optionally permits + empty result sets. + .PARAMETER TestResultsFile + Path to the NUnit XML result file. Defaults to 'pester-tests.xml'. + .PARAMETER TestArea + Label for the test area, used in error messages. Defaults to 'test/powershell'. + .PARAMETER ResultObject + A Pester PassThru result object to inspect instead of parsing a file. + .PARAMETER CanHaveNoResult + When specified with ResultObject, suppresses the 'NO TESTS RUN' exception for + zero-count results. + #> [CmdletBinding(DefaultParameterSetName='file')] param( [Parameter(ParameterSetName='file')] @@ -2059,6 +2455,20 @@ function Test-PSPesterResults } function Start-PSxUnit { + <# + .SYNOPSIS + Runs the xUnit tests for the PowerShell engine. + .DESCRIPTION + Executes 'dotnet test' in the test/xUnit directory against the built PowerShell + binaries. On Unix, copies native libraries and required dependencies into the test + output directory. Publishes results to CI when not in debug-logging mode. + .PARAMETER xUnitTestResultsFile + Path for the xUnit XML result file. Defaults to 'xUnitResults.xml'. + .PARAMETER DebugLogging + Enables detailed console test output instead of writing an XML result file. + .PARAMETER Filter + An xUnit filter expression to restrict which tests are run. + #> [CmdletBinding()]param( [string] $xUnitTestResultsFile = "xUnitResults.xml", [switch] $DebugLogging, @@ -2150,6 +2560,29 @@ function Start-PSxUnit { } function Install-Dotnet { + <# + .SYNOPSIS + Installs the .NET SDK using the official install script. + .DESCRIPTION + Downloads and runs dotnet-install.sh (Linux/macOS) or dotnet-install.ps1 (Windows) + to install the specified SDK version into the user-local dotnet installation directory. + .PARAMETER Channel + The release channel to install from when no explicit version is given. + .PARAMETER Version + The exact SDK version to install. Defaults to the version required by this repository. + .PARAMETER Quality + The quality level (e.g. 'GA', 'preview') used when installing by channel. + .PARAMETER RemovePreviousVersion + Attempts to uninstall previously installed dotnet packages before installing. + .PARAMETER NoSudo + Omits sudo from install commands, useful inside containers running as root. + .PARAMETER InstallDir + Custom installation directory for the .NET SDK. + .PARAMETER AzureFeed + Override URL for the Azure CDN feed used to download the SDK. + .PARAMETER FeedCredential + Credential token for accessing a private Azure feed. + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2301,6 +2734,15 @@ function Install-Dotnet { } function Get-RedHatPackageManager { + <# + .SYNOPSIS + Returns the install command prefix for the available Red Hat-family package manager. + .DESCRIPTION + Detects whether yum, dnf, or tdnf is installed and returns the corresponding + install command string for use in bootstrapping scripts. + .OUTPUTS + System.String. A package-manager install command such as 'dnf install -y -q'. + #> if ($environment.IsCentOS -or (Get-Command -Name yum -CommandType Application -ErrorAction SilentlyContinue)) { "yum install -y -q" } elseif ($environment.IsFedora -or (Get-Command -Name dnf -CommandType Application -ErrorAction SilentlyContinue)) { @@ -2313,6 +2755,27 @@ function Get-RedHatPackageManager { } function Start-PSBootstrap { + <# + .SYNOPSIS + Installs build dependencies for PowerShell. + .DESCRIPTION + Depending on the selected scenario, installs native OS packages, the required + .NET SDK, Windows packaging tools (WiX), and/or .NET global tools (dotnet-format). + Supports Linux, macOS, and Windows. + .PARAMETER Channel + The .NET SDK release channel to use when installing by channel. + .PARAMETER Version + The exact .NET SDK version to install. Defaults to the required version. + .PARAMETER NoSudo + Omits sudo from native-package install commands, useful inside containers. + .PARAMETER BuildLinuxArm + Installs Linux ARM cross-compilation dependencies (Ubuntu/AzureLinux only). + .PARAMETER Force + Forces .NET SDK reinstallation even if the correct version is already present. + .PARAMETER Scenario + What to install: 'Package' (packaging tools), 'DotNet' (.NET SDK), + 'Both' (Package + DotNet), 'Tools' (.NET global tools), or 'All' (everything). + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2580,6 +3043,17 @@ function Start-PSBootstrap { ## If the required SDK version is found, return it. ## Otherwise, return the latest installed SDK version that can be found. function Find-RequiredSDK { + <# + .SYNOPSIS + Returns the installed .NET SDK version that best satisfies the required version. + .DESCRIPTION + Lists installed SDKs with 'dotnet --list-sdks'. Returns the required version + string if it is installed; otherwise returns the newest installed SDK version. + .PARAMETER requiredSdkVersion + The exact .NET SDK version string to search for. + .OUTPUTS + System.String. The matched or newest installed SDK version string. + #> param( [Parameter(Mandatory, Position = 0)] [string] $requiredSdkVersion @@ -2604,6 +3078,28 @@ function Find-RequiredSDK { } function Start-DevPowerShell { + <# + .SYNOPSIS + Launches a PowerShell session using the locally built pwsh. + .DESCRIPTION + Starts a new pwsh process from the build output directory, optionally setting + the DEVPATH environment variable, redirecting PSModulePath to the built Modules + directory, and loading or suppressing the user profile. + .PARAMETER ArgumentList + Additional arguments passed to the pwsh process. + .PARAMETER LoadProfile + When specified, the user profile is loaded (by default -noprofile is prepended). + .PARAMETER Configuration + Build configuration whose output directory to use (ConfigurationParamSet). + .PARAMETER BinDir + Explicit path to the directory containing the pwsh binary (BinDirParamSet). + .PARAMETER NoNewWindow + Runs pwsh in the current console window instead of a new one. + .PARAMETER Command + A command string passed to pwsh via -command. + .PARAMETER KeepPSModulePath + Preserves the existing PSModulePath instead of redirecting it to the build output. + #> [CmdletBinding(DefaultParameterSetName='ConfigurationParamSet')] param( [string[]]$ArgumentList = @(), @@ -2671,6 +3167,16 @@ function Start-DevPowerShell { function Start-TypeGen { + <# + .SYNOPSIS + Generates the CorePsTypeCatalog type-catalog file. + .DESCRIPTION + Invokes the TypeCatalogGen .NET tool to produce CorePsTypeCatalog.cs, which maps + .NET types to their containing assemblies. The output .inc file name varies by + runtime to allow simultaneous builds on Windows and WSL. + .PARAMETER IncFileName + Name of the .inc file listing dependent assemblies. Defaults to 'powershell.inc'. + #> [CmdletBinding()] param ( @@ -2699,6 +3205,13 @@ function Start-TypeGen function Start-ResGen { + <# + .SYNOPSIS + Regenerates C# resource bindings from resx files. + .DESCRIPTION + Runs the ResGen .NET tool in src/ResGen to produce strongly-typed resource classes + for all resx files in the PowerShell project. + #> [CmdletBinding()] param() @@ -2771,6 +3284,17 @@ function Set-PSEnvironmentVariable { } function Find-Dotnet { + <# + .SYNOPSIS + Ensures the required .NET SDK is available on PATH. + .DESCRIPTION + Checks whether the dotnet currently on PATH can locate the required SDK version. + If not, prepends the user-local dotnet installation directory to PATH. + Optionally sets DOTNET_ROOT and adds the global tools directory to PATH. + .PARAMETER SetDotnetRoot + When specified, sets the DOTNET_ROOT environment variable and adds the + .NET global tools path to PATH. + #> param ( [switch] $SetDotnetRoot ) @@ -2867,6 +3391,14 @@ function Convert-TxtResourceToXml } function script:Use-MSBuild { + <# + .SYNOPSIS + Ensures that the msbuild command is available in the current scope. + .DESCRIPTION + If msbuild is not found in PATH, creates a script-scoped alias pointing to the + .NET Framework 4 MSBuild at its standard Windows location. Throws if neither + location provides a usable msbuild. + #> # TODO: we probably should require a particular version of msbuild, if we are taking this dependency # msbuild v14 and msbuild v4 behaviors are different for XAML generation $frameworkMsBuildLocation = "${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319\msbuild" @@ -2886,6 +3418,18 @@ function script:Use-MSBuild { function script:Write-Log { + <# + .SYNOPSIS + Writes a colored message to the host, with optional error annotation. + .DESCRIPTION + In GitHub Actions, error messages are emitted as workflow error annotations + using the '::error::' command. Normal messages are written in green; errors + in red. Console colors are reset after each call. + .PARAMETER message + The text to write. + .PARAMETER isError + When specified, writes the message as an error (red / GitHub Actions annotation). + #> param ( [Parameter(Position=0, Mandatory)] @@ -2913,6 +3457,18 @@ function script:Write-Log } function script:Write-LogGroup { + <# + .SYNOPSIS + Emits a titled group of log messages wrapped in log-group markers. + .DESCRIPTION + Calls Write-LogGroupStart, writes each message line via Write-Log, then calls + Write-LogGroupEnd. In GitHub Actions this creates a collapsible group; on other + hosts it adds BEGIN/END banners. + .PARAMETER Message + One or more message lines to write inside the group. + .PARAMETER Title + The title displayed for the log group. + #> param ( [Parameter(Position = 0, Mandatory)] @@ -2935,6 +3491,15 @@ function script:Write-LogGroup { $script:logGroupColor = [System.ConsoleColor]::Cyan function script:Write-LogGroupStart { + <# + .SYNOPSIS + Opens a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::group::'. On other hosts writes a colored + begin banner using the script-level log group color. + .PARAMETER Title + The label for the group. + #> param ( [Parameter(Mandatory)] @@ -2950,6 +3515,15 @@ function script:Write-LogGroupStart { } function script:Write-LogGroupEnd { + <# + .SYNOPSIS + Closes a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::endgroup::'. On other hosts writes a colored + end banner using the script-level log group color. + .PARAMETER Title + The group label (used only in non-GitHub-Actions output). + #> param ( [Parameter(Mandatory)] @@ -2965,6 +3539,20 @@ function script:Write-LogGroupEnd { } function script:precheck([string]$command, [string]$missedMessage) { + <# + .SYNOPSIS + Tests whether a command exists on PATH and optionally emits a warning if missing. + .DESCRIPTION + Uses Get-Command to locate the specified command. Returns $true if found, + $false otherwise. If the command is absent and a message is provided, + Write-Warning is called with that message. + .PARAMETER command + The command name to look for. + .PARAMETER missedMessage + Warning text to emit when the command is not found. Pass $null to suppress it. + .OUTPUTS + System.Boolean. $true when the command is found; $false otherwise. + #> $c = Get-Command $command -ErrorAction Ignore if (-not $c) { if (-not [string]::IsNullOrEmpty($missedMessage)) @@ -2980,6 +3568,13 @@ function script:precheck([string]$command, [string]$missedMessage) { # Cleans the PowerShell repo - everything but the root folder function Clear-PSRepo { + <# + .SYNOPSIS + Cleans all subdirectories of the PowerShell repository using 'git clean -fdX'. + .DESCRIPTION + Iterates over every top-level directory under the repository root and removes all + files that are not tracked by git, including ignored files. + #> [CmdletBinding()] param() @@ -2992,6 +3587,20 @@ function Clear-PSRepo # Install PowerShell modules such as PackageManagement, PowerShellGet function Copy-PSGalleryModules { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache to a Modules directory. + .DESCRIPTION + Reads the PackageReference items in the specified csproj file, resolves each + package from the NuGet global cache, and copies it to the destination directory. + Package nupkg and metadata files are excluded from the copy. + .PARAMETER CsProjPath + Path to the csproj file whose PackageReference items describe Gallery modules. + .PARAMETER Destination + Destination Modules directory. Must end with 'Modules'. + .PARAMETER Force + Forces NuGet package restore even if packages are already present. + #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] @@ -3051,6 +3660,22 @@ function Copy-PSGalleryModules function Merge-TestLogs { + <# + .SYNOPSIS + Merges xUnit and NUnit test log files into a single xUnit XML file. + .DESCRIPTION + Converts NUnit Pester logs to xUnit assembly format and appends them, along with + any additional xUnit logs, to the primary xUnit log. The merged result is saved + to the specified output path. + .PARAMETER XUnitLogPath + Path to the primary xUnit XML log file. + .PARAMETER NUnitLogPath + One or more NUnit (Pester) XML log file paths to merge in. + .PARAMETER AdditionalXUnitLogPath + Optional additional xUnit XML log files to append. + .PARAMETER OutputLogPath + Path for the merged xUnit output file. + #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] @@ -3092,6 +3717,23 @@ function Merge-TestLogs } function ConvertFrom-PesterLog { + <# + .SYNOPSIS + Converts Pester NUnit XML log files to xUnit assembly format. + .DESCRIPTION + Accepts one or more NUnit log files produced by Pester, or existing xUnit logs, + and converts them to an in-memory xUnit assembly object model. If multiple logs + are provided and -MultipleLog is not set, they are combined into a single + assemblies object. + .PARAMETER Logfile + Path(s) to the NUnit or xUnit log file(s) to convert. Accepts pipeline input. + .PARAMETER IncludeEmpty + When specified, includes test assemblies that contain zero test cases. + .PARAMETER MultipleLog + When specified, returns one assemblies object per log file instead of combining. + .OUTPUTS + assemblies. One or more xUnit assemblies objects containing converted test data. + #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0)] @@ -3099,21 +3741,6 @@ function ConvertFrom-PesterLog { [Parameter()][switch]$IncludeEmpty, [Parameter()][switch]$MultipleLog ) - <# -Convert our test logs to -xunit schema - top level assemblies -Pester conversion -foreach $r in "test-results"."test-suite".results."test-suite" -assembly - name = $r.Description - config-file = log file (this is the only way we can determine between admin/nonadmin log) - test-framework = Pester - environment = top-level "test-results.environment.platform - run-date = date (doesn't exist in pester except for beginning) - run-time = time - time = -#> - BEGIN { # CLASSES class assemblies { @@ -3460,6 +4087,17 @@ assembly # Save PSOptions to be restored by Restore-PSOptions function Save-PSOptions { + <# + .SYNOPSIS + Persists the current PSOptions to a JSON file. + .DESCRIPTION + Serializes the current build options (or the supplied Options object) to JSON + and writes them to the specified path. Defaults to psoptions.json in the repo root. + .PARAMETER PSOptionsPath + Path to the JSON file to write. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Options + PSOptions object to save. Defaults to the current build options. + #> param( [ValidateScript({$parent = Split-Path $_;if($parent){Test-Path $parent}else{return $true}})] [ValidateNotNullOrEmpty()] @@ -3477,6 +4115,17 @@ function Save-PSOptions { # Restore PSOptions # Optionally remove the PSOptions file function Restore-PSOptions { + <# + .SYNOPSIS + Loads saved PSOptions from a JSON file and makes them the active build options. + .DESCRIPTION + Reads the JSON file produced by Save-PSOptions, reconstructs a PSOptions + hashtable, and stores it via Set-PSOptions. Optionally deletes the file afterward. + .PARAMETER PSOptionsPath + Path to the JSON file to read. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Remove + When specified, deletes the JSON file after loading. + #> param( [ValidateScript({Test-Path $_})] [string] @@ -3509,6 +4158,31 @@ function Restore-PSOptions { function New-PSOptionsObject { + <# + .SYNOPSIS + Constructs the PSOptions hashtable from individual build-option components. + .DESCRIPTION + Assembles the hashtable consumed by Start-PSBuild, Restore-PSPackage, and related + commands. Prefer New-PSOptions, which auto-computes fields such as the output path. + .PARAMETER RootInfo + PSCustomObject with repo root path validation metadata. + .PARAMETER Top + Path to the top-level project directory (pwsh source directory). + .PARAMETER Runtime + The .NET runtime identifier (RID) for the build. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER PSModuleRestore + Whether Gallery modules should be restored to the build output. + .PARAMETER Framework + The target .NET framework moniker, e.g. 'net11.0'. + .PARAMETER Output + Full path to the output pwsh executable. + .PARAMETER ForMinimalSize + Whether this is a minimal-size build. + .OUTPUTS + System.Collections.Hashtable. A PSOptions hashtable. + #> param( [PSCustomObject] $RootInfo, @@ -3679,6 +4353,17 @@ $script:RESX_TEMPLATE = @' '@ function Get-UniquePackageFolderName { + <# + .SYNOPSIS + Returns a unique temporary folder path for a test package under the specified root. + .DESCRIPTION + Tries the path '<Root>/TestPackage' first, then appends a random numeric suffix + until an unused path is found. Throws if a unique name cannot be found in 10 tries. + .PARAMETER Root + The parent directory under which the unique folder name is generated. + .OUTPUTS + System.String. A path under Root that does not yet exist. + #> param( [Parameter(Mandatory)] $Root ) @@ -3705,6 +4390,18 @@ function Get-UniquePackageFolderName { function New-TestPackage { + <# + .SYNOPSIS + Creates a zip archive containing all test content and test tools. + .DESCRIPTION + Builds and publishes test tools, copies the test directory, assets directory, + and resx resource directories into a temporary staging folder, then zips the + staging folder to TestPackage.zip in the specified destination directory. + .PARAMETER Destination + Directory where the TestPackage.zip file is created. + .PARAMETER Runtime + The .NET runtime identifier (RID) used when publishing test tool executables. + #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] @@ -3781,6 +4478,16 @@ class NugetPackageSource { } function New-NugetPackageSource { + <# + .SYNOPSIS + Creates a NugetPackageSource object with the given URL and name. + .PARAMETER Url + The NuGet feed URL. + .PARAMETER Name + The feed name used as the key in nuget.config. + .OUTPUTS + NugetPackageSource. An object with Url and Name properties. + #> param( [Parameter(Mandatory = $true)] [string]$Url, [Parameter(Mandatory = $true)] [string] $Name @@ -3791,6 +4498,22 @@ function New-NugetPackageSource { $script:NuGetEndpointCredentials = [System.Collections.Generic.Dictionary[String,System.Object]]::new() function New-NugetConfigFile { + <# + .SYNOPSIS + Generates a nuget.config file at the specified destination. + .DESCRIPTION + Creates a nuget.config XML file with the supplied package sources and optional + credentials. The generated file is marked as skip-worktree in git to prevent + accidental commits of feed credentials. + .PARAMETER NugetPackageSource + One or more NugetPackageSource objects defining the feeds to include. + .PARAMETER Destination + Directory where nuget.config is written. + .PARAMETER UserName + Username for authenticated feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName ='user')] [Parameter(Mandatory = $true, ParameterSetName ='nouser')] @@ -3872,10 +4595,24 @@ function New-NugetConfigFile { } function Clear-PipelineNugetAuthentication { + <# + .SYNOPSIS + Clears cached NuGet feed credentials used by the pipeline. + .DESCRIPTION + Removes all entries from the script-scoped NuGetEndpointCredentials dictionary. + #> $script:NuGetEndpointCredentials.Clear() } function Set-PipelineNugetAuthentication { + <# + .SYNOPSIS + Publishes cached NuGet feed credentials to the Azure DevOps pipeline. + .DESCRIPTION + Serializes the script-scoped NuGetEndpointCredentials dictionary to JSON and sets + the VSS_NUGET_EXTERNAL_FEED_ENDPOINTS pipeline variable so that subsequent NuGet + operations authenticate automatically. + #> $endpointcredentials = @() foreach ($key in $script:NuGetEndpointCredentials.Keys) { @@ -3890,6 +4627,14 @@ function Set-PipelineNugetAuthentication { function Set-CorrectLocale { + <# + .SYNOPSIS + Configures the Linux locale to en_US.UTF-8 for consistent build behavior. + .DESCRIPTION + On Ubuntu 20+ systems, generates the en_US.UTF-8 locale and sets LC_ALL and LANG + environment variables. Skips execution on non-Linux platforms and Ubuntu versions + earlier than 20. + #> Write-LogGroupStart -Title "Set-CorrectLocale" if (-not $IsLinux) @@ -3926,6 +4671,13 @@ function Set-CorrectLocale } function Write-Locale { + <# + .SYNOPSIS + Writes the current system locale settings to the log output. + .DESCRIPTION + Runs the 'locale' command on Linux or macOS and writes the output inside a + collapsible log group. Does nothing on Windows. + #> if (-not $IsLinux -and -not $IsMacOS) { Write-Verbose -Message "only supported on Linux and macOS" -Verbose return @@ -3937,6 +4689,13 @@ function Write-Locale { } function Install-AzCopy { + <# + .SYNOPSIS + Downloads and installs AzCopy v10 on Windows. + .DESCRIPTION + Downloads the AzCopy v10 zip archive from the official Microsoft URL and extracts + it to the Agent tools directory. Skips installation if AzCopy is already present. + #> $testPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe" if (Test-Path $testPath) { Write-Verbose "AzCopy already installed" -Verbose @@ -3951,6 +4710,15 @@ function Install-AzCopy { } function Find-AzCopy { + <# + .SYNOPSIS + Locates the AzCopy executable on the system. + .DESCRIPTION + Searches several well-known installation paths for AzCopy.exe and falls back to + Get-Command if none of the paths contain the executable. + .OUTPUTS + System.String. The full path to the AzCopy executable. + #> $searchPaths = @('$(Agent.ToolsDirectory)\azcopy10\AzCopy.exe', "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe", "C:\azcopy10\AzCopy.exe") foreach ($filter in $searchPaths) { @@ -3966,6 +4734,16 @@ function Find-AzCopy { function Clear-NativeDependencies { + <# + .SYNOPSIS + Removes unnecessary native dependency files from the publish output. + .DESCRIPTION + Strips architecture-specific DiaSym reader DLLs that are not needed for the + target runtime from both the publish folder and the pwsh.deps.json manifest. + Skips fxdependent runtimes where no cleanup is needed. + .PARAMETER PublishFolder + Path to the publish output directory containing pwsh.deps.json. + #> param( [Parameter(Mandatory=$true)] [string] $PublishFolder ) @@ -4032,6 +4810,14 @@ function Clear-NativeDependencies function Update-DotNetSdkVersion { +<# + .SYNOPSIS + Updates the .NET SDK version in global.json and DotnetRuntimeMetadata.json. + .DESCRIPTION + Queries the official .NET SDK feed for the latest version in the current channel + and writes the new version to global.json and DotnetRuntimeMetadata.json. + #> + param() $globalJsonPath = "$PSScriptRoot/global.json" $globalJson = get-content $globalJsonPath | convertfrom-json $oldVersion = $globalJson.sdk.version @@ -4051,6 +4837,17 @@ function Update-DotNetSdkVersion { } function Set-PipelineVariable { + <# + .SYNOPSIS + Sets an Azure DevOps pipeline variable and the corresponding environment variable. + .DESCRIPTION + Emits a ##vso[task.setvariable] logging command so that subsequent pipeline steps + can access the variable, and also sets it in the current process environment. + .PARAMETER Name + The pipeline variable name. + .PARAMETER Value + The value to assign. + #> param( [parameter(Mandatory)] [string] $Name, From 1b390e1fa752d47c3073e9f0d513d0a13416212f Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:22:31 -0400 Subject: [PATCH 328/378] Update package references and move to .NET SDK 11.0-preview.2 (#27117) --- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 15 ++- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 4 +- .../System.Management.Automation.csproj | 12 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- tools/cgmanifest/main/cgmanifest.json | 108 ++++++++++-------- 13 files changed, 85 insertions(+), 76 deletions(-) diff --git a/global.json b/global.json index 2fe6c88b1f6..ef31c0723ff 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "11.0.100-preview.1.26104.118" + "version": "11.0.100-preview.2.26159.112" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index ab9bd210353..8e5a6b3f2e3 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ <ItemGroup> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> <PropertyGroup> diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index a8c2c34aca2..8bb897e0095 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index b2fae8b21e7..d6cd95677ab 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ <ItemGroup> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> - <PackageReference Include="Markdig.Signed" Version="1.0.0" /> + <PackageReference Include="Markdig.Signed" Version="1.1.2" /> <PackageReference Include="Microsoft.PowerShell.MarkdownRender" Version="7.2.1" /> </ItemGroup> @@ -32,8 +32,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" /> - <PackageReference Include="System.Drawing.Common" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" /> + <PackageReference Include="System.Drawing.Common" Version="11.0.0-preview.2.26159.112" /> <PackageReference Include="JsonSchema.Net" Version="7.4.0" /> </ItemGroup> diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 6df470621f5..1a63891ef77 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 979764ff79f..ecc224713cc 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ <ItemGroup> <!-- This section is to force the version of non-direct dependencies --> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.2.26159.112" /> <!-- the following package(s) are from https://github.com/dotnet/fxdac --> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.IO.Packaging" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.Net.Http.WinHttpHandler" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="System.IO.Packaging" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Net.Http.WinHttpHandler" Version="11.0.0-preview.2.26159.112" /> <!-- the following package(s) are from https://github.com/dotnet/wcf --> <PackageReference Include="System.ServiceModel.Http" Version="10.0.652802" /> <PackageReference Include="System.ServiceModel.NetTcp" Version="10.0.652802" /> <PackageReference Include="System.ServiceModel.Primitives" Version="10.0.652802" /> <!-- the source could not be found for the following package(s) --> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> <!-- @@ -41,14 +41,13 @@ dotnet msbuild ./dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag 3. Search '_ReferencesFromRAR' in the produced 'msbuild.log' file. --> - <Target Name="_GetDependencies" - DependsOnTargets="ResolveAssemblyReferencesDesignTime"> + <Target Name="_GetDependencies" DependsOnTargets="ResolveAssemblyReferencesDesignTime"> <ItemGroup> <!-- Excludes 'Microsoft.Management.Infrastructure' from the type catalog reference list, as it is provided separately at runtime and must not be included in the generated catalog. --> - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' " /> </ItemGroup> <WriteLinesToFile File="$(_DependencyFile)" Lines="@(_RefAssemblyPath)" Overwrite="true" /> </Target> diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index e3bb66c87ac..bc6e4b105de 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <ProjectReference Include="..\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> <PropertyGroup> diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 44d93a5e31b..6ba483b5f6e 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -14,7 +14,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" /> - <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0" PrivateAssets="all" /> + <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" PrivateAssets="all" /> + <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="5.3.0" PrivateAssets="all" /> </ItemGroup> </Project> diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index d8a66b2ab74..fa797a7f0de 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ <!-- the Application Insights package --> <PackageReference Include="Microsoft.ApplicationInsights" Version="2.23.0" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.DirectoryServices" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.Management" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="11.0.0-preview.1.26104.118" /> - <PackageReference Include="System.Security.Permissions" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.DirectoryServices" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Management" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Security.Permissions" Version="11.0.0-preview.2.26159.112" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0-rc.1" /> diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 58ea02cf1b5..ff3f14d5a0d 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -10,6 +10,6 @@ <PackageReference Include="MarkdownLog.NS20" Version="0.10.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="BenchmarkDotNet" Version="0.15.8" /> - <PackageReference Include="Perfolizer" Version="0.6.7" /> + <PackageReference Include="Perfolizer" Version="0.7.1" /> </ItemGroup> </Project> diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 7580229ce98..906820d262b 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.2.26159.112" /> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> </ItemGroup> diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 00cd6825dff..c632e960a53 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="11.0.0-preview.1.26104.118" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="11.0.0-preview.2.26159.112" /> </ItemGroup> </Project> diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 4d856723eaa..5322bc102bd 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -66,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "1.0.0" + "Version": "1.1.2" } }, "DevelopmentDependency": false @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -126,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -186,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -336,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -376,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -436,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -596,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -606,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -616,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -626,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -636,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -646,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -656,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -706,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -716,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -726,7 +726,17 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.3" + "Version": "10.0.5" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Text.Encoding.CodePages", + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -746,7 +756,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.3" + "Version": "10.0.5" } }, "DevelopmentDependency": false From ff37ab4539966407a14d89c66004fd5f479836db Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 31 Mar 2026 14:24:41 -0700 Subject: [PATCH 329/378] Revert "Fetch latest ICU release version dynamically" (#27127) --- tools/packaging/packaging.psm1 | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index d420ceb620d..198fb91912e 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2152,7 +2152,7 @@ function Get-PackageDependencies # than the build version and we know that older versions just works. # $MinICUVersion = 60 # runtime minimum supported - $BuildICUVersion = Get-IcuLatestRelease + $BuildICUVersion = 76 # current build version $MaxICUVersion = $BuildICUVersion + 30 # headroom if ($Distribution -eq 'deb') { @@ -5809,15 +5809,3 @@ function Test-IsProductFile { return $false } - -# Get major version from latest ICU release (latest: stable version) -function Get-IcuLatestRelease { - $response = Invoke-WebRequest -Uri "https://github.com/unicode-org/icu/releases/latest" - $tagUrl = ($response.Links | Where-Object href -like "*releases/tag/release-*")[0].href - - if ($tagUrl -match 'release-(\d+)\.') { - return [int]$Matches[1] - } - - throw "Unable to determine the latest ICU release version." -} From 45a80d9a4894802a61637cc7c8843bc66b0bcc5d Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:20:45 -0500 Subject: [PATCH 330/378] Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27024) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- ...Shell-Coordinated_Packages-NonOfficial.yml | 4 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../store/PDP/PDP-Media/en-US/Error.png | Bin 120539 -> 0 bytes .../PDP-Media/en-US/Experimental_Features.png | Bin 161370 -> 0 bytes .../PDP/PDP-Media/en-US/Feedback_Provider.png | Bin 167038 -> 0 bytes .../PDP/PDP-Media/en-US/Predictor_Inline.png | Bin 110258 -> 0 bytes .../PDP-Media/en-US/Predictor_ListView.png | Bin 146469 -> 0 bytes .../store/PDP/PDP-Media/en-US/Prompt.png | Bin 132747 -> 0 bytes .../PDP/PDP-Media/en-US/Stable_Release.png | Bin 179123 -> 0 bytes .../store/PDP/PDP-Media/en-US/pwshLogo.png | Bin 13152 -> 0 bytes .pipelines/store/PDP/PDP/en-US/PDP.xml | 25 -- .pipelines/templates/package-create-msix.yml | 197 -------------- .../templates/package-store-package.yml | 242 ++++++++++++++++++ .pipelines/templates/release-MSIX-Publish.yml | 14 +- .../stages/PowerShell-Packages-Stages.yml | 6 + 18 files changed, 266 insertions(+), 236 deletions(-) delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Error.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Prompt.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png create mode 100644 .pipelines/templates/package-store-package.yml diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 55d4c4557d8..0b417df5c05 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -90,7 +90,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 81f343a04a0..9419d3f29b5 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 681babb2220..b524cb0ff81 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index ca5a6383f33..7864513fc2c 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Release-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index 642b169adaf..f1f4211ca8f 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ../templates/variables/PowerShell-vPack-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ../templates/stages/PowerShell-vPack-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Error.png b/.pipelines/store/PDP/PDP-Media/en-US/Error.png deleted file mode 100644 index 48e96378055b5d7fbb4d744007c1ebc073da2453..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120539 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png deleted file mode 100644 index 90420254a8e4a4720601e3050567db719819efc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161370 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 QBJkg#{kr>7G|bQcAJc$pZvX%Q diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png deleted file mode 100644 index f4084360d5c630119e469b721dde87920d5a8346..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167038 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 L$C>(5*M9y#()S`v diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png deleted file mode 100644 index 3b8d62284859c6ce60c96d643b3b2bdb994471d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110258 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 W56C)9ct$q>0000<MNUMnLSTZ6K}~c3 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png deleted file mode 100644 index 1fb9a6247c576275add6641350ea1d667c2f005c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146469 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৉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 Y-W{2D?d+Of_f@>lUHq~3hwBgi2Mp#?lK=n! diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png deleted file mode 100644 index a40d6fddfdc44c9f7fb643ebc4e84eda527a395d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132747 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ǟ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 E0osNO-T(jq diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png b/.pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png deleted file mode 100644 index 2761a46a64ff6d281aeee9e9422c8a3a36ae814e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 179123 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િI>b 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�E+=*#$Yf8)8vJb1}=9_dWABXCqD%pWa_q_sbD7Q@=YUrk0Qi3$a5 zS=Fn5S&oE`_j|oFZ_D+yPvE4}!D9m%`DxdI?vkAD0akeTcH_tF-D0v#6b<JE&NfK_ zTX%VLOs-hrhlr%QGRt0|)lr|OVGT_IxYgG{XkMeeXlgu1`0PG<>qA-#hksR^_wjm7 zyHWIrZM^A4S~+x3trRbH2sw_R%>kr3D@}`Ad<fwZBJQNp#*9s)AHw-+6Su3Zw2m;Q ztX9--vQGkF$=#1!a>QHe^23CtVu4>Z?VW2J{3z)kpX3whDnT;pQ~(JQt=qYXB@J*E z`j)AW*?o(cD5iT<t|Cxs$uDpC0Q9|{P7$4LAoete%eSS6F5OI9c5SqhNTRh_qxhZp zE9L{JcV-FLA8=JN7I<Ae!3im?%4ORH<WoaU_g~W{!#|e^C@Jh*5m~F!2&YJjL!01t z#KlcO@dNW7y+piqs)I+7;Urt;$*`G>yBSl?%1T*pj(Mhn8j{Dn581t?JSt0V5nBup zr#y!T7rD<{n%b)KmcUc)W!X;ML^VqfRTr`;J7%D^sWcAewPS3<tX8X$T%$~xQ1KLh zo6sfW(Rq*q==-rD@s<}%PG7t!NQe~{=kJ5Eiit(=sPh@sUD0I4Xpau%H0k-tOki_@ z>Ce~Ry+HK#%)_m*%Bm%7Bv(isWuwV62RP1+#>ej!2Qj+T=BZoXm#6Wy3UVW{q2*z< z@rS&i9x~qb_2{|suO76K^2N~rF(LZ$2rNs7eOSh<ap%VjfC`dgQkH=2dI5>LQTmIn zs}!8X)6LuL!GWy)qr&XsXculW*zV%^Ry5-MOb((ryxiJ%Cx`H(sK&F;m6Q~7!O!vC z`|u^VfW1L8oov2Rb`wihRWZ)9!bo!BorY5!dP~IeN!4lP8VE}?c-#Y_F|1E1rkJO> zBWVLXZL-bA1f}|`HzG2gWIPxB5rfkv1m8VAtDcb_5=R!u@k{#%ig#pGw$cHCR+Hr5 zd1G%;zQVt#Y=sQ=)Usc9PfI}KRWvm<#wnKnqi>}xq9`DTU~DRG$XyPwkeG`2E<^~9 z1&<Yl@;SvESph0}VyFNEI!~2Ii>q0EFWm84d0}$Qm)aI=vo5>J3`D#EewALs?q%>$ z@M^VD&z-q@4bALulo1vxhQoh~v4TRv=2;hSa6}{Y1|+KPk77;>mo;O=uHxRMw>eAk z7vDV{S2n#u$!h_Sb{UOcO%x1)s1_JLQBdAdGv4_Qi*{X;DY~bykvu!-m0l2MO}oFY zoj?y88S9M<OQAU611o0;?ug0^7CWxY+3|7<?;{AOPnf{wsih(l0ah8F=?@5`y3n5O zsJmEbk(ppOc_B}v%psuW&rkNnpD)nIZ=6%e{wIU(t}0^KqHE#{dBwq78Syz!7b4c3 zwVNLfw@!$*{W`F{E|W*dFA<VE!~M|45Ru4QSjr49k7>%`oTX3Pt<KN!=oq;;=IU<8 z{rqx=7u{D7W-xuQ-Q}Gc^D0+JA1#j0Q0k`(ClEMV2`(aRZ8wYc_JzCem`DDlOp$B< z-I+r<`sndAhxF!9`Ln%iBM~e|Ck3?s0k3TBc<n&WT8QJMMtBc+?7e^>uJkvjXnXVh z@t49=W46kmh%(uFe23)?AE)?l>z^8!+%2xlBN?%1#N)wfUGsT*XQ2$?C<r~xAQ>Hs z7l_NKoC9Hdf!j0clfh+YVU3pj_<^e<i#s)@aQ)Eq8~ZB9-{9g0j9(B_>6zgUYthHO z@OLWR-Dj4~rz<31GS4IxH>WyWR-MYLi=30VJEB({YJI$KH44~;$Wc3OGGHbm^%0** ziQLKnvC7vZer-+o4bB=FdCD;%0&*Vb>$y@(usr;yEc18C&R7P2#j2hLbxm!ftxlYG zL57dNB2tJlBHmbj4EQLC8|5bYBjlI!K$YGXzdv13h@wQLr^?tUlMl|vf3IO&>>fp} z<)tCo_(&c+s?x`_Au7Wp^*XS3644_m�-ID=%B|=h~b5ZOc}~$w;f(<4)0Z?9))3 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png deleted file mode 100644 index c531f719c85429fa6192eae82bb434e0318de801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13152 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 diff --git a/.pipelines/store/PDP/PDP/en-US/PDP.xml b/.pipelines/store/PDP/PDP/en-US/PDP.xml index 15d0bdf5270..ce36a3677f7 100644 --- a/.pipelines/store/PDP/PDP/en-US/PDP.xml +++ b/.pipelines/store/PDP/PDP/en-US/PDP.xml @@ -55,33 +55,8 @@ PowerShell is Open Source. See https://github.com/powershell/powershell </Descr <ScreenshotCaptions> <!-- Valid length: 200 character limit, up to 9 elements per platform --> <!-- Valid attributes: any of DesktopImage, MobileImage, XboxImage, SurfaceHubImage, and HoloLensImage --> - <Caption DesktopImage="Prompt.png" _locID="App_caption1"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 1" --> - Prompt - </Caption> - <Caption DesktopImage="Predictor_Inline.png" _locID="App_caption2"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 2" --> - Inline Prediction - </Caption> - <Caption DesktopImage="Predictor_ListView.png" _locID="App_caption3"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 3" --> - Prediction List View - </Caption> - <Caption DesktopImage="Error.png" _locID="App_caption4"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 4" --> - Error Feedback Provider - </Caption> - <Caption DesktopImage="Feedback_Provider.png" _locID="App_caption5"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 5" --> - Feedback Provider - </Caption> - <Caption DesktopImage="Experimental_Features.png" _locID="App_caption6"> - <!-- _locComment_text="{MaxLength=200} Screenshot caption 6" --> - Experimental Features - </Caption> </ScreenshotCaptions> <AdditionalAssets> - <Icon FileName="pwshLogo.png" /> <!-- Valid elements:--> <!-- HeroImage414x180, HeroImage846x468, HeroImage558x756, HeroImage414x468, HeroImage558x558, HeroImage2400x1200,--> <!-- ScreenshotWXGA, ScreenshotHD720, ScreenshotWVGA, Doublewide, Panoramic, Square,--> diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index e461bb6efd9..97d2f4fc46a 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -12,7 +12,6 @@ jobs: variables: - group: msixTools - group: 'Azure Blob variable group' - - group: 'Store Publish Variables' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - name: ob_sdl_tsa_configFile @@ -153,199 +152,3 @@ jobs: Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts - - - pwsh: | - Write-Verbose -Verbose "Pipeline.Workspace: $(Pipeline.Workspace)" - Get-ChildItem -Path $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)" - Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName - Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose - displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - - - template: channelSelection.yml@self - - - pwsh: | - $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' - $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' - - Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" - - # Define app configurations for each channel - $channelConfigs = @{ - 'LTS' = @{ - AppStoreName = 'PowerShell-LTS' - ProductId = '$(productId-LTS)' - AppId = '$(AppID-LTS)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Stable' = @{ - AppStoreName = 'PowerShell' - ProductId = '$(productId-Stable)' - AppId = '$(AppID-Stable)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Preview' = @{ - AppStoreName = 'PowerShell (Preview)' - ProductId = '$(productId-Preview)' - AppId = '$(AppID-Preview)' - ServiceEndpoint = "StoreAppPublish-Preview" - } - } - - $currentChannel = if ($IsLTS) { 'LTS' } - elseif ($IsStable) { 'Stable' } - elseif ($IsPreview) { 'Preview' } - else { - Write-Error "No valid channel detected" - exit 1 - } - - $config = $channelConfigs[$currentChannel] - Write-Verbose -Verbose "Selected channel: $currentChannel" - Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" - Write-Verbose -Verbose "Product ID: $($config.ProductId)" - - # Update PDP.xml file - $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' - if (Test-Path $pdpPath) { - Write-Verbose -Verbose "Updating PDP file: $pdpPath" - - [xml]$pdpXml = Get-Content $pdpPath -Raw - - # Create namespace manager for XML with default namespace - $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) - $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - - $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) - if ($appStoreNameElement) { - $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) - Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" - } else { - Write-Warning "AppStoreName element not found in PDP file" - } - - $pdpXml.Save($pdpPath) - Write-Verbose -Verbose "PDP file updated successfully" - Get-Content -Path $pdpPath | Write-Verbose -Verbose - } else { - Write-Error "PDP file not found: $pdpPath" - exit 1 - } - - # Update SBConfig.json file - $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' - if (Test-Path $sbConfigPath) { - Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" - - $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json - - $sbConfigJson.appSubmission.productId = $config.ProductId - Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" - - $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 - Write-Verbose -Verbose "SBConfig file updated successfully" - Get-Content -Path $sbConfigPath | Write-Verbose -Verbose - } else { - Write-Error "SBConfig file not found: $sbConfigPath" - exit 1 - } - - Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" - - # Select the correct bundle based on channel - $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') - Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" - - if ($IsLTS) { - $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } - } else { - # Catches Stable or Preview - $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } - } - - if (-not $bundleFile) { - Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" - exit 1 - } - - # Copy the selected bundle to a dedicated directory for store packaging - $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' - New-Item $storeBundleDir -Type Directory -Force > $null - Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose - Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" - Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" - - # These variables are used in the next tasks to determine which ServiceEndpoint to use - $ltsValue = $IsLTS.ToString().ToLower() - $stableValue = $IsStable.ToString().ToLower() - $previewValue = $IsPreview.ToString().ToLower() - - Write-Verbose -Verbose "About to set variables:" - Write-Verbose -Verbose " LTS=$ltsValue" - Write-Verbose -Verbose " STABLE=$stableValue" - Write-Verbose -Verbose " PREVIEW=$previewValue" - - Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" - Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" - Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" - - Write-Verbose -Verbose "Variables set successfully" - name: UpdateConfigs - displayName: Update PDPs and SBConfig.json - - - pwsh: | - Write-Verbose -Verbose "Checking variables after UpdateConfigs:" - Write-Verbose -Verbose "LTS=$(LTS)" - Write-Verbose -Verbose "STABLE=$(STABLE)" - Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" - displayName: Debug - Check Variables - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Preview)' - condition: eq(variables['PREVIEW'], 'true') - inputs: - serviceEndpoint: 'StoreAppPublish-Preview' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Stable' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - pwsh: | - Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | - Copy-Item -Destination "$(ob_outputDirectory)" -Verbose - displayName: Upload Store Failure Log - condition: failed() - - - pwsh: | - $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" - $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" - $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - - if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { - Write-Verbose -Verbose "Uploading StoreBroker Package files:" - Write-Verbose -Verbose "JSON File: $jsonFile" - Write-Verbose -Verbose "ZIP File: $zipFile" - - Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } - - else { - Write-Error "Required files not found in $submissionPackageDir" - } - displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml new file mode 100644 index 00000000000..7667b1361e7 --- /dev/null +++ b/.pipelines/templates/package-store-package.yml @@ -0,0 +1,242 @@ +jobs: +- job: CreateStorePackage + displayName: Create StoreBroker Package + pool: + type: windows + + variables: + - group: 'Azure Blob variable group' + - group: 'Store Publish Variables' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + + steps: + - checkout: self + clean: true + + - template: release-SetReleaseTagandContainerName.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_msixbundle_CreateMSIXBundle + itemPattern: | + **/*.msixbundle + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download signed msixbundle + + - pwsh: | + $bundleDir = '$(Build.ArtifactStagingDirectory)/downloads' + $bundle = Get-ChildItem -Path $bundleDir -Filter '*.msixbundle' -Recurse | Select-Object -First 1 + if (-not $bundle) { + Write-Error "No .msixbundle file found in $bundleDir" + exit 1 + } + Write-Verbose -Verbose "Found bundle: $($bundle.FullName)" + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$($bundle.DirectoryName)" + Write-Host "##$vstsCommandString" + displayName: Locate msixbundle + + - template: channelSelection.yml@self + + - pwsh: | + $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" + + # Define app configurations for each channel + $channelConfigs = @{ + 'LTS' = @{ + AppStoreName = 'PowerShell-LTS' + ProductId = '$(productId-LTS)' + AppId = '$(AppID-LTS)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Stable' = @{ + AppStoreName = 'PowerShell' + ProductId = '$(productId-Stable)' + AppId = '$(AppID-Stable)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Preview' = @{ + AppStoreName = 'PowerShell (Preview)' + ProductId = '$(productId-Preview)' + AppId = '$(AppID-Preview)' + ServiceEndpoint = "StoreAppPublish-Preview" + } + } + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" + Write-Verbose -Verbose "Product ID: $($config.ProductId)" + + # Update PDP.xml file + $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' + if (Test-Path $pdpPath) { + Write-Verbose -Verbose "Updating PDP file: $pdpPath" + + [xml]$pdpXml = Get-Content $pdpPath -Raw + + # Create namespace manager for XML with default namespace + $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) + $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") + + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) + if ($appStoreNameElement) { + $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) + Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" + } else { + Write-Warning "AppStoreName element not found in PDP file" + } + + $pdpXml.Save($pdpPath) + Write-Verbose -Verbose "PDP file updated successfully" + Get-Content -Path $pdpPath | Write-Verbose -Verbose + } else { + Write-Error "PDP file not found: $pdpPath" + exit 1 + } + + # Update SBConfig.json file + $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' + if (Test-Path $sbConfigPath) { + Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" + + $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json + + $sbConfigJson.appSubmission.productId = $config.ProductId + Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" + + $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 + Write-Verbose -Verbose "SBConfig file updated successfully" + Get-Content -Path $sbConfigPath | Write-Verbose -Verbose + } else { + Write-Error "SBConfig file not found: $sbConfigPath" + exit 1 + } + + Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" + name: UpdateConfigs + displayName: Update PDPs and SBConfig.json + + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Preview)' + condition: eq(variables['PREVIEW'], 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | + Copy-Item -Destination $outputDirectory -Verbose + displayName: Upload Store Failure Log + condition: failed() + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" + $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" + $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" + + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { + Write-Verbose -Verbose "Uploading StoreBroker Package files:" + Write-Verbose -Verbose "JSON File: $jsonFile" + Write-Verbose -Verbose "ZIP File: $zipFile" + + Copy-Item -Path $submissionPackageDir -Destination $outputDirectory -Verbose -Recurse + } + else { + Write-Error "Required files not found in $submissionPackageDir" + exit 1 + } + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index aaef3c6f269..cbbdb70cc4f 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -12,7 +12,7 @@ jobs: inputs: - input: pipelineArtifact pipeline: PSPackagesOfficial - artifactName: drop_msixbundle_CreateMSIXBundle + artifactName: drop_store_package_CreateStorePackage variables: - group: 'Store Publish Variables' - name: LTS @@ -107,28 +107,32 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), eq(variables['PREVIEW'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index ff40941e31b..b1efb2a8097 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -173,6 +173,12 @@ stages: parameters: OfficialBuild: ${{ parameters.OfficialBuild }} +- stage: store_package + displayName: 'Store Package' + dependsOn: [msixbundle] + jobs: + - template: /.pipelines/templates/package-store-package.yml@self + - stage: upload displayName: 'Upload' dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON From a625d2d451515542e912e50ab1a818d0c3b9e0b4 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 3 Apr 2026 12:42:34 -0700 Subject: [PATCH 331/378] Delay update notification for one week to ensure all packages become available (#27095) --- .../host/msh/UpdatesNotification.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index b7c001db710..eb4557c04d2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -28,6 +28,9 @@ internal static class UpdatesNotification private const string StableBuildInfoURL = "https://aka.ms/pwsh-buildinfo-stable"; private const string PreviewBuildInfoURL = "https://aka.ms/pwsh-buildinfo-preview"; + private const int NotificationDelayDays = 7; + private const int UpdateCheckBackoffDays = 7; + /// <summary> /// The version of new update is persisted using a file, not as the file content, but instead baked in the file name in the following template: /// `update{notification-type}_{version}_{publish-date}` -- held by 's_updateFileNameTemplate', @@ -89,9 +92,18 @@ internal static void ShowUpdateNotification(PSHostUserInterface hostUI) if (TryParseUpdateFile( updateFilePath: out _, out SemanticVersion lastUpdateVersion, - lastUpdateDate: out _) + out DateTime lastUpdateDate) && lastUpdateVersion != null) { + DateTime today = DateTime.UtcNow; + if ((today - lastUpdateDate).TotalDays < NotificationDelayDays) + { + // The update was out less than 1 week ago and it's possible the packages are still rolling out. + // We only show the notification when the update is at least 1 week old, to reduce the chance that + // users see the notification but cannot get the new update when they try to install it. + return; + } + string releaseTag = lastUpdateVersion.ToString(); string notificationMsgTemplate = s_notificationType == NotificationType.LTS ? ManagedEntranceStrings.LTSUpdateNotificationMessage @@ -169,7 +181,7 @@ internal static async Task CheckForUpdates() out DateTime lastUpdateDate); DateTime today = DateTime.UtcNow; - if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < 7) + if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < UpdateCheckBackoffDays) { // There is an existing update file, and the last update was less than 1 week ago. // It's unlikely a new version is released within 1 week, so we can skip this check. From 22f62e859d30aa3623d24d374110b41a310bbb81 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:58:53 -0700 Subject: [PATCH 332/378] Redo windows image fix to use latest image (#27198) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .../variables/PowerShell-Coordinated_Packages-Variables.yml | 2 +- .pipelines/templates/variables/PowerShell-vPack-Variables.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml index de3ac0ba1b6..dd67d509a8a 100644 --- a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -39,7 +39,7 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] - name: ReleaseTagVar diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml index 276911a35b3..7f00a5e0e2a 100644 --- a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -19,7 +19,7 @@ variables: - name: BuildConfiguration value: Release - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: Codeql.Enabled value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - name: DOTNET_CLI_TELEMETRY_OPTOUT From 601f0167e0a5229b2e9a6b145d0a382432bab5c9 Mon Sep 17 00:00:00 2001 From: StepSecurity Bot <bot@stepsecurity.io> Date: Tue, 7 Apr 2026 13:29:52 -0700 Subject: [PATCH 333/378] [StepSecurity] ci: Harden GitHub Actions (#27202) Signed-off-by: StepSecurity Bot <bot@stepsecurity.io> --- .github/workflows/copilot-setup-steps.yml | 3 +++ .github/workflows/windows-packaging-reusable.yml | 3 +++ .github/workflows/xunit-tests.yml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index be2dd55df7d..7c63c9122a8 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -10,6 +10,9 @@ on: paths: - ".github/workflows/copilot-setup-steps.yml" +permissions: + contents: read + jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. # See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 55715c42a4c..8b8df27a4e2 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -13,6 +13,9 @@ env: SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts +permissions: + contents: read + jobs: package: name: ${{ matrix.architecture }} - ${{ matrix.channel }} diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index a1c86bea70a..61d535ec49d 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -14,6 +14,9 @@ on: required: false default: testResults-xunit +permissions: + contents: read + jobs: xunit: name: Run xUnit Tests From 34375e9059c7e5339fdbd5790579b444e3dde37d Mon Sep 17 00:00:00 2001 From: StepSecurity Bot <bot@stepsecurity.io> Date: Tue, 7 Apr 2026 14:13:19 -0700 Subject: [PATCH 334/378] [StepSecurity] ci: Harden GitHub Actions (#27201) Signed-off-by: StepSecurity Bot <bot@stepsecurity.io> --- .github/actions/build/ci/action.yml | 4 ++-- .../get-changed-files/action.yml | 2 +- .../infrastructure/path-filters/action.yml | 2 +- .../actions/test/linux-packaging/action.yml | 8 ++++---- .github/actions/test/nix/action.yml | 6 +++--- .../test/process-pester-results/action.yml | 2 +- .github/actions/test/windows/action.yml | 4 ++-- .github/workflows/analyze-reusable.yml | 2 +- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/labels.yml | 4 ++-- .github/workflows/linux-ci.yml | 18 +++++++++--------- .github/workflows/macos-ci.yml | 18 +++++++++--------- .github/workflows/verify-markdown-links.yml | 2 +- .github/workflows/windows-ci.yml | 12 ++++++------ .../workflows/windows-packaging-reusable.yml | 6 +++--- .github/workflows/xunit-tests.yml | 6 +++--- 16 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index be9c0ecd20b..65331fb3185 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -13,7 +13,7 @@ runs: if: github.event_name != 'PullRequest' run: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json - name: Bootstrap @@ -34,7 +34,7 @@ runs: Invoke-CIBuild shell: pwsh - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build path: ${{ runner.workspace }}/build diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml index c897d4f388d..51631cfe141 100644 --- a/.github/actions/infrastructure/get-changed-files/action.yml +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -21,7 +21,7 @@ runs: steps: - name: Get changed files id: get-files - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 656719262b2..af23540256d 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -39,7 +39,7 @@ runs: - name: Check if GitHubWorkflowChanges is present id: filter - uses: actions/github-script@v7.0.1 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: FILES_JSON: ${{ steps.get-files.outputs.files }} with: diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 3a61e0751c7..ce37a38c8b7 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -11,7 +11,7 @@ runs: Show-Environment shell: pwsh - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -48,21 +48,21 @@ runs: shell: pwsh - name: Upload deb packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-deb path: ${{ runner.workspace }}/packages/*.deb if-no-files-found: ignore - name: Upload rpm packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-rpm path: ${{ runner.workspace }}/packages/*.rpm if-no-files-found: ignore - name: Upload tar.gz packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-tar path: ${{ runner.workspace }}/packages/*.tar.gz diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index 7f68e71c1f5..ab30e0d9ce6 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -29,7 +29,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -42,7 +42,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json @@ -101,7 +101,7 @@ runs: Write-LogGroupEnd -Title 'Bootstrap' - name: Extract Files - uses: actions/github-script@v7.0.0 + uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0 # v7.0.0 env: DESTINATION_FOLDER: "${{ github.workspace }}/bins" ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml index 27b94f6ebcb..44f2037626f 100644 --- a/.github/actions/test/process-pester-results/action.yml +++ b/.github/actions/test/process-pester-results/action.yml @@ -21,7 +21,7 @@ runs: - name: Upload testResults artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: junit-pester-${{ inputs.name }} path: ${{ runner.workspace }}/testResults diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 2c41f6aac5c..ddc5da4d664 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -29,7 +29,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -42,7 +42,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: .\global.json diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 0fe64afb19a..14651c7cd8e 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -41,7 +41,7 @@ jobs: with: fetch-depth: '0' - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 7c63c9122a8..d78e745a4a9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -25,7 +25,7 @@ jobs: # You can define any steps you want, and they will run before the agent starts. # If you do not check out your code, Copilot will do this for you. steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 61b5eebb88f..27ceac59bbd 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -18,11 +18,11 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify PR has label starting with 'cl-' id: verify-labels - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 49d1c0a055f..8f57190b1e9 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -76,7 +76,7 @@ jobs: contents: read steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check for merge conflict markers uses: "./.github/actions/infrastructure/merge-conflict-checker" @@ -88,7 +88,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -103,7 +103,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated CI @@ -121,7 +121,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated CI @@ -139,7 +139,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated Others @@ -157,7 +157,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated Others @@ -181,7 +181,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 @@ -255,7 +255,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Linux Packaging diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 5f363e0c265..99b6d8796c6 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -72,7 +72,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -86,7 +86,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -104,7 +104,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -122,7 +122,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -140,7 +140,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -167,10 +167,10 @@ jobs: - macos-15-large steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json - name: Bootstrap packaging @@ -229,7 +229,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml index df37ba3c513..19da648a959 100644 --- a/.github/workflows/verify-markdown-links.yml +++ b/.github/workflows/verify-markdown-links.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify markdown links id: verify diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 92bbf2f4c9e..3385a13cb54 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -60,7 +60,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -75,7 +75,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -89,7 +89,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated CI @@ -107,7 +107,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated CI @@ -125,7 +125,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated Others @@ -143,7 +143,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated Others diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 8b8df27a4e2..8d0255d4443 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -64,7 +64,7 @@ jobs: shell: pwsh - name: Setup .NET - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -84,7 +84,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 61d535ec49d..c643917edd0 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -23,12 +23,12 @@ jobs: runs-on: ${{ inputs.runner_os }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Setup .NET - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -49,7 +49,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: always() with: name: ${{ inputs.test_results_artifact_name }} From 0fe8748ea154f59778562010708b97a8db9d7f3f Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 7 Apr 2026 14:55:30 -0700 Subject: [PATCH 335/378] Change the display name of `PowerShell-LTS` MSIX package to "PowerShell LTS" (#27203) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 198fb91912e..96c60ae69ed 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4285,7 +4285,7 @@ function New-MSIXPackage $displayName += ' Preview' } elseif ($LTS) { $ProductName += '-LTS' - $displayName += '-LTS' + $displayName += ' LTS' } Write-Verbose -Verbose "ProductName: $productName" From 58b00b5bb0828dd074aede9a0e3e673842456b70 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 21:58:10 +0000 Subject: [PATCH 336/378] Pin ready-to-merge.yml reusable workflow to commit SHA (#27204) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 2 +- .github/workflows/macos-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 8f57190b1e9..77186125a9c 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -244,7 +244,7 @@ jobs: - infrastructure_tests # - analyze if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} linux_packaging: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 99b6d8796c6..55d852bb68a 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -243,6 +243,6 @@ jobs: - macos_test_unelevated_ci - macos_test_unelevated_others if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 3385a13cb54..8a57b8b9726 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -189,6 +189,6 @@ jobs: - analyze - windows_packaging if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} From 073f4d61bda965385232da22a332d54f6bdfce79 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 8 Apr 2026 13:28:20 -0700 Subject: [PATCH 337/378] Build, package, and create VPack for the PowerShell-LTS store package within the same `msixbundle-vpack` pipeline (#150) (#27209) --- .pipelines/MSIXBundle-vPack-Official.yml | 513 +++++++++++++++--- PowerShell.Common.props | 2 +- .../host/msh/ConsoleHost.cs | 2 +- .../host/msh/ManagedEntrance.cs | 4 +- .../resources/ManagedEntranceStrings.resx | 2 +- .../resources/RemotingErrorIdStrings.resx | 2 +- .../resources/TabCompletionStrings.resx | 4 +- .../utils/Telemetry.cs | 8 +- tools/packaging/packaging.psm1 | 4 +- 9 files changed, 450 insertions(+), 91 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 876da9c2aff..08edd0367bd 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -1,31 +1,56 @@ trigger: none +pr: none parameters: # parameters are shown up in ADO UI in a build queue time - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean default: true +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' - name: 'debug' displayName: 'Enable debug output' type: boolean default: false -- name: 'ReleaseTagVar' +- name: netiso + displayName: "Network Isolation Policy" type: string - displayName: 'Release Tag Var:' - default: 'fromBranch' + values: + - KS4 + - R1 + - Netlock + default: "R1" -name: msixbundle_vPack_$(date:yyMM).$(date:dd)$(rev:rrr) +name: msixbundle_vPack_$(Build.SourceBranchName)_Prod.True_Create.${{ parameters.createVPack }}_$(date:yyyyMMdd).$(rev:rr) variables: - CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] - system.debug: ${{ parameters.debug }} - BuildSolution: $(Build.SourcesDirectory)\dirs.proj - ReleaseTagVar: ${{ parameters.ReleaseTagVar }} - BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - POWERSHELL_TELEMETRY_OPTOUT: 1 + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: netiso + value: ${{ parameters.netiso }} + - group: certificate_logical_to_actual # used within signing task + - group: MSIXSigningProfile + - group: msixTools resources: repositories: @@ -34,27 +59,17 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main - pipelines: - - pipeline: PSPackagesOfficial - source: 'PowerShell-Packages-Official' - trigger: - branches: - include: - - master - - releases/* - extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + platform: + name: 'windows_undocked' # windows undocked featureFlags: WindowsHostVersion: Version: 2022 - platform: - name: 'windows_undocked' # windows undocked - + Network: ${{ variables.netiso }} cloudvault: enabled: false - globalSdl: useCustomPolicy: true # for signing code disableLegacyManifest: true @@ -78,71 +93,417 @@ extends: tsaOptionsFile: .config/tsaoptions.json stages: - - stage: build + - stage: Build_MSIX_Package + displayName: 'Build and create MSIX packages' + dependsOn: [] jobs: - - job: main + - job: Build pool: type: windows + strategy: + matrix: + x64: + Architecture: x64 + arm64: + Architecture: arm64 + variables: + ArtifactPlatform: 'windows' ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_build_$(Architecture) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + # The env variable 'ReleaseTagVar' will be updated in this step. + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $releaseTag = '$(ReleaseTagVar)' + if ($releaseTag -match '-') { + throw "Never release msixbundle vpack for a preview build. Current version: $releaseTag" + } + + # Check if release tag matches the expected format v#.#.# + $matched = $releaseTag -match '^v\d+\.(\d+)\.\d+$' + if (-not $matched) { + throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" + } + + # Extract minor version and verify it's even (LTS versions only) + $minorVersion = [int]$Matches[1] + if($minorVersion % 2 -ne 0) { + throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + ### START BUILD ### + + # Clone the checked out PowerShell repo to '/PowerShell' and set the variable 'PowerShellRoot'. + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + # Add CodeQL Init task right before your 'Build' step. + - task: CodeQL3000Init@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + # AnalyzeInPipeline: false = upload results + # AnalyzeInPipeline: true = do not upload results + AnalyzeInPipeline: false + Language: csharp + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $runtime = switch ($env:Architecture) + { + "x64" { "win7-x64" } + "arm64" { "win-arm64" } + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Architecture) -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore -ReleaseTag $(ReleaseTagVar) + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Verifying pdbs exist in build folder" + $pdbs = Get-ChildItem -Path $buildWithSymbolsPath -Recurse -Filter *.pdb + if ($pdbs.Count -eq 0) { + throw "No pdbs found in build folder" + } + else { + Write-Verbose -Verbose "Found $($pdbs.Count) pdbs in build folder" + $pdbs | ForEach-Object { + Write-Verbose -Verbose "Pdb: $($_.FullName)" + } + + $pdbs | Compress-Archive -DestinationPath '$(ob_outputDirectory)\symbols-$(Architecture).zip' -Update + } + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols folder' + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + # Add CodeQL Finalize task right after your 'Build' step. + - task: CodeQL3000Finalize@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(PowerShellRoot)\src' + ob_restore_phase: true + + # The signed files will be put in '$(ob_outputDirectory)\Signed-$(Runtime)' after this step. + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + OfficialBuild: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\Signed-$(Runtime)' -Recurse | Out-String -Width 9999 + displayName: Capture signed files + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -Width 9999 + displayName: Capture Environment + condition: succeededOrFailed() + + ### START Packaging ### + + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false + + - pwsh: | + Write-Verbose -Verbose "runtime = '$(Runtime)'" + Write-Verbose -Verbose "RepoRoot = '$(PowerShellRoot)'" + + $runtime = '$(Runtime)' + $repoRoot = '$(PowerShellRoot)' + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + Find-Dotnet + + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + $psoptionsFilePath = '$(ob_outputDirectory)\psoptions\psoptions.json' + + Write-Verbose -Verbose "signedFilesPath: $signedFilesPath" + Write-Verbose -Verbose "psoptionsFilePath: $psoptionsFilePath" + + Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose + if (-not (Test-Path $signedFilesPath\pwsh.exe)) { + throw "pwsh.exe not found in $signedFilesPath" + } + + Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose + + Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" + Get-PSOptions | Write-Verbose -Verbose + + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File + $msixPkgPath = $msixPkgFile.FullName + Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" + + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose + displayName: 'Build MSIX Package (Unsigned)' + + ### END OF Packaging ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' + + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] + jobs: + - job: Bundle + pool: + type: windows + variables: + ArtifactPlatform: 'windows' + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_pack_msixbundle ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell.app' + ob_createvpack_packagename: 'PowerShell7.Store.app' ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. ob_createvpack_propsFile: false ob_createvpack_provData: true ob_createvpack_metadata: '$(Build.SourceVersion)' ob_createvpack_versionAs: string - ob_createvpack_version: '$(version)' + ob_createvpack_version: '$(Version)' ob_createvpack_verbose: true steps: - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(version)' - if('$(version)' -match '-') { - throw "Don't release a preview build msixbundle package" - } - displayName: Stop any preview release - - - download: PSPackagesOfficial - artifact: 'drop_msixbundle_CreateMSIXBundle' - displayName: Download package - - - pwsh: | - $payloadDir = '$(Pipeline.Workspace)\PSPackagesOfficial\drop_msixbundle_CreateMSIXBundle' - Get-ChildItem $payloadDir -Recurse | Out-String -Width 150 - $vstsCommandString = "vso[task.setvariable variable=PayloadDir]$payloadDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Capture Artifact Listing' - - - pwsh: | - $bundlePackage = Get-ChildItem '$(PayloadDir)\*.msixbundle' - Write-Verbose -Verbose ("MSIX bundle package: " + $bundlePackage.FullName -join ', ') - if ($bundlePackage.Count -ne 1) { - throw "Expected to find 1 MSIX bundle package, but found $($bundlePackage.Count)" - } + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $bundlePackage.FullName -Destination $targetPath - displayName: 'Stage msixbundle for vpack' + - template: /.pipelines/templates/shouldSign.yml@self - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 150 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - stage: Publish_Symbols + displayName: 'Publish Symbols' + dependsOn: [Pack_MSIXBundle_And_Sign] + jobs: + - job: PublishSymbols + pool: + type: windows + variables: + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem Env: | Out-String -Width 9999 + displayName: 'Capture Environment Variables' + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for arm64 + + - pwsh: | + $downloadDir = '$(Build.ArtifactStagingDirectory)\downloads' + Write-Verbose -Verbose "Enumerating $downloadDir" + $downloadedArtifacts = Get-ChildItem -Path $downloadDir -Recurse -Filter 'symbols-*.zip' + $downloadedArtifacts | Out-String -Width 9999 + + $expandedRoot = New-Item -Path "$(Pipeline.Workspace)\expanded" -ItemType Directory -Verbose + $downloadedArtifacts | ForEach-Object { + $expandDir = Join-Path $expandedRoot $_.BaseName + Write-Verbose -Verbose "Expanding $($_.FullName) to $expandDir" + $null = New-Item -Path $expandDir -ItemType Directory -Verbose + Expand-Archive -Path $_.FullName -DestinationPath $expandDir -Force + } + + Write-Verbose -Verbose "Enumerating $expandedRoot" + Get-ChildItem -Path $expandedRoot -Recurse | Out-String -Width 9999 + $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$expandedRoot" + Write-Verbose -Message "$vstsCommandString" -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Expand and capture symbols folders + + - task: PublishSymbols@2 + condition: and(succeeded(), ${{ parameters.createVPack }}) + inputs: + symbolsFolder: '$(SymbolsPath)' + searchPattern: '**/*.pdb' + indexSources: false + publishSymbols: true + symbolServerType: TeamServices + detailedLog: true diff --git a/PowerShell.Common.props b/PowerShell.Common.props index fa2a5305e32..d71432aed2f 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -163,7 +163,7 @@ <PropertyGroup> <DefineConstants>$(DefineConstants);CORECLR</DefineConstants> - <IsWindows Condition="'$(IsWindows)' =='true' or ( '$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> + <IsWindows Condition="'$(IsWindows)' == 'true' or ('$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> </PropertyGroup> <!-- Define non-windows, all configuration properties --> diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 2d9902d176a..daf69d50251 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -321,7 +321,7 @@ internal static int Start( } s_theConsoleHost.BindBreakHandler(); - PSHost.IsStdOutputRedirected = Console.IsOutputRedirected; + IsStdOutputRedirected = Console.IsOutputRedirected; // Send startup telemetry for ConsoleHost startup ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal", s_cpp.ParametersUsedAsDouble); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs index 6dfd5d54e6f..acfdea07153 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs @@ -86,9 +86,9 @@ public static int Start([MarshalAs(UnmanagedType.LPArray, ArraySubType = Unmanag int exitCode = 0; try { - var banner = string.Format( + string banner = string.Format( CultureInfo.InvariantCulture, - ManagedEntranceStrings.ShellBannerNonWindowsPowerShell, + ManagedEntranceStrings.ShellBannerPowerShell, PSVersionInfo.GitCommitId); ConsoleHost.DefaultInitialSessionState = InitialSessionState.CreateDefault2(); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index 2c0b0154757..44ebf0fb538 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -117,7 +117,7 @@ <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> - <data name="ShellBannerNonWindowsPowerShell" xml:space="preserve"> + <data name="ShellBannerPowerShell" xml:space="preserve"> <value>PowerShell {0}</value> </data> <data name="ShellBannerCLMode" xml:space="preserve"> diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 819270da259..b5905f1cf7a 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -849,7 +849,7 @@ Note that 'Start-Job' is not supported by design in scenarios where PowerShell i <value>The WriteEvents parameter cannot be used without the Wait parameter.</value> </data> <data name="PowerShellVersionNotSupported" xml:space="preserve"> - <value>PowerShell remoting endpoint versioning is not supported on PowerShell Core.</value> + <value>PowerShell remoting endpoint versioning is not supported on PowerShell 7+.</value> </data> <data name="JobManagerRegistrationConstructorError" xml:space="preserve"> <value>The following type cannot be instantiated because its constructor is not public: {0}.</value> diff --git a/src/System.Management.Automation/resources/TabCompletionStrings.resx b/src/System.Management.Automation/resources/TabCompletionStrings.resx index 751e04cfd2b..298de92da3c 100644 --- a/src/System.Management.Automation/resources/TabCompletionStrings.resx +++ b/src/System.Management.Automation/resources/TabCompletionStrings.resx @@ -457,10 +457,10 @@ This must be the last parameter on the #requires statement line.</value> Specifies the minimum version of PowerShell that the script requires.</value> </data> <data name="RequiresPsEditionCoreDescription" xml:space="preserve"> - <value>Specifies that the script requires PowerShell Core to run.</value> + <value>Specifies that the script requires PowerShell 7+ to run.</value> </data> <data name="RequiresPsEditionDesktopDescription" xml:space="preserve"> - <value>Specifies that the script requires Windows PowerShell to run.</value> + <value>Specifies that the script requires Windows PowerShell 5.1 to run.</value> </data> <data name="RequiresModuleSpecModuleNameDescription" xml:space="preserve"> <value>[string] diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index f72ac4eade4..9a67f4bb6ed 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -166,7 +166,7 @@ public static class ApplicationInsightsTelemetry private static readonly string s_uuidPath; /// <summary>Gets a value indicating whether telemetry can be sent.</summary> - public static bool CanSendTelemetry { get; private set; } = false; + public static bool CanSendTelemetry { get; private set; } /// <summary> /// Initializes static members of the <see cref="ApplicationInsightsTelemetry"/> class. @@ -774,11 +774,11 @@ internal static void SendUseTelemetry(string featureName, string detail, double if (string.Compare(featureName, s_subsystemRegistration, true) == 0) { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); } else { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); } } @@ -794,7 +794,7 @@ internal static void SendExperimentalUseData(string featureName, string detail) return; } - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); + SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); } // Get the experimental feature name. If we can report it, we'll return the name of the feature, otherwise, we'll return "anonymous" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 96c60ae69ed..361f82769f0 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4318,8 +4318,7 @@ function New-MSIXPackage Write-Verbose "Using LTS assets" -Verbose } - # Appx manifest needs to be in root of source path, but the embedded version needs to be updated - # cp-459155 is 'CN=Microsoft Windows Store Publisher (Store EKU), O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + # Appx manifest needs to be in root of source path, but the embedded version needs to be updated. # authenticodeFormer is 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' $releasePublisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' @@ -4361,7 +4360,6 @@ function New-MSIXPackage else { Copy-Item -Path "$RepoRoot\assets\$_.png" -Destination "$ProductSourcePath\assets\" } - } if ($PSCmdlet.ShouldProcess("Create .msix package?")) { From 9c1272039cf8eab566a048fbfba8007567983cd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:35:19 -0400 Subject: [PATCH 338/378] Bump actions/checkout from 6.0.0 to 6.0.2 (#27206) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/scorecards.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 14651c7cd8e..bb90de8e264 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: '0' diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 79f45e9eb4d..3b610326e44 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: 'Dependency Review' uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index b84ed640102..7b3711666aa 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From 25e80cefdb14d0c69eaa976314e31d035aeddd73 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:27:13 -0500 Subject: [PATCH 339/378] Fix the package pipeline by adding in PDP-Media directory (#27254) --- .pipelines/store/PDP/PDP-Media/en-US/.gitkeep | 0 .pipelines/templates/package-store-package.yml | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/.gitkeep diff --git a/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep b/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml index 7667b1361e7..6abddae6851 100644 --- a/.pipelines/templates/package-store-package.yml +++ b/.pipelines/templates/package-store-package.yml @@ -195,6 +195,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' @@ -206,6 +207,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - pwsh: | $outputDirectory = "$(ob_outputDirectory)" From 30d14eafaa02d2815970b99d14e00de297909b6d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 17:30:19 -0400 Subject: [PATCH 340/378] Externalize `findMissingNotices` target framework selection with ordered Windows fallback (#27269) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk <travis.plunk@microsoft.com> --- tools/findMissingNotices.ps1 | 113 ++++++++++++++++++++++---- tools/findMissingNotices.targets.json | 5 ++ 2 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 tools/findMissingNotices.targets.json diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 884eff50664..5ed931c5caa 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -16,6 +16,45 @@ Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" . "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" +$targetsConfigPath = Join-Path -Path $PSScriptRoot -ChildPath 'findMissingNotices.targets.json' +if (-not (Test-Path -LiteralPath $targetsConfigPath)) { + throw "Missing target framework config file '$targetsConfigPath'. Add '/tools/findMissingNotices.targets.json' with 'dotnetTargetName' and 'windowsTargetNames' entries." +} + +try { + $targetsConfig = Get-Content -LiteralPath $targetsConfigPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop +} catch { + throw "Failed to load target framework config from '$targetsConfigPath'. Ensure the file contains valid JSON. Error: $($_.Exception.Message)" +} + +if ($targetsConfig -isnot [hashtable]) { + throw "Invalid target framework config '$targetsConfigPath': expected a JSON object with 'dotnetTargetName' and 'windowsTargetNames'." +} + +if (-not $targetsConfig.ContainsKey('dotnetTargetName') -or [string]::IsNullOrWhiteSpace($targetsConfig['dotnetTargetName'])) { + throw "Invalid target framework config '$targetsConfigPath': 'dotnetTargetName' must be a non-empty string." +} + +if (-not $targetsConfig.ContainsKey('windowsTargetNames')) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be present and must be an array." +} + +if ($null -eq $targetsConfig['windowsTargetNames'] -or $targetsConfig['windowsTargetNames'] -isnot [array]) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be an array (empty array is allowed)." +} + +$script:dotnetTargetName = [string]$targetsConfig['dotnetTargetName'] +$script:windowsTargetNames = @() +foreach ($windowsTargetName in $targetsConfig['windowsTargetNames']) { + if ($windowsTargetName -isnot [string] -or [string]::IsNullOrWhiteSpace($windowsTargetName)) { + throw "Invalid target framework config '$targetsConfigPath': every entry in 'windowsTargetNames' must be a non-empty string." + } + + $script:windowsTargetNames += $windowsTargetName +} + +# Empty windowsTargetNames is valid and means "use base target fallback only". + $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { $null = Register-PackageSource -Name $packageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet @@ -195,8 +234,7 @@ function Get-CGRegistrations { $registrationChanged = $false - $dotnetTargetName = 'net11.0' - $dotnetTargetNameWin7 = 'net11.0-windows8.0' + $baseTargetName = $script:dotnetTargetName $unixProjectName = 'powershell-unix' $windowsProjectName = 'powershell-win-core' $actualRuntime = $Runtime @@ -204,35 +242,30 @@ function Get-CGRegistrations { switch -regex ($Runtime) { "alpine-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "linux-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "osx-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" - } - "win-x*" { - $sdkToUse = $winDesktopSdk - $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "win-.*" { + $sdkToUse = $winDesktopSdk $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } "modules" { $folder = "modules" $actualRuntime = 'linux-x64' - $target = "$dotnetTargetName|$actualRuntime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } Default { throw "Invalid runtime name: $Runtime" @@ -247,6 +280,50 @@ function Get-CGRegistrations { dotnet restore --runtime $actualRuntime "/property:SDKToUse=$sdkToUse" } $null = New-PADrive -Path $PSScriptRoot\..\src\$folder\obj\project.assets.json -Name $folder + + if ($Runtime -like "win-*") { + # Windows target selection is optional and ordered: + # 1. Try full Windows TFMs from config in order. + # 2. Fall back to the base non-Windows TFM if present. + try { + $availableTargets = @(Get-ChildItem -Path "${folder}:/targets" -ErrorAction Stop | Select-Object -ExpandProperty Name) + } catch { + throw "Unable to enumerate available targets for runtime '$Runtime' in '$folder'. Ensure dotnet restore succeeded and project.assets.json contains target data. Error: $($_.Exception.Message)" + } + + $selectedTargetName = $null + + foreach ($windowsTargetName in $script:windowsTargetNames) { + if ($windowsTargetName -in $availableTargets) { + $selectedTargetName = $windowsTargetName + break + } + } + + if (-not $selectedTargetName -and $baseTargetName -in $availableTargets) { + Write-Verbose "No configured windows target matched for '$Runtime'. Falling back to base target '$baseTargetName'." -Verbose + $selectedTargetName = $baseTargetName + } + + if (-not $selectedTargetName) { + Write-Verbose "Available targets for '$folder': $($availableTargets -join ', ')" -Verbose + if ($script:windowsTargetNames.Count -eq 0) { + throw "Unable to find a target for '$Runtime'. Tried fallback base target '$baseTargetName' (no windowsTargetNames configured). Ensure project.assets.json contains this target or update dotnetTargetName in '$targetsConfigPath'." + } + + throw "Unable to find a target for '$Runtime'. Tried configured windowsTargetNames '$($script:windowsTargetNames -join "', '")' and fallback base target '$baseTargetName'. Update '$targetsConfigPath' with a valid windows target from the available list." + } + + $target = "$selectedTargetName|$actualRuntime" + $neutralTarget = $selectedTargetName + } + + # Defensive check: non-Windows paths set targets in the switch block, + # Windows path may override them after inspecting available assets targets. + if (-not $target -or -not $neutralTarget) { + throw "Unable to determine restore targets for runtime '$Runtime'." + } + try { $targets = Get-ChildItem -Path "${folder}:/targets/$target" -ErrorAction Stop | Where-Object { $_.Type -eq 'package' } | select-object -ExpandProperty name $targets += Get-ChildItem -Path "${folder}:/targets/$neutralTarget" -ErrorAction Stop | Where-Object { $_.Type -eq 'project' } | select-object -ExpandProperty name diff --git a/tools/findMissingNotices.targets.json b/tools/findMissingNotices.targets.json new file mode 100644 index 00000000000..a347ee4c3be --- /dev/null +++ b/tools/findMissingNotices.targets.json @@ -0,0 +1,5 @@ +{ + "dotnetTargetName": "net11.0", + "windowsTargetNames": [ + ] +} From 72be78e6beb39c122297478b3d6d0135cbca7367 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:01:35 -0500 Subject: [PATCH 341/378] Remove MSI from publishing pipeline (#27213) Co-authored-by: Justin Chung <chungjustin@microsoft.com> Co-authored-by: Aditya Patwardhan <adityap@microsoft.com> --- .github/CONTRIBUTING.md | 16 +- ...rshell-module-organization.instructions.md | 2 +- .../templates/packaging/windows/package.yml | 19 +- .../templates/packaging/windows/sign.yml | 109 +-- .pipelines/templates/release-githubNuget.yml | 7 + .../release-validate-packagenames.yml | 6 +- .pipelines/templates/uploadToAzure.yml | 20 +- .../RegisterMicrosoftUpdate.ps1 | 70 -- assets/wix/ExeLicense.rtf | 206 ------ assets/wix/Product.wxs | 654 ------------------ assets/wix/WixUIBannerBmp.png | Bin 3855 -> 0 bytes assets/wix/WixUIDialogBmp.png | Bin 30804 -> 0 bytes assets/wix/WixUIInfoIco.png | Bin 1638 -> 0 bytes assets/wix/bundle.wxs | 40 -- build.psm1 | 5 - docs/maintainers/releasing.md | 12 +- .../powershell-win-core.csproj | 2 +- test/perf/benchmarks/assets/compiler.test.ps1 | 20 - .../Installer/WindowsInstaller.Tests.ps1 | 39 -- tools/UpdateDotnetRuntime.ps1 | 28 - tools/ci.psm1 | 66 +- tools/packaging/boms/windows.json | 5 - tools/packaging/packaging.psd1 | 3 - tools/packaging/packaging.psm1 | 470 +------------ 24 files changed, 53 insertions(+), 1746 deletions(-) delete mode 100644 assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 delete mode 100644 assets/wix/ExeLicense.rtf delete mode 100644 assets/wix/Product.wxs delete mode 100644 assets/wix/WixUIBannerBmp.png delete mode 100644 assets/wix/WixUIDialogBmp.png delete mode 100644 assets/wix/WixUIInfoIco.png delete mode 100644 assets/wix/bundle.wxs delete mode 100644 test/powershell/Installer/WindowsInstaller.Tests.ps1 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 776a9a8c60f..35eab8c9b5b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -91,7 +91,7 @@ To run the link-checker, follow these steps: 1. Issues marked as [`First-Time-Issue`][first-time-issue], are identified as being easy and a great way to learn about this project and making contributions. - + ### Finding or creating an issue 1. Follow the instructions in [Contributing to Issues][contribute-issues] to find or open an issue. @@ -264,18 +264,10 @@ Please see PowerShell [Testing Guidelines - Running Tests Outside of CI][running * Our CI contains automated spell checking and link checking for Markdown files. If there is any false-positive, [run the spell checker command-line tool in interactive mode](#spell-checking-documentation) to add words to the `.spelling` file. -* Our packaging test may not pass and ask you to update `files.wxs` file if you add/remove/update nuget package references or add/remove assert files. - - You could update the file manually in accordance with messages in the test log file. Or you can use automatically generated file. To get the file you should build the msi package locally: - - ```powershell - Import-Module .\build.psm1 - Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration Release -ReleaseTag <release tag> - Import-Module .\tools\packaging - Start-PSPackage -Type msi -ReleaseTag <release tag> -WindowsRuntime 'win7-x64' -SkipReleaseChecks - ``` - Last command will report where new file is located. + You could update the `.spelling` file manually in accordance with messages in the test log file, or + [run the spell checker command-line tool in interactive mode](#spell-checking-documentation) + to add the false-positive words directly. #### Pull Request - Workflow diff --git a/.github/instructions/powershell-module-organization.instructions.md b/.github/instructions/powershell-module-organization.instructions.md index 461d19fb5df..9cdba06c364 100644 --- a/.github/instructions/powershell-module-organization.instructions.md +++ b/.github/instructions/powershell-module-organization.instructions.md @@ -83,7 +83,7 @@ PowerShell code in GitHub Actions YAML files should be kept minimal. Move code t **Examples**: - `Start-PSPackage` - Create packages -- `New-MSIPackage` - Create Windows MSI +- `New-MSIXPackage` - Create Windows MSIX - `New-DotnetSdkContainerFxdPackage` - Create container packages **When NOT to use**: diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 1cc0e9d0e94..8b0e230b6b8 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -161,9 +161,9 @@ jobs: } $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix') } - 'x86' { @('msi', 'zip', 'msix') } - 'arm64' { @('msi', 'zip', 'msix') } + 'x64' { @('zip', 'msix') } + 'x86' { @('zip', 'msix') } + 'arm64' { @('zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -193,9 +193,9 @@ jobs: Write-Verbose -Verbose "runtime = '$(Runtime)'" $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix') } - 'x86' { @('msi', 'zip', 'msix') } - 'arm64' { @('msi', 'zip', 'msix') } + 'x64' { @('zip', 'msix') } + 'x86' { @('zip', 'msix') } + 'arm64' { @('zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -205,13 +205,6 @@ jobs: New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - if ($packageTypes -contains 'msi') { - $msiPkgNameFilter = "powershell-*.msi" - $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "unsigned msiPkgPath: $msiPkgPath" - Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { $zipPkgNameFilter = "powershell-*.zip" $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml index f7a2e5e03e8..151b5d676fb 100644 --- a/.pipelines/templates/packaging/windows/sign.yml +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -67,110 +67,25 @@ jobs: - template: /.pipelines/templates/install-dotnet.yml@self - # Import build.psm1 and bootstrap packaging dependencies (WiX Toolset) + # Import build.psm1 and bootstrap packaging dependencies - pwsh: | $repoRoot = "$env:REPOROOT" Import-Module "$repoRoot\build.psm1" Import-Module "$repoRoot\tools\packaging" Write-Verbose -Verbose "Modules imported successfully" - - # Install WiX Toolset for EXE package creation - $isArm64 = '$(Runtime)' -eq 'arm64' - $env:RUNTIME = '$(Runtime)' - Start-PSBootstrap -Scenario Package - displayName: 'Import modules and install WiX Toolset' + displayName: 'Import modules' env: ob_restore_phase: true - # Sign MSI packages - - task: onebranch.pipeline.signing@1 - displayName: Sign MSI packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.msi' - search_root: '$(Pipeline.Workspace)' - - # Create EXE package from signed MSI (for x64, x86, arm64 only) - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $version = '$(Version)' - - $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiLocation: $msiLocation" - - Set-Location $repoRoot - - $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation - Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" - Write-Host "##vso[task.setvariable variable=exePath]$exePath" - Write-Verbose -Verbose "exePath: $exePath" - - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: 'Make exe and expand package' - - # Sign EXE engine - - task: onebranch.pipeline.signing@1 - displayName: Sign exe engine - inputs: - command: 'sign' - signing_profile: $(msft_3rd_party_cert_id) - files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' - search_root: '$(Pipeline.Workspace)' - - # Compress signed EXE engine back into package - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $exePath = '$(exePath)' - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: Compress signed exe package - - # Sign final EXE packages - - task: onebranch.pipeline.signing@1 - displayName: Sign exe packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.exe' - search_root: '$(Pipeline.Workspace)' - # Copy all signed packages to output directory - pwsh: | $runtime = '$(Runtime)' Write-Verbose -Verbose "runtime = '$(Runtime)'" $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix', 'exe') } - 'x86' { @('msi', 'zip', 'msix', 'exe') } - 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'x64' { @('zip', 'msix') } + 'x86' { @('zip', 'msix') } + 'arm64' { @('zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -180,20 +95,6 @@ jobs: New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - if ($packageTypes -contains 'msi') { - $msiPkgNameFilter = "powershell-*.msi" - $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "signed msiPkgPath: $msiPkgPath" - Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - - if ($packageTypes -contains 'exe') { - $exePkgNameFilter = "powershell-*.exe" - $exePkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $exePkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "signed exePkgPath: $exePkgPath" - Copy-Item -Path $exePkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { $zipPkgNameFilter = "powershell-*.zip" $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 95698554c40..e7c36a49fe6 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -43,6 +43,13 @@ jobs: $exefiles | Remove-Item -Force -Verbose } + # The .msi packages should not be uploaded to GitHub release. + $msifiles = Get-ChildItem -Path $Path -Filter *.msi + if ($msifiles) { + Write-Verbose -Verbose "Remove .msi packages:" + $msifiles | Remove-Item -Force -Verbose + } + $OutputPath = Join-Path $Path 'hashes.sha256' $packages = Get-ChildItem -Path $Path -Include * -Recurse -File $checksums = $packages | diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 6344418cd8f..7271ffc05a8 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -94,8 +94,8 @@ jobs: - pwsh: | $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { - if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(msi|zip){1}') + Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip | ForEach-Object { + if($_.Name -notmatch 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(fxdependent|x64|arm64|x86|fxdependentWinDesktop)\.(zip){1}') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance @@ -104,7 +104,7 @@ jobs: } if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Zip and MSI Package Names + displayName: Validate Zip Package Names - pwsh: | $message = @() diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index ce7f26131cc..de6f8e0d7fd 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -149,10 +149,8 @@ jobs: buildType: 'current' artifact: drop_windows_package_package_win_arm64 itemPattern: | - **/*.msi **/*.msix **/*.zip - **/*.exe targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows arm64 packages @@ -185,10 +183,8 @@ jobs: buildType: 'current' artifact: drop_windows_package_package_win_x64 itemPattern: | - **/*.msi **/*.msix **/*.zip - **/*.exe targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows x64 packages @@ -197,10 +193,8 @@ jobs: buildType: 'current' artifact: drop_windows_package_package_win_x86 itemPattern: | - **/*.msi **/*.msix **/*.zip - **/*.exe targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows x86 packages @@ -246,17 +240,17 @@ jobs: - pwsh: | Write-Verbose -Verbose "Copying Github Release files in $(Build.ArtifactStagingDirectory)/downloads to use in Release Pipeline" - + Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force - Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | - Where-Object { $_.Extension -notin '.msix', '.nupkg' -and $_.Name -notmatch '-gc'} | + Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + Where-Object { $_.Extension -notin '.msix', '.nupkg' -and $_.Name -notmatch '-gc'} | Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose - + Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force - Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | - Where-Object { $_.Extension -eq '.nupkg' } | + Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)/downloads/*" -Recurse | + Where-Object { $_.Extension -eq '.nupkg' } | Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose displayName: Copy downloads to Artifacts @@ -395,7 +389,7 @@ jobs: } # To use -Include parameter, we need to use \* to get all files - $files = Get-ChildItem -Path $downloadsDirectory\* -Include @("*.deb", "*.tar.gz", "*.rpm", "*.msi", "*.zip", "*.pkg") + $files = Get-ChildItem -Path $downloadsDirectory\* -Include @("*.deb", "*.tar.gz", "*.rpm", "*.zip", "*.pkg") Write-Verbose -Verbose "files to upload." $files | Write-Verbose -Verbose diff --git a/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 b/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 deleted file mode 100644 index da89768f74a..00000000000 --- a/assets/MicrosoftUpdate/RegisterMicrosoftUpdate.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -param( - [ValidateSet('Hang', 'Fail')] - $TestHook -) - -$waitTimeoutSeconds = 300 -switch ($TestHook) { - 'Hang' { - $waitTimeoutSeconds = 10 - $jobScript = { Start-Sleep -Seconds 600 } - } - 'Fail' { - $jobScript = { throw "This job script should fail" } - } - default { - $jobScript = { - # This registers Microsoft Update via a predefined GUID with the Windows Update Agent. - # https://learn.microsoft.com/windows/win32/wua_sdk/opt-in-to-microsoft-update - - $serviceManager = (New-Object -ComObject Microsoft.Update.ServiceManager) - $isRegistered = $serviceManager.QueryServiceRegistration('7971f918-a847-4430-9279-4a52d1efe18d').Service.IsRegisteredWithAu - - if (!$isRegistered) { - Write-Verbose -Verbose "Opting into Microsoft Update as the Automatic Update Service" - # 7 is the combination of asfAllowPendingRegistration, asfAllowOnlineRegistration, asfRegisterServiceWithAU - # AU means Automatic Updates - $null = $serviceManager.AddService2('7971f918-a847-4430-9279-4a52d1efe18d', 7, '') - } - else { - Write-Verbose -Verbose "Microsoft Update is already registered for Automatic Updates" - } - - $isRegistered = $serviceManager.QueryServiceRegistration('7971f918-a847-4430-9279-4a52d1efe18d').Service.IsRegisteredWithAu - - # Return if it was successful, which is the opposite of Pending. - return $isRegistered - } - } -} - -Write-Verbose "Running job script: $jobScript" -Verbose -$job = Start-ThreadJob -ScriptBlock $jobScript - -Write-Verbose "Waiting on Job for $waitTimeoutSeconds seconds" -Verbose -$null = Wait-Job -Job $job -Timeout $waitTimeoutSeconds - -if ($job.State -ne 'Running') { - Write-Verbose "Job finished. State: $($job.State)" -Verbose - $result = Receive-Job -Job $job -Verbose - Write-Verbose "Result: $result" -Verbose - if ($result) { - Write-Verbose "Registration succeeded" -Verbose - exit 0 - } - else { - Write-Verbose "Registration failed" -Verbose - # at the time this was written, the MSI is ignoring the exit code - exit 1 - } -} -else { - Write-Verbose "Job timed out" -Verbose - Write-Verbose "Stopping Job. State: $($job.State)" -Verbose - Stop-Job -Job $job - # at the time this was written, the MSI is ignoring the exit code - exit 258 -} diff --git a/assets/wix/ExeLicense.rtf b/assets/wix/ExeLicense.rtf deleted file mode 100644 index 09b0b1402a5..00000000000 --- a/assets/wix/ExeLicense.rtf +++ /dev/null @@ -1,206 +0,0 @@ -{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;} -{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;} -{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} -{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1032\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f1033\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\f1035\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f1036\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f1037\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\f1038\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f1039\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f1040\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} -{\f1372\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f1373\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f1375\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f1376\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;} -{\f1379\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f1380\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f1402\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f1403\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;} -{\f1405\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f1406\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f1407\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f1408\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);} -{\f1409\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f1410\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} -{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;} -{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);} -{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} -{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} -{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;} -{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} -{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} -{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} -{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} -{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; -\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\chyperlink\ctint255\cshade255\red5\green99\blue193;\red96\green94\blue92;\red225\green223\blue221;} -{\*\defchp \f31506\fs24 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \sunhideused \spriority1 Default Paragraph Font;}{\* -\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv -\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\* -\cs15 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf19 \sbasedon10 \sunhideused \styrsid11998831 Hyperlink;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf20\chshdng0\chcfpat0\chcbpat21 \sbasedon10 \ssemihidden \sunhideused \styrsid11998831 -Unresolved Mention;}{\s17\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext17 \ssemihidden \sunhideused \styrsid11998831 Normal (Web);}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid203718\rsid534261\rsid10121125\rsid11155465 -\rsid11998831\rsid15422468\rsid15613908}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Travis Plunk}{\operator Travis Plunk} -{\creatim\yr2021\mo2\dy19\hr9\min23}{\revtim\yr2021\mo2\dy19\hr12\min33}{\version4}{\edmins5}{\nofpages1}{\nofwords75}{\nofchars430}{\nofcharsws504}{\vern6021}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}} -\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect -\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen -\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 -\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct -\asianbrkrule\rsidroot11998831\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 -{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang -{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang -{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} -\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15422468 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid15422468\charrsid15422468 This application is licensed under the\~}{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11155465 HYPERLINK "https://aka.ms/PowerShellLicense"}{\rtlch\fcs1 \af0 \ltrch\fcs0 -\insrsid11155465\charrsid15422468 {\*\datafield -00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b5a000000680074007400700073003a002f002f0061006b0061002e006d0073002f0050006f007700650072005300680065006c006c004c006900630065006e00730065000000795881f43b1d7f48af2c825dc4852763 -0000000085ab000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf19\insrsid15422468\charrsid15422468 MIT License}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15422468\charrsid15422468 -. -\par You may review the\~}{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11155465 HYPERLINK "https://aka.ms/PowerShellThirdPartyNotices"}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11155465\charrsid15422468 {\*\datafield -00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b6e000000680074007400700073003a002f002f0061006b0061002e006d0073002f0050006f007700650072005300680065006c006c0054006800690072006400500061007200740079004e006f007400690063006500 -73000000795881f43b1d7f48af2c825dc48527630000000085ab000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf19\insrsid15422468\charrsid15422468 ThirdPartyNotices}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid15422468\charrsid15422468 . -\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15422468\charrsid15422468 This application collects telemetry under the\~}{\field\fldedit{\*\fldinst {\rtlch\fcs1 -\af0 \ltrch\fcs0 \insrsid534261 HYPERLINK "https://aka.ms/PrivacyPolicy"}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid534261 {\*\datafield -00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b52000000680074007400700073003a002f002f0061006b0061002e006d0073002f00500072006900760061006300790050006f006c006900630079000000795881f43b1d7f48af2c825dc48527630000000085ab0000} -}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf19\insrsid15422468\charrsid15422468 Microsoft Privacy Statement}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15422468\charrsid15422468 -. To opt out, see\~}{\field\fldedit{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11155465 HYPERLINK "https://aka.ms/PowerShellTelemetryOptOut" \\o "Original URL:https://github.com/PowerShell/PowerS -hell/blob/master/README.md#telemetryClick to follow link."}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11155465\charrsid15422468 {\*\datafield -10d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b6a000000680074007400700073003a002f002f0061006b0061002e006d0073002f0050006f007700650072005300680065006c006c00540065006c0065006d0065007400720079004f00700074004f00750074000000 -795881f43b1d7f48af2c825dc48527630000000085ab000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs15\ul\cf19\insrsid15422468\charrsid15422468 here}}}\sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0 \ltrch\fcs0 -\insrsid15422468\charrsid15422468 .}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid11998831 -\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a -9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad -5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 -b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 -0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 -a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f -c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 -0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 -a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 -6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b -4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b -4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100b6f4679893070000c9200000160000007468656d652f7468656d652f -7468656d65312e786d6cec59cd8b1bc915bf07f23f347d97f5d5ad8fc1f2a24fcfda33b6b164873dd648a5eef2547789aad28cc56208de532e81c026e49085bd -ed21842cecc22eb9e48f31d8249b3f22afaa5bdd5552c99e191c3061463074977eefd5afde7bf5de53d5ddcf5e26d4bbc05c1096f6fcfa9d9aefe174ce16248d -7afeb3d9a4d2f13d2151ba4094a5b8e76fb0f03fbbf7eb5fdd454732c609f6403e1547a8e7c752ae8eaa5531876124eeb0154ee1bb25e30992f0caa3ea82a34b -d09bd06aa3566b55134452df4b51026a1f2f97648ebd9952e9dfdb2a1f53784da5500373caa74a35b6243476715e5708b11143cabd0b447b3eccb3609733fc52 -fa1e4542c2173dbfa6fffceabdbb5574940b517940d6909be8bf5c2e17589c37f49c3c3a2b260d823068f50bfd1a40e53e6edc1eb7c6ad429f06a0f91c569a71 -b175b61bc320c71aa0ecd1a17bd41e35eb16ded0dfdce3dc0fd5c7c26b50a63fd8c34f2643b0a285d7a00c1feee1c3417730b2f56b50866fede1dbb5fe28685b -fa3528a6243ddf43d7c25673b85d6d0159327aec8477c360d26ee4ca4b144443115d6a8a254be5a1584bd00bc6270050408a24493db959e1259a43140f112567 -9c7827248a21f056286502866b8ddaa4d684ffea13e827ed5174849121ad780113b137a4f87862cec94af6fc07a0d537206f7ffef9cdeb1fdfbcfee9cd575fbd -79fdf77c6eadca923b466964cafdf2dd1ffef3cd6fbd7ffff0ed2f5fff319b7a172f4cfcbbbffdeedd3ffef93ef5b0e2d2146ffff4fdbb1fbf7ffbe7dfffebaf -5f3bb4f7393a33e1339260e13dc297de5396c0021dfcf119bf9ec42c46c494e8a791402952b338f48f656ca11f6d10450edc00db767cce21d5b880f7d72f2cc2 -d398af2571687c182716f094313a60dc6985876a2ec3ccb3751ab927e76b13f714a10bd7dc43945a5e1eaf579063894be530c616cd2714a5124538c5d253dfb1 -738c1dabfb8210cbaea764ce99604be97d41bc01224e93ccc899154da5d03149c02f1b1741f0b7659bd3e7de8051d7aa47f8c246c2de40d4417e86a965c6fb68 -2d51e252394309350d7e8264ec2239ddf0b9891b0b099e8e3065de78818570c93ce6b05ec3e90f21cdb8dd7e4a37898de4929cbb749e20c64ce4889d0f6394ac -5cd829496313fbb938871045de13265df05366ef10f50e7e40e941773f27d872f787b3c133c8b026a53240d4376beef0e57dccacf89d6ee8126157aae9f3c44a -b17d4e9cd131584756689f604cd1255a60ec3dfbdcc160c05696cd4bd20f62c82ac7d815580f901dabea3dc5027a25d5dcece7c91322ac909de2881de073bad9 -493c1b9426881fd2fc08bc6eda7c0ca52e7105c0633a3f37818f08f480102f4ea33c16a0c308ee835a9fc4c82a60ea5db8e375c32dff5d658fc1be7c61d1b8c2 -be04197c6d1948eca6cc7b6d3343d49aa00c9819822ec3956e41c4727f29a28aab165b3be596f6a62ddd00dd91d5f42424fd6007b4d3fb84ffbbde073a8cb77f -f9c6b10f3e4ebfe3566c25ab6b763a8792c9f14e7f7308b7dbd50c195f904fbfa919a175fa04431dd9cf58b73dcd6d4fe3ffdff73487f6f36d2773a8dfb8ed64 -7ce8306e3b99fc70e5e3743265f3027d8d3af0c80e7af4b14f72f0d46749289dca0dc527421ffc08f83db398c0a092d3279eb838055cc5f0a8ca1c4c60e1228e -b48cc799fc0d91f134462b381daafb4a492472d591f0564cc0a1911e76ea5678ba4e4ed9223becacd7d5c16656590592e5782d2cc6e1a04a66e856bb3cc02bd4 -6bb6913e68dd1250b2d721614c6693683a48b4b783ca48fa58178ce620a157f65158741d2c3a4afdd6557b2c805ae115f8c1edc1cff49e1f06200242701e07cd -f942f92973f5d6bbda991fd3d3878c69450034d8db08283ddd555c0f2e4fad2e0bb52b78da2261849b4d425b46377822869fc17974aad1abd0b8aeafbba54b2d -7aca147a3e08ad9246bbf33e1637f535c8ede6069a9a9982a6de65cf6f35430899395af5fc251c1ac363b282d811ea3717a211dcbccc25cf36fc4d32cb8a0b39 -4222ce0cae934e960d122231f728497abe5a7ee1069aea1ca2b9d51b90103e59725d482b9f1a3970baed64bc5ce2b934dd6e8c284b67af90e1b35ce1fc568bdf -1cac24d91adc3d8d1797de195df3a708422c6cd795011744c0dd413db3e682c0655891c8caf8db294c79da356fa3740c65e388ae62945714339967709dca0b3a -faadb081f196af190c6a98242f8467912ab0a651ad6a5a548d8cc3c1aafb6121653923699635d3ca2aaa6abab39835c3b60cecd8f26645de60b53531e434b3c2 -67a97b37e576b7b96ea74f28aa0418bcb09fa3ea5ea12018d4cac92c6a8af17e1a56393b1fb56bc776811fa07695226164fdd656ed8edd8a1ae19c0e066f54f9 -416e376a6168b9ed2bb5a5f5adb979b1cdce5e40f2184197bba6526857c2c92e47d0104d754f92a50dd8222f65be35e0c95b73d2f3bfac85fd60d80887955a27 -1c57826650ab74c27eb3d20fc3667d1cd66ba341e31514161927f530bbb19fc00506dde4f7f67a7cefee3ed9ded1dc99b3a4caf4dd7c5513d777f7f5c6e1bb7b -8f40d2f9b2d598749bdd41abd26df627956034e854bac3d6a0326a0ddba3c9681876ba9357be77a1c141bf390c5ae34ea5551f0e2b41aba6e877ba9576d068f4 -8376bf330efaaff23606569ea58fdc16605ecdebde7f010000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d65 -2f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d36 -3f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e -3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d985 -0528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c020000130000000000000000000000 -0000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000 -000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c0000000000000000000000000019020000 -7468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d0014000600080000002100b6f4679893070000c92000001600000000000000 -000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b01000027000000 -000000000000000000009d0a00007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000980b00000000} -{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d -617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 -6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 -656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} -{\*\latentstyles\lsdstimax376\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong; -\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid; -\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid; -\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2; -\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1; -\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1; -\lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1; -\lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2; -\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3; -\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4; -\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; -\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; -\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; -\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; -\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; -\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; -\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; -\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; -\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; -\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; -\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; -\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;}}{\*\datastore }} \ No newline at end of file diff --git a/assets/wix/Product.wxs b/assets/wix/Product.wxs deleted file mode 100644 index 0b525288ae1..00000000000 --- a/assets/wix/Product.wxs +++ /dev/null @@ -1,654 +0,0 @@ -<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> - <!-- The URL for add/remove programs --> - <!-- TBD:Point to the actual release --> - <?define InfoURL="https://github.com/PowerShell/PowerShell" ?> - <?define ProductSimpleVersionWithNameAndOptionalArchitecture = "$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))"?> - <?if $(var.IsPreview)=True?> - <?define PwshPath = "[VersionFolder]preview"?> - <?define IconPath = "assets\Powershell_av_colors.ico"?> - <?else?> - <?define PwshPath = "[VersionFolder]"?> - <?define IconPath = "assets\Powershell_black.ico"?> - <?endif?> - <!-- UpgradeCode GUID MUST REMAIN SAME THROUGHOUT ALL VERSIONS, otherwise, updates won't occur. --> - <?if $(sys.BUILDARCH)=x64?> - <?define ExplorerContextMenuDialogText = "&$(var.ProductName) $(var.SimpleProductVersion)"?> - <?define UpgradeCodePreview = "39243d76-adaf-42b1-94fb-16ecf83237c8"?> - <?define UpgradeCodeRelease = "31ab5147-9a97-4452-8443-d9709f0516e1"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?elseif $(sys.BUILDARCH) = "ARM64"?> - <?define ExplorerContextMenuDialogText = "&$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))"?> - <?define UpgradeCodePreview = "f064cf16-97b7-4550-b392-ce0f4a6823a3"?> - <?define UpgradeCodeRelease = "75c68ab2-09d8-46b8-b697-d829bdd4c94f"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?else?> - <?define ExplorerContextMenuDialogText = "&$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))"?> - <?define UpgradeCodePreview = "86abcfbd-1ccc-4a88-b8b2-0facfde29094"?> - <?define UpgradeCodeRelease = "1d00683b-0f84-4db8-a64f-2f98ad42fe06"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?endif?> - <!-- Explorer context submenu entries. The ampersand denotes the keyboard shortcut. --> - <?define ExplorerContextSubMenuDialogText = "Open &here"?> - <?define ExplorerContextSubMenuElevatedDialogText = "Open here as &Administrator"?> - <!-- ps1 context submenu entries. --> - <?define PowerShellFileContextSubMenuDialogText = "Run with $(var.ProductName) $(var.SimpleProductVersion)"?> - <!-- Registry location to save installer properties. --> - <?if $(var.IsPreview)=True?> - <?define InstallerPropertiesKey = "Software\Microsoft\PowerShellCore\PreviewInstallerProperties"?> - <?else?> - <?define InstallerPropertiesKey = "Software\Microsoft\PowerShellCore\InstallerProperties"?> - <?endif?> - <Product - Id="*" - Name="PowerShell $(var.SimpleProductVersion)-$(sys.BUILDARCH)" - Language="1033" - Version="$(var.ProductVersion)" - Manufacturer="Microsoft Corporation" - UpgradeCode="$(var.UpgradeCode)"> - <!-- Properties About The Package --> - <Package Id="*" Keywords="Installer" Platform="$(sys.BUILDARCH)" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Description="PowerShell package" Comments="PowerShell for every system" /> - <!-- Add PowerShell icon for executable --> - <Icon Id="PowerShellExe.ico" SourceFile="$(var.IconPath)" /> - <!-- Add PowerShell icon in Add/Remove Programs --> - <Property Id="ARPPRODUCTICON" Value="PowerShellExe.ico" /> - <!-- Set properties for add/remove programs --> - <Property Id="ARPHELPLINK" Value="$(var.InfoURL)" /> - <!-- custom images --> - <WixVariable Id="WixUIBannerBmp" Value="assets\wix\WixUIBannerBmp.png" /> - <WixVariable Id="WixUIDialogBmp" Value="assets\wix\WixUIDialogBmp.png" /> - <WixVariable Id="WixUIExclamationIco" Value="assets\wix\WixUIInfoIco.png" /> - <WixVariable Id="WixUIInfoIco" Value="assets\ps_black_32x32.ico" /> - <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Open $(var.ProductName)" /> - <!-- Default value of Checkbox of starting PowerShell after installation --> - <Property Id="WixShellExecTarget" Value="[VersionFolder]pwsh.exe"/> - <!-- This changes the default setting from "reinstall if the file is a newer version" to "reinstall if the file is a different version" --> - <Property Id="REINSTALLMODE" Value="dmus"/> - <CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" /> - - <!-- Property Initialization --> - - <!-- - Each property below will undergo the following steps in the - initial sequence (`InstallUISequence` if the UI is shown - or `InstallExecuteSequence` if the UI is skipped): - - 1. Load the value that was used in the previous installation into a separate property. - - 2. `..._SetFromSaved`: If the property does not have a value (meaning it - was not specified on the command line) and there is a value from the - previous installation, use the value from the previous installation. - - 3. `..._SetDefault`: If the property does not have a value (meaning it was not specified - on the command line _and_ there wasn't a value from a previous installation), and - the property has a default value, then set the property to the default value. - - 4. `..._DeleteIfOff`: For "boolean" properties, if the property value is not `1`, then delete - the property. This needs to be done so that the checkbox in the UI is not initially checked. - If the property exists, the checkbox will be initially checked regardless of the property value. - - Then in the `InstallExecuteSequence`: - - 1. `..._SetToOffIfMissing`: For boolean properties, if the property does not exist, it is set - to `0`. This ensures that the property value that is saved to the registry is not blank. - If blank values are saved to the registry, then the `..._SetFromSaved` step won't run because - a blank property value is indistinguishable from a property value that does not exist. - - When using "boolean" properties, always check if the property value is equal `1`, instead - of just checking if the property exists. For example, use `FOO=1` instead of just `FOO`. - --> - - <!-- Property: INSTALLFOLDER --> - <Property Id="PREVIOUS_INSTALLFOLDER"> - <RegistrySearch Id="GetSavedInstallFolder" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="InstallFolder" Type="raw" /> - </Property> - <SetProperty Id="INSTALLFOLDER" Action="InstallFolder_SetFromSaved" After="AppSearch" Value="[PREVIOUS_INSTALLFOLDER]" Sequence="first"> - not INSTALLFOLDER and PREVIOUS_INSTALLFOLDER - </SetProperty> - - <!-- Property: ADD_PATH --> - <Property Id="PREVIOUS_ADD_PATH"> - <RegistrySearch Id="GetSavedAddToPath" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddToPath" Type="raw" /> - </Property> - <SetProperty Id="ADD_PATH" Action="AddToPath_SetFromSaved" After="AppSearch" Value="[PREVIOUS_ADD_PATH]" Sequence="first"> - not ADD_PATH and PREVIOUS_ADD_PATH - </SetProperty> - <SetProperty Id="ADD_PATH" Action="AddToPath_SetDefault" After="AddToPath_SetFromSaved" Value="1" Sequence="first"> - not ADD_PATH - </SetProperty> - <SetProperty Id="ADD_PATH" Action="AddToPath_DeleteIfOff" After="AddToPath_SetDefault" Value="{}" Sequence="first"> - ADD_PATH<>1 - </SetProperty> - <SetProperty Id="ADD_PATH" Action="AddToPath_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not ADD_PATH - </SetProperty> - - <!-- Property: REGISTER_MANIFEST --> - <Property Id="PREVIOUS_REGISTER_MANIFEST"> - <RegistrySearch Id="GetSavedRegisterManifest" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="RegisterManifest" Type="raw" /> - </Property> - <SetProperty Id="REGISTER_MANIFEST" Action="RegisterManifest_SetFromSaved" After="AppSearch" Value="[PREVIOUS_REGISTER_MANIFEST]" Sequence="first"> - not REGISTER_MANIFEST and PREVIOUS_REGISTER_MANIFEST - </SetProperty> - <SetProperty Id="REGISTER_MANIFEST" Action="RegisterManifest_SetDefault" After="RegisterManifest_SetFromSaved" Value="1" Sequence="first"> - not REGISTER_MANIFEST - </SetProperty> - <SetProperty Id="REGISTER_MANIFEST" Action="RegisterManifest_DeleteIfOff" After="RegisterManifest_SetDefault" Value="{}" Sequence="first"> - REGISTER_MANIFEST<>1 - </SetProperty> - <SetProperty Id="REGISTER_MANIFEST" Action="RegisterManifest_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not REGISTER_MANIFEST - </SetProperty> - - <!-- Property: ENABLE_PSREMOTING --> - <Property Id="PREVIOUS_ENABLE_PSREMOTING"> - <RegistrySearch Id="GetSavedEnablePsRemoting" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="EnablePsRemoting" Type="raw" /> - </Property> - <SetProperty Id="ENABLE_PSREMOTING" Action="EnablePsRemoting_SetFromSaved" After="AppSearch" Value="[PREVIOUS_ENABLE_PSREMOTING]" Sequence="first"> - not ENABLE_PSREMOTING and PREVIOUS_ENABLE_PSREMOTING - </SetProperty> - <SetProperty Id="ENABLE_PSREMOTING" Action="EnablePsRemoting_DeleteIfOff" After="EnablePsRemoting_SetFromSaved" Value="{}" Sequence="first"> - ENABLE_PSREMOTING<>1 - </SetProperty> - <SetProperty Id="ENABLE_PSREMOTING" Action="EnablePsRemoting_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not ENABLE_PSREMOTING - </SetProperty> - - <!-- Property: DISABLE_TELEMETRY --> - <Property Id="PREVIOUS_DISABLE_TELEMETRY"> - <RegistrySearch Id="GetSavedDisableTelemetry" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="DisableTelemetry" Type="raw" /> - </Property> - <SetProperty Id="DISABLE_TELEMETRY" Action="DisableTelemetry_SetFromSaved" After="AppSearch" Value="[PREVIOUS_DISABLE_TELEMETRY]" Sequence="first"> - not DISABLE_TELEMETRY and PREVIOUS_DISABLE_TELEMETRY - </SetProperty> - <SetProperty Id="DISABLE_TELEMETRY" Action="DisableTelemetry_DeleteIfOff" After="DisableTelemetry_SetFromSaved" Value="{}" Sequence="first"> - DISABLE_TELEMETRY<>1 - </SetProperty> - <SetProperty Id="DISABLE_TELEMETRY" Action="DisableTelemetry_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not DISABLE_TELEMETRY - </SetProperty> - - <!-- Property: ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL --> - <Property Id="PREVIOUS_ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL"> - <RegistrySearch Id="GetSavedAddExplorerContextMenuOpenPowerShell" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddExplorerContextMenuOpenPowerShell" Type="raw" /> - </Property> - <SetProperty Id="ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL" Action="AddExplorerContextMenuOpenPowerShell_SetFromSaved" After="AppSearch" Value="[PREVIOUS_ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL]" Sequence="first"> - not ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL and PREVIOUS_ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL - </SetProperty> - <SetProperty Id="ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL" Action="AddExplorerContextMenuOpenPowerShell_DeleteIfOff" After="AddExplorerContextMenuOpenPowerShell_SetFromSaved" Value="{}" Sequence="first"> - ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL<>1 - </SetProperty> - <SetProperty Id="ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL" Action="AddExplorerContextMenuOpenPowerShell_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL - </SetProperty> - - <!-- Property: ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL --> - <Property Id="PREVIOUS_ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL"> - <RegistrySearch Id="GetSavedAddFileContextMenuRunPowerShell" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddFileContextMenuRunPowerShell" Type="raw" /> - </Property> - <SetProperty Id="ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL" Action="AddFileContextMenuRunPowerShell_SetFromSaved" After="AppSearch" Value="[PREVIOUS_ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL]" Sequence="first"> - not ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL and PREVIOUS_ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL - </SetProperty> - <SetProperty Id="ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL" Action="AddFileContextMenuRunPowerShell_DeleteIfOff" After="AddFileContextMenuRunPowerShell_SetFromSaved" Value="{}" Sequence="first"> - ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL<>1 - </SetProperty> - <SetProperty Id="ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL" Action="AddFileContextMenuRunPowerShell_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL - </SetProperty> - - <!-- Property: USE_MU --> - <Property Id="PREVIOUS_USE_MU"> - <RegistrySearch Id="GetSavedUseMU" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="UseMU" Type="raw" /> - </Property> - <SetProperty Id="USE_MU" Action="UseMU_SetFromSaved" After="AppSearch" Value="[PREVIOUS_USE_MU]" Sequence="first"> - not USE_MU and PREVIOUS_USE_MU - </SetProperty> - <SetProperty Id="USE_MU" Action="UseMU_SetDefault" After="UseMU_SetFromSaved" Value="1" Sequence="first"> - not USE_MU - </SetProperty> - <SetProperty Id="USE_MU" Action="UseMU_DeleteIfOff" After="UseMU_SetDefault" Value="{}" Sequence="first"> - USE_MU<>1 - </SetProperty> - <SetProperty Id="USE_MU" Action="UseMU_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not USE_MU - </SetProperty> - - <!-- Property: ENABLE_MU --> - <Property Id="PREVIOUS_ENABLE_MU"> - <RegistrySearch Id="GetSavedEnableMU" Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="EnableMU" Type="raw" /> - </Property> - <SetProperty Id="ENABLE_MU" Action="EnableMU_SetFromSaved" After="AppSearch" Value="[PREVIOUS_ENABLE_MU]" Sequence="first"> - not ENABLE_MU and PREVIOUS_ENABLE_MU - </SetProperty> - <SetProperty Id="ENABLE_MU" Action="EnableMU_SetDefault" After="EnableMU_SetFromSaved" Value="1" Sequence="first"> - not ENABLE_MU - </SetProperty> - <SetProperty Id="ENABLE_MU" Action="EnableMU_DeleteIfOff" After="EnableMU_SetDefault" Value="{}" Sequence="first"> - ENABLE_MU<>1 - </SetProperty> - <SetProperty Id="ENABLE_MU" Action="EnableMU_SetToOffIfMissing" Before="InstallInitialize" Value="0" Sequence="execute"> - not ENABLE_MU - </SetProperty> - - <!-- End Property Initialization --> - - <SetProperty Id="RegisterManifest" - Before="RegisterManifest" - Sequence="execute" - Value=""[VersionFolder]pwsh.exe" -NoProfile -ExecutionPolicy Bypass -File "[VersionFolder]RegisterManifest.ps1"" /> - <CustomAction Id="RegisterManifest" - BinaryKey="WixCA" - DllEntry="CAQuietExec" - Execute="deferred" - Return="ignore" - Impersonate="no" /> - <SetProperty Id="EnablePSRemoting" - Before="EnablePSRemoting" - Sequence="execute" - Value=""[VersionFolder]pwsh.exe" -NoProfile -ExecutionPolicy Bypass -Command "Enable-PSRemoting"" /> - <CustomAction Id="EnablePSRemoting" - BinaryKey="WixCA" - DllEntry="CAQuietExec" - Execute="deferred" - Return="ignore" - Impersonate="no" /> - <SetProperty Id="EnableMU" - Before="EnableMU" - Sequence="execute" - Value=""[VersionFolder]pwsh.exe" -NoProfile -ExecutionPolicy Bypass -File "[VersionFolder]RegisterMicrosoftUpdate.ps1"" /> - <CustomAction Id="EnableMU" - BinaryKey="WixCA" - DllEntry="CAQuietExec" - Execute="deferred" - Return="ignore" - Impersonate="no" /> - <InstallExecuteSequence> - <!-- Do not remove shortcuts on upgrade to preserve user shortcuts pinned to Taskbar, see https://stackoverflow.com/a/33402698/1810304 --> - <RemoveShortcuts>Installed AND NOT UPGRADINGPRODUCTCODE</RemoveShortcuts> - <Custom Action="RegisterManifest" After="InstallFiles"> - <![CDATA[NOT Installed AND (REGISTER_MANIFEST=1)]]> - </Custom> - <Custom Action="EnablePSRemoting" After="InstallFiles"> - <![CDATA[NOT Installed AND (ENABLE_PSREMOTING=1)]]> - </Custom> - <Custom Action="EnableMU" After="InstallFiles"> - <![CDATA[NOT Installed AND (ENABLE_MU=1)]]> - </Custom> - </InstallExecuteSequence> - <UI> - <Dialog Id="MyExitDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)"> - <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="yes" Text="!(loc.ExitDialogBitmap)" /> - <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Bigger}!(loc.Error1707)" TabSkip="yes" /> - <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="20" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogDescription)" TabSkip="yes" /> - <!-- divider between check boxes and button row --> - <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" TabSkip="yes" /> - <!-- Button row --> - <!-- Checkbox to allow starting PowerShell after the installation (in UI mode only) --> - <Control Id="LaunchCheckBox" Type="CheckBox" X="10" Y="243" Width="170" Height="17" Property="LAUNCHAPPONEXIT" Hidden="yes" CheckBoxValue="1" Text="Launch $(var.ProductName)" > - <Condition Action="show">NOT Installed</Condition> - </Control> - <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" /> - <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIFinish)" /> - <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUICancel)" /> - </Dialog> - <InstallUISequence> - <Show Dialog="MyExitDialog" OnExit="success" /> - </InstallUISequence> - <AdminUISequence> - <Show Dialog="MyExitDialog" OnExit="success" /> - </AdminUISequence> - <Publish Dialog="MyExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish> - </UI> - <UI> - <Publish Dialog="MyExitDialog" Control="Finish" Order="1" Event="DoAction" Value="LaunchApplication">LAUNCHAPPONEXIT=1</Publish> - </UI> - <!-- Prerequisites --> - <Condition Message="Supported only on Windows 8.1 and above"> - <![CDATA[ Installed OR MsiNTProductType <> 1 OR VersionNT >= 603 ]]> - </Condition> - <Condition Message="Supported only on Windows Server 2012 and above"> - <![CDATA[ Installed OR MsiNTProductType = 1 OR VersionNT >= 602 ]]> - </Condition> - <!-- Information About When Older Versions Are Trying To Be Installed--> - <MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ProductName) is already installed." /> - <!-- Embed Cabinet Files in Product--> - <MediaTemplate EmbedCab="yes" /> - <!-- In Your Wix Setup Project, Add A Reference To WixUIExtension.dll --> - <UIRef Id="CustomWixUI_InstallDir" /> - <!-- Features are mandatory. Need At Least One. --> - <Feature Id="ProductFeature" Title="PowerShell" Level="1"> - <ComponentGroupRef Id="ApplicationFiles"/> - <ComponentRef Id="ApplicationProgramsMenuShortcut"/> - <ComponentRef Id="MURegistryEntries"/> - <ComponentRef Id="RegistryEntries"/> - <?if $(var.IsPreview)!=True?> - <ComponentRef Id="AppPath"/> - <?endif?> - <ComponentRef Id="SetPath"/> - <ComponentRef Id="Telemetry"/> - <ComponentRef Id="DisableTelemetry"/> - <ComponentRef Id="ExplorerContextMenu"/> - <ComponentRef Id="PowerShellFileContextMenu"/> - <ComponentRef Id="SaveInstallerProperties"/> - </Feature> - <!-- We need to show EULA, and provide option to customize download location --> - <Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" /> - <!-- Need to get the Windows product name from the registry --> - <Property Id="WINDOWS_PRODUCT_NAME"> - <RegistrySearch Id="ProductName" Root="HKLM" Type="raw" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="ProductName" /> - </Property> - <!-- Prerequisite check for Windows Universal C runtime --> - <Property Id="UNIVERSAL_C_RUNTIME_INSTALLED" Secure="yes"> - <DirectorySearch Id="WindowsDirectory" Path="[WindowsFolder]"> - <DirectorySearch Id="System32" Path="System32"> - <FileSearch Id="ucrtbase" Name="ucrtbase.dll"/> - </DirectorySearch> - </DirectorySearch> - </Property> - <Condition Message="$(var.ProductName) requires the Universal C Runtime to be installed to enable remoting over WinRM. You can find a download link to it here: https://aka.ms/pscore6-prereq"> - <![CDATA[Installed OR UNIVERSAL_C_RUNTIME_INSTALLED]]> - </Condition> - <!-- Prerequisite check for Windows Management Framework --> - <Property Id="PWRSHPLUGIN_VERSION" Secure="yes"> - <DirectorySearchRef Id="System32" Parent="WindowsDirectory" Path="System32"> - <FileSearch Id="pwrshplugin" Name="pwrshplugin.dll" MinVersion="6.3.9600.16383"/> - </DirectorySearchRef> - </Property> - <Condition Message="$(var.ProductName) requires the Windows Management Framework 4.0 or newer to be installed to enable remoting over WinRM. You can find download links here: https://aka.ms/pscore6-prereq"> - <![CDATA[Installed OR PWRSHPLUGIN_VERSION ]]> - </Condition> - <Directory Id="TARGETDIR" Name="SourceDir"> - <Directory Id="$(var.ProductProgFilesDir)"> - <Directory Id="INSTALLFOLDER" Name="PowerShell"> - <Directory Id="VersionFolder" Name="$(var.SimpleProductVersion)"> - <Component Id="Telemetry" Guid="{80520f20-471d-4d08-adc8-bab637627b39}" KeyPath="yes"> - <!-- Should retain component GUID since this is a shared, non-file, non-registry resource. --> - <Environment Id="PowerShellDistributionChannel" Action="create" Name="POWERSHELL_DISTRIBUTION_CHANNEL" Permanent="no" System="yes" Value="MSI:[WINDOWS_PRODUCT_NAME]"/> - </Component> - <Component Id="MURegistryEntries"> - <Condition>USE_MU=1</Condition> - <!-- Create registry key to allow opt-out of MU servicing without opting out of MU completely. We don't want to uninstall because it's used by both Preview and Stable and the detection relies on PS7 being installed for this to take effect. --> - <RegistryKey Root="HKLM" Key="Software\Microsoft\PowerShellCore" Action="create" ForceCreateOnInstall="yes"> - <RegistryValue Type="integer" Value="1" Name="UseMU" KeyPath="yes"/> - </RegistryKey> - </Component> - <Component Id="RegistryEntries"> - <!-- create key for easy detection of a particular version of a powershell core package - The upgrade code is used in the key because it will change when we allow SxS --> - <RegistryKey Root="HKLM" Key="Software\Microsoft\PowerShellCore\InstalledVersions\$(var.UpgradeCode)" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes"> - <RegistryValue Type="string" Value="$(var.ProductSemanticVersion)" Name="SemanticVersion" KeyPath="yes"/> - <RegistryValue Type="string" Value="[VersionFolder]" Name="InstallLocation" /> - <RegistryValue Type="string" Value="[ProductCode]" Name="ProductCode" /> - </RegistryKey> - - </Component> - <?if $(var.IsPreview)!=True?> - <Component Id="AppPath"> - <!-- register ourselves in application registry so can be started using just Win+R `pwsh.exe` --> - <RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes"> - <!-- As a shared path, the last one to install will overwrite any previous value. It also needs to be in its own component to properly ref-count and be removed when appropriate. --> - <RegistryValue Type="string" Value="[VersionFolder]pwsh.exe" KeyPath="yes"/> - </RegistryKey> - </Component> - <?endif?> - <Component Id="DisableTelemetry" Guid="{E86F5C91-3721-4C5C-A31F-1F0A5A468573}" KeyPath="yes"> - <Condition>DISABLE_TELEMETRY=1</Condition> - <Environment Id="PowerShellTelemetryOptout" Action="set" Name="POWERSHELL_TELEMETRY_OPTOUT" Permanent="no" System="yes" Value="1"/> - </Component> - <!-- add ourselves to %PATH% so pwsh.exe can be started from Windows PowerShell or cmd.exe --> - <Component Id="SetPath"> - <Condition>ADD_PATH=1</Condition> - <Environment Id="PATH" Action="set" Name="PATH" Part="last" Permanent="no" System="yes" Value="$(var.PwshPath)"/> - <!-- Can't use a shared component GUID here either since the path we add to PATH varies on the actual directory path. Use a key that represents this same path. --> - <RegistryKey Root="HKLM" Key="Software\Microsoft\PowerShellCore\InstalledVersions\$(var.UpgradeCode)"> - <RegistryValue Type="string" Name="InstallDir" Value="[VersionFolder]" KeyPath="yes"/> - </RegistryKey> - </Component> - <!-- Explorer context menu with 2 submenus to open PowerShell normally or as an Administrator. - See https://blogs.msdn.microsoft.com/andrew_richards/2017/03/01/enhancing-the-open-command-prompt-here-shift-right-click-context-menu-experience/ for details --> - <Component Id="ExplorerContextMenu"> - <Condition>ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1</Condition> - <!-- When clicking on background in Explorer --> - <RegistryKey Root="HKCR" Key="Directory\Background\shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)" KeyPath="yes"/> - </RegistryKey> - <!-- When clicking on Drive in Explorer --> - <RegistryKey Root="HKCR" Key="Drive\shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"/> - </RegistryKey> - <!-- When clicking on Desktop background in Explorer --> - <RegistryKey Root="HKCR" Key="DesktopBackground\shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"/> - </RegistryKey> - <!-- When clicking on folder in Explorer --> - <RegistryKey Root="HKCR" Key="Directory\shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"/> - </RegistryKey> - <!-- When being in a Library folder in Explorer --> - <RegistryKey Root="HKCR" Key="LibraryFolder\background\shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"/> - </RegistryKey> - <!-- Sub menus to open PowerShell at the current location either as a normal shell or as Administrator --> - <RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)\shell\openpwsh"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextSubMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - </RegistryKey> - <RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)\shell\openpwsh\command"> - <RegistryValue Type="string" Value="[VersionFolder]pwsh.exe -NoExit -RemoveWorkingDirectoryTrailingCharacter -WorkingDirectory "%V!" -Command "$host.UI.RawUI.WindowTitle = '$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))'""/> - </RegistryKey> - <RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)\shell\runas"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextSubMenuElevatedDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe"/> - <RegistryValue Type="string" Value="" Name="HasLUAShield"/> - </RegistryKey> - <RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)\shell\runas\command"> - <RegistryValue Type="string" Value="[VersionFolder]pwsh.exe -NoExit -RemoveWorkingDirectoryTrailingCharacter -WorkingDirectory "%V!" -Command "$host.UI.RawUI.WindowTitle = '$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))'""/> - </RegistryKey> - <RemoveRegistryKey Id="RemoveOldOpenKey" Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)\shell\open" Action="removeOnInstall"/> - </Component> - <Component Id="PowerShellFileContextMenu"> - <Condition>ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1</Condition> - <!-- When right-clicking ps1 file --> - <RegistryKey Root="HKCR" Key="Microsoft.PowerShellScript.1\Shell\$(var.ProductName)$(var.SimpleProductVersion)$(sys.BUILDARCH)"> - <RegistryValue Type="string" Name="MUIVerb" Value="$(var.PowerShellFileContextSubMenuDialogText)"/> - <RegistryValue Type="string" Name="Icon" Value="[VersionFolder]pwsh.exe" KeyPath="yes"/> - <RegistryKey Key="Command"> - <RegistryValue Type="string" Value="[VersionFolder]pwsh.exe -Command "$host.UI.RawUI.WindowTitle = '$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))'; & '%1'""/> - </RegistryKey> - </RegistryKey> - </Component> - <Component Id="SaveInstallerProperties" Permanent="yes"> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddToPath" Value="[ADD_PATH]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="RegisterManifest" Value="[REGISTER_MANIFEST]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="EnablePSRemoting" Value="[ENABLE_PSREMOTING]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="DisableTelemetry" Value="[DISABLE_TELEMETRY]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddExplorerContextMenuOpenPowerShell" Value="[ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="AddFileContextMenuRunPowerShell" Value="[ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="UseMU" Value="[USE_MU]" Type="string" /> - <RegistryValue Root="HKLM" Key="$(var.InstallerPropertiesKey)" Name="EnableMU" Value="[ENABLE_MU]" Type="string" /> - </Component> - </Directory> - </Directory> - </Directory> - <Directory Id="ProgramMenuFolder"> - <Directory Id="ApplicationProgramsFolder" Name="$(var.ProductName)"> - <Component Id="ApplicationProgramsMenuShortcut"> - <Shortcut Id="PowerShell_ProgramsMenuShortcut" - Name="$(var.ProductSimpleVersionWithNameAndOptionalArchitecture)" - Description="$(var.ProductSimpleVersionWithNameAndOptionalArchitecture)" - Target="[VersionFolder]pwsh.exe" - Arguments="-WorkingDirectory ~" /> - <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/> - <!-- HKMU is HKLM when installing perMachine and HKCU when installing perUser--> - <RegistryValue Root="HKMU" Key="Software\Microsoft\PowerShellCore\ProgramsMenuShortcut\$(var.SimpleProductVersion)" Name="installed" Type="integer" Value="1" KeyPath="yes"/> - </Component> - </Directory> - </Directory> - </Directory> - </Product> - -<!-- Explorer Context Menu Dialog --> -<Fragment> - <UI> - <Dialog Id="ExplorerContextMenuDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)"> - <!-- Banner --> - <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="yes" Text="!(loc.InstallDirDlgBannerBitmap)"/> - <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}Optional Actions" TabSkip="yes" /> - <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Initialization and Customization" TabSkip="yes" /> - <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" TabSkip="yes" /> - <!-- If the checkboxes are defined first, then they are first in the tab order and can be ticked and unticked using the spacebar --> - <Control Id="AddToPathCheckBox" Type="CheckBox" X="20" Y="60" Width="290" Height="17" Property="ADD_PATH" CheckBoxValue="1" Text="Add $(var.ProductName) to Path Environment Variable"/> - <Control Id="RegisterManifestCheckBox" Type="CheckBox" X="20" Y="80" Width="290" Height="17" Property="REGISTER_MANIFEST" CheckBoxValue="1" Text="Register Windows Event Logging Manifest"/> - <Control Id="EnablePSRemotingCheckBox" Type="CheckBox" X="20" Y="100" Width="290" Height="17" Property="ENABLE_PSREMOTING" CheckBoxValue="1" Text="Enable $(var.ProductName) remoting"/> - <Control Id="DisableTelemetry" Type="CheckBox" X="20" Y="120" Width="290" Height="17" Property="DISABLE_TELEMETRY" CheckBoxValue="1" Text="Disable Telemetry (Reboot or Restart of processes may be required)" ToolTip="Sets environment variable POWERSHELL_TELEMETRY_OPTOUT to 1, see https://go.microsoft.com/fwlink/?linkid=2242006"/> - <Control Id="ContextMenuOpenPowerShell" Type="CheckBox" X="20" Y="140" Width="290" Height="17" Property="ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL" CheckBoxValue="1" Text="Add '$(var.ExplorerContextSubMenuDialogText)' context menus to Explorer"/> - <Control Id="ContextMenuRunPowerShell" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL" CheckBoxValue="1" Text="Add '$(var.PowerShellFileContextSubMenuDialogText)' context menu for PowerShell files"/> - <Control Id="LicenseLink" Type="Hyperlink" X="20" Y="190" Width="214" Height="17"> - <Text><![CDATA[<a href="https://github.com/PowerShell/PowerShell/blob/master/LICENSE.txt">The application is distributed under the MIT license.</a>]]></Text> - </Control> - <Control Id="TpnLink" Type="Hyperlink" X="20" Y="210" Width="290" Height="17"> - <Text><![CDATA[<a href="https://github.com/PowerShell/PowerShell/blob/master/ThirdPartyNotices.txt">Please review the ThirdPartyNotices.txt</a>]]></Text> - </Control> - <!-- divider and bottom buttons --> - <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" TabSkip="yes"/> - <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)"/> - <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Cancel="yes" Default="yes" Text="!(loc.WixUINext)"/> - <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)"> - <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> - </Control> - </Dialog> - </UI> -</Fragment> - -<!-- Microsoft Update Menu Dialog --> -<Fragment> - <UI> - <Dialog Id="MuDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)"> - <!-- Banner --> - <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="yes" Text="!(loc.InstallDirDlgBannerBitmap)"/> - <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="30" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}Use Microsoft Update to help keep your computer secure and up to date" TabSkip="yes" /> - <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" TabSkip="yes" /> - <Control Id="Description" Type="Text" X="25" Y="54" Width="280" Height="100" Transparent="yes" NoPrefix="yes" Text="Microsoft Update helps keep your computer secure and up to date for Windows and other Microsoft products, including PowerShell 7. Updates will be delivered based on your current update settings. You can review or change these settings from the Windows Update control panel." TabSkip="yes" /> - <!-- If the checkboxes are defined first, then they are first in the tab order and can be ticked and unticked using the spacebar --> - <Control Id="UseMuCheckBox" Type="CheckBox" X="20" Y="100" Width="290" Height="27" Property="USE_MU" CheckBoxValue="1" Text="Enable updating PowerShell through Microsoft Update or WSUS (recommended)"/> - <Control Id="EnableMuCheckBox" Type="CheckBox" X="20" Y="130" Width="290" Height="17" Property="ENABLE_MU" CheckBoxValue="1" Text="Use Microsoft Update when I check for updates (recommended)"> - </Control> - <Control Id="MuWarningText" Type="Text" X="20" Y="160" Width="290" Height="27" Text="Without Microsoft Update enabled, you will need to use another update solution like WSUS or SCCM in order to receive automatic updates."> - <Condition Action="hide"><![CDATA[ENABLE_MU="1" OR USE_MU<>"1"]]></Condition> - <Condition Action="show"><![CDATA[ENABLE_MU<>"1" AND USE_MU="1"]]></Condition> - </Control> - <Control Id="MuFAQ" Type="Hyperlink" X="20" Y="190" Width="214" Height="17"> - <Text><![CDATA[<a href="https://aka.ms/PowerShell-Microsoft-Update-FAQ">See the Microsoft Update FAQ</a>]]></Text> - </Control> - <Control Id="PrivacyLink" Type="Hyperlink" X="20" Y="210" Width="290" Height="17"> - <Text><![CDATA[<a href="https://aka.ms/PowerShell-Microsoft-Update-Privacy-Statement">Read the Microsoft Update Privacy Statement</a>]]></Text> - </Control> - <!-- divider and bottom buttons --> - <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" TabSkip="yes"/> - <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)"/> - <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Cancel="yes" Default="yes" Text="!(loc.WixUINext)"/> - <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)"> - <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> - </Control> - </Dialog> - </UI> -</Fragment> -<!-- Customized version of WixUI_InstallDir, which is necessary to add custom dialogs. https://github.com/wixtoolset/wix3/blob/master/src/ext/UIExtension/wixlib/WixUI_InstallDir.wxs --> -<Fragment> - <UI Id="CustomWixUI_InstallDir"> - <!-- - First-time install dialog sequence: - - WixUI_WelcomeDlg - - WixUI_InstallDirDlg - - ExplorerContextMenuDialog - - MuDialog - - WixUI_VerifyReadyDlg - - WixUI_DiskCostDlg - Maintenance dialog sequence: - - WixUI_MaintenanceWelcomeDlg - - WixUI_MaintenanceTypeDlg - - WixUI_InstallDirDlg - - WixUI_VerifyReadyDlg - Patch dialog sequence: - - WixUI_WelcomeDlg - - WixUI_VerifyReadyDlg - --> - - <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> - <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" /> - <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" /> - - <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" /> - <Property Id="WixUI_Mode" Value="InstallDir" /> - - <DialogRef Id="BrowseDlg" /> - <DialogRef Id="DiskCostDlg" /> - <DialogRef Id="ErrorDlg" /> - <DialogRef Id="FatalError" /> - <DialogRef Id="FilesInUse" /> - <DialogRef Id="MsiRMFilesInUse" /> - <DialogRef Id="PrepareDlg" /> - <DialogRef Id="ProgressDlg" /> - <DialogRef Id="ResumeDlg" /> - <DialogRef Id="UserExit" /> - <DialogRef Id="ExplorerContextMenuDialog" /> - - - <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish> - <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> - - <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish> - <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish> - - <Publish Dialog="ExplorerContextMenuDialog" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish> - <Publish Dialog="ExplorerContextMenuDialog" Control="Next" Event="NewDialog" Value="MuDialog">1</Publish> - <Publish Dialog="MuDialog" Control="Back" Event="NewDialog" Value="ExplorerContextMenuDialog">1</Publish> - <Publish Dialog="MuDialog" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="2">1</Publish> - - <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish> - <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> - <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish> - <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> - <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish> - <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="ExplorerContextMenuDialog" Order="5">1</Publish> - <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> - <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> - - <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MuDialog" Order="1">NOT Installed</Publish> - <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish> - <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish> - - <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> - - <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> - <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> - <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish> - - <Property Id="ARPNOMODIFY" Value="1" /> - </UI> - <UIRef Id="WixUI_Common" /> - </Fragment> - -</Wix> diff --git a/assets/wix/WixUIBannerBmp.png b/assets/wix/WixUIBannerBmp.png deleted file mode 100644 index 2a1922c1d7c83c687f6abf001a773d0d5387c095..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3855 zcma)9c|278_h&4V$&h^uMUp*~eQB|zWFkw}22ma&+gOG)lzk~YR2W&FhGdLr5=K)D zDip$HEHSdqV940{4Lz^t`|t0MyL|4wuXE4myx-@%&q=ywWe$aiLs(c?pca=*Y*<)W zY0P`QL!8WW!8$9zys!q_m|tMQb{(B%F4%9Mzj~g9r8?vAwmS!N&2{gRV=xN~CvN{> z4c49*XFe1SF})FTJ-|C8%st49<(|8be~7BTSIDt5s_Lp*J62pXEG#?^EKJVZhP%;5 ze6q9qo`LUq@!feb8(p&YHuB~Shxl_hpMHOPN4*E}S4&z>#dqk;b!&=2t#yNSf+zTM zADW2$NX^vxY$+^CX=xGtELtEYnkxGSc+D!#G{P`mYg%-+3$Qb^3-L5+jPBY)uWT*n zPgK?y?%EDSqmgVZGBPsapcWZEK0e)y8z-2nX}%N_6O%~;k0*(ViTUQr{Cs>*RuWB_ zZ-S(%FEL+r$qFYWCdL;Zc0l#!KDcgp-sMaI_pjL5hvbMV%KiG``snDF1*^fWKSFtC z><hbh--9pj8-dC>Y&{r>(MuIt^CxAShIuZ>Ryk=Ed+!#M`Fs%QqlJmS8fuFDf+t(+ zE^1jmZ#eImkUZ#XZ8ZP&R9=MA7bk}jzgER;{A&}RVDM$}+>$zXF^EJ?F>cpe(DG*L zcKxG!SDjfLXi<|_eJ=WUx=h-3nlVc4Z`suzt7+sC^Ga(!Rc;;`DA@yfDRVYP!)E!_ z6MG$wD+6O0Fe^qyhU%ic=>G1`WJlerlX#o5a6WKePuf(ozqrf`3UO{q{WRrl4TKzq zJhv}-5h%1QVXt^Iw&Fg=@?6gGfFYYnE7#ckA=7sBn<Il+)3OyWC7;=?Jhs*ai)DGs z5<E`!d~tr_)F1mJ^JJ-@_ObW(^iB#}Ud*fzPKr2tslEI{6yrpTSB|V!iJ-a<DbY&B z#5TxCMt(|0MqNUHUxQAaUo8Khhqk|8slA3#0m(DClws6}-(jkmGaU8~%<vc^V*62s z1M;}u5O}T=%JmipqKSw4`BHnO7MuQ82sK0rcRd6?eO%@<H+5+}B<jOT#vJ7<5@L3M zkI;z2gSWg!LZW~sCqM8t8l>NLh{}N`cD)V)GnAd-+7(29ZhqizMVwMBJ0cxIRhGrc z3e+sM#pU+3<*o^)?$bwHG2NAYE@xyOdiOZ)?cHyChYFACroUTTXzQ@c8}C86V%WC4 zkK@Q4L~JdX!R-tmNH|2*5CY^_QIbU<<b^2CPoBNkdK-@vqU{Ua0NAO08r~^er=hMN zXLF8eZVLFSIrq<K==Sf3Gga$)L74Y!$R|gD;KxQj!aX#Us|N?dy#PWjzZBw#D)8h$ zyc7a_OcSjX&e;Y@$%Miy0{YG1ZU4AOSwj5Z&r9F4-?@EJB@p&;pWnqr=L$dEuU`pc z{%Fr)yRUG^iO>@!Ij0v_ZyGiPLK?jRfso#bM07Ezp;Z6~RK$7O!P~+?WI0Yo-Aod& zJp7?(FPP$)xb<&9ISdIz!;BB57s$eZ3ZCfi^v?yPTob))QTy(i-qI|WZKs>>VZW8q zIzC|Y=QDX+9tfmw&4CZJF}PAFC;}n}+YCdfH#Bi=rgHAzw&YjIDM*Ov0aP6Fkq_`t zUNAeNNCmfARI|Owvkf1JDU0E+GuoaxbvaMZ097!~Lk*GyRJ`F5m9C*rZ=4pg(8H1X zRfT}^T~t9iNPk2C@GRkf;%t+WkuDLSvY;S%kN|?)umLZ@Z!Q>+zO5Pp?9%H{_R|ej z*t8+P`VBOoFC7IMsFlO-+wo9C;E4V5q&N=5D+u+LEUsB*qI<NOPyU-kfYN{F8n>rn z#89*i$u05b>yY_e%GlUQ)vnLap_Q$jcC3%4RWeu_tuZLUG>3=yIjiCM0QFI#l;&~a zJn6x7rRY}Y<bSuV>skeAN+=xt1@$9;thq)2Ow+#7v76p1m0gB=NgWWOq2mddnYh~@ z<1sUCetSf#Wp>64y&KpFrWivf(Ab06>5j}w!AURWv68?AHT*7gtC`Kb&l5C|u6@4( z<ScE_FgmVKFQP9*v4hWFyzMC~V1SYoDvaMV(pY~+@!w}-`>c`S+WSCy!ckx|%ufkt zNC29eub+I2{Zz;+hN)xgzpj732;^KS=zx-}6(K{Y#|QwWxRc0}cO*ew5oey3(()sR zq!Za1emD>|AhTag^B1O(yc_KJt<vywaM-FO+GCM~Hkh_QYUKU0Y;Tj%Yy2j%nvIQ2 z9uiW<$w#v38;F<K!80Iv56<REHItNDDI`PJl>Ph*(lC5FnIyfS#YXNQ`URzWnZc*$ zi2d&n91>_7b%E8x0}=u~+XK^ch6^#&Ek#@?6T@+Z&C>A4#PshdNl#7&z*Xnd5$=cV z7G0KE@Hw_G4NtNP2<*d*@0v!aN@R638#%i3r6F!79&>{LR9?}ZunfzHtX-UQ_)MUq z?s~&--$1G05fKTP)U+S+q!E<lFD|OJJB8j5J+fInf#$rh&tYB1+)a;RTvXPEKHi_E z0V4a+mZ8)~tSH)8N+lD<tcewev6PhD$UaK+Kws1S;pM&$(o0K%l+rpLDxFCX-AH8@ zueUmPb|0$#=jP7%URO99SsXpFK*EFZfoh1*h9f|b8Y7u3)gm-<W$InMnv0oLUp^}o zCMJM|CC?Mnm)IGJd985z91=U9c|?Cd2PSPd(P_8!$5!vsmbs{;(S4Gq5z+Gkz!U*M z5ddGUU8pKUbj=0)I>J}F+Nq&*T!G=nq(bv2LzH3E<SB#N)nD`VCt9oycG^dB`#CD_ zw#<p&mDE3m8>w_%c|6PIw?+W;aH|Ahl-Q*l(87?cDsTHbUz0V`UVc*~D*SS3Sa`BF zt}OzD1eW+_wmUJK*38%)NU3fg{qQ+*eL^acQH$7s!szcsoVoqxpI;RMuF{mM_hch3 zJa=oeDroyuWtdR*n^|7_E$GLZuZO7N<#FcBig}`#k`?&kYj}Pg2F1TG_g0}lO{xM@ z9DXhd2JC;NL_^V<ynB&q4A+>gtG`_`_l{x*&|$`AtC<N$3hWhY5rgrVhhz{km4|v7 z1|QS$(-FU|)?8iFDoZkiW*;!|mBZ-JV(*a9U*XB!Lvrl+3UA^2+f@yHl*!Qd?|8=| z$FG(SV9m0bF_~NvtPs(+EEEg_GwyIpxN|a~ihnKE1>{A(q~8gIvB@3e$jleJXp2i2 zd7Pm<=^{6b&P&ColLKek)mL>Qb~cuLIzG%dTxt(Eq;5bOO`%DmHEcMT$cDhjZgDcw zw8e{dhUXV&%~O!#+y@w&U{pbpc~a89mjp*r3haj-R*r2*ZEmI=)(7RFA28<Bj7_@p zI}<IG#C|VjKPmZbLGKpDf{;&Dm>JB|yai6H8f4;e@c`lOqTq9V!>f2AV$B1|Mve(j zULawgRSSL?+bW8D*ti>n1&0}Jif1ZKCCrd=;xPcSx{@em1k!dwRsL;%cB0*fa<|10 z8h;SC;t}biP;Nh%8s5ObYiERaqT@YraAIM#3!HH6-7-1xYr*oPcuY7O@~J%TZ90_q zXKY0O)!|<FL63&%j<diw)wby<EC>L7%S+k$bB^KTq!{ZxTes-wo$%$q!yb>|Seb1G z9$8&=_TNy+aNzO3o)vz~FPB;LJ$;b!y&)9=6%tZWU#diq=!m6`Dv^eWadE2tk;b*n zc6#s)dK&GLqQ7a#tI++59T|Q(M;<pq0NjlT0DfEn@8+j~TP^%N7B#j`uB*d*{KK*p zNA2%*R9`$1Z<V~o&fp$iAqxL?(NL?*v7fG5E2^a#wRkyfup{pFx@`B>s7)kPZU6Ya z3|orJ9Xm~<wlE5eTNyF^i1E+UVJ|{Q`JL4eaJcX6AjkUpLpq*`#+3s!I!EKC(*g#W z#R`^Ou@8yy#wV*)n~2#f##(oy*~-se;mdN1y+d)MMw!S>7rpRs`u>daF{cS%6S1qv z4Errc@v2Vr$ME<6^E+zVO^B%%hz(0w=C(+2(aoa`i>IFVZ_8#v=J+Z=<T`InQoXmP z0$B3hs6Qd--n=u6fX)1Yv>6_o3TS#@w9<1r5El1`$dkoiCOR_+r`9~k@tBYTof5YN z*PWe0iG<D|@x^m4{U?s&I<qDQAK96a2jKRLeMYtSXBR=SLkoR3CBLf)t%Vr=DauEU zd21^PV*-HKr={%43C`Dhn<eNi+^T!c-)n@2*~y55p0XK2wN=9HI5m8c@NcDzZONg> zR!7g?CDXOMD+gnrxbv}|rwL2(rA3>k1yh(RnQ%bD%ss<yFjMI5;b0z^I(AU`Ox2*W zuVWg=&B5fxDgDP!jr$-}o03YU8*pB~@MMCB{(51{$X^oVZm;`vk^fw5Wb~WgM=_Jp zgO_^3L4|+ir0j7Fgg%(H4QjZ?fj3gXf}E)&JcxXU_69`8h&W53`8(<x-ktk)`Q0KV z<qvDR$-D;3R9F;<+_*2NGD^6WN@7=~J<2tyPFV@pTS;Whl6L2zFs`ZDf`Ez)wZ+-U zr2T;fQ#TAY*q&szDojyt{aE7>?dyOeVh<hgmGcu=-@pqXvXSj<;xaNMM6wc*^==0O zZ^4i<NZ|05K4(25Q}<H!+-Npp(h8lB|4O$Vo1gSLS*%?-z|721K;yE+V>b;+pGUoq zolbKoV8u^N+qrvK$z{G#di>Ne{$U4y3r6IaYTqLu+oi>_<9vw6$zuK<KC#@`#HUG5 zk7Ok-m4&BfB$Dd5tVQ*WCZ5Z9@_+BaLjnjfpX$zbG$nlCJg8J>>SZhD8+&M1V3#%X znS<4Q8TqEAd8`f<F*NmqI7@D<@9a_!<h^-NcK^TgTYJQxp%3c69y3#6Zy6fKZNQvY OSu9MgOt2T=vHu4m33(F$ diff --git a/assets/wix/WixUIDialogBmp.png b/assets/wix/WixUIDialogBmp.png deleted file mode 100644 index 57cf3734c176908bc7ae2435a0e31711ae210ebe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30804 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 RaOp3Vo{sSikf(|M{{S(tW9a|@ diff --git a/assets/wix/WixUIInfoIco.png b/assets/wix/WixUIInfoIco.png deleted file mode 100644 index cb705d5f33f1a3451203f97d0228031368355dc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1638 zcmV-s2ATPZP)<h;3K|Lk000e1NJLTq001BW001Ef1^@s6xF)Gl00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGX&Hw-d&H<-TH)H?+02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;jv63FrU-1=mSLK~z{r#nyRHlyw*fa1gnX`#$&J+Ffpz zTb6sdMNzrL1Kl*t@<=Vx5l1t}(owQ;Jkm0f3e8e0nzT_H3)5z-yk<HLGtDtnOhgX9 zJ-_#57nb*>{A+t=9)|ht@ArP5eRrQ{Uo!yzYl<$KGDR0nnWBrPOwmPCrsyKe{hxn} z(z$DpQ~Nw}rag!3>Sf5PT8hldCCIE;jLfNvpqcVC(#sbhbz(hI%H|@eREMPEIwTg( zg1Vp<@p)B<&8|RnRym?HWr#>Cfik5C%0w+9QVX!X<(N2ryL$ks<%<xh)ltqtMDA>; za%Mr9Jp;<DS|~E7AzV|1(D73dl3I@7<TA(-OCePkK@yjbz?fVFL}tNHl@8zV6nKXw zz*8Ov4@nf<0+n#_3xkul9CeG<i5Kw2`QHX{9U}60JT`weUf$k{XBxMSz$ZdJ3=d*> zlpaqdJdwwx3|DcuvyU8(o<Z2W=ZJU#TU(D0;kmP*%ASdJTU+QQ;L#&s)#i5zpF9FD zAUu!oZ1}4*@Kx}*mpq>EXbyMvXLvB-5;(Z~qy79f@dD;G?i|GH=-tnx+ddt$mu<uV z(<uf99%0GaT^ue`7aQ<EhDYe}BzOf6;z0}#=W#Cy#<>STrc6NReG!~xM)h*~+=p;Q zW-Y=qs`0|cx4ApOqOX4da~ql<i6=ak@Mwl-5S|8~Fg+dv_n-(K_YH=Vmz2ZpU42kk zQO_<T?1D?bcMjp%LwHzvB|_7t;H7N`Xd53r5BpHP;6=i7INVRk@MOZ(@Q@AS0SdxH zc-(`>ZJj*OuznZ2gs_0-wljnH3@GRuAD&TTz(Z0dL7p^$+UGOc%13ukFUoZdgpcR( z5H&nGJd(p*815}2JP;19zOZxhgpGqM4xjjr9Tyg`eA7Myt}w#O38!{TD1kJ-5O2JH zg0}O~^>+{QE1!aQ2(_Cm7VZ)~9y)}(5$;U*I9E8i`QX~EK6X@CK&fsO-|Gz55N_1# zgsThrc8k?wf7@v~!pC2C?jyZ;I^ooA0j$?~oVA;Sn;+p`guB7Y&Jl?jCF}_28R382 z?m;Bo{>L3O66*J3UtOT1d~{szgdcqj`av@ix3+VFrHwsw3)isi!U8_}@}dYn`k>Ji zRpa6hSLi4oJ-z+3x6CkT9Nhe2=i&`pN5buS+``ftJKs6VwhIebyW<dthmEiJ&q1@a z@fCDGcu2?ixYzv<Pd4tQcdsxE8hZ|RC)}BE2M)IwYl%z0++jzA1yn8EAizfsn(*X8 zeAsr9whzVmpKc(ts)75`=?9Iy3$@!Ye5{oX##oGnJS+xX-P|$b0y^mjD88_czVU<) zwwo-0@L_{yLQOq7uH9sZxnPsA`N&ziD_X&zVZCnc-~ub#aR%IsxU#DG?5M#t{B!C; z2iI=HaVdvuA*BM=H|<7WUq5Z-<NB>G)GT=o?$TJ%L1SaUZ3(yJaF%Pg>|@7;1vKqD zY8W*7UT1i6eignxcbT>f#nID0A}UY!uY-oetqG^k+|1nEP{7G=er1;s7BHvbRii<} z@Fy0p#@#OZ#TbnH4|=hp=@5Jr8V*m_PQvb%!)QLxhUWb&KgL_Fl<ytE{AX7aZUysU zxU0JlZr$T9B`hF~o@#~<nz)>)=pPuMm-x8&^Plu&w37RQ(GQyA?c6vWHDt;p1I{vC zJB2M9OqSfA%UADmw|@Ab2~ii|>WxnBi}w1#(~wesk9?x3tzU^#=dPgr`wl_w`Jf$^ zcFslxEMBpNIFSP0JlrliXymk}E}93g&=k=pn$ZT0`4|f$Sf8z*oFPu6fMpx@3I@&N zJkf{^n$d7Odq-To*-M;A0WF`NMOujtYHbbTax3Xcb~2(eCLuDt6spu>D3kM{ROcZ) zE(@VC8iYiqB3P9KnIaBBVbKT(R>5DUfS)7;KK?R6%4qm(+HsI5W1OX6!PF_bXv!2_ kG-Zk|nleQfO_wnH2U8%-p4+>Ne*gdg07*qoM6N<$g8cvk-~a#s diff --git a/assets/wix/bundle.wxs b/assets/wix/bundle.wxs deleted file mode 100644 index a2d93b47099..00000000000 --- a/assets/wix/bundle.wxs +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"> - <!-- UpgradeCode GUID MUST REMAIN SAME THROUGHOUT ALL VERSIONS, otherwise, updates won't occur. --> - <?if $(sys.BUILDARCH)=x64?> - <?define UpgradeCodePreview = "3C90221B-D500-43C6-A4A6-0BE6C2C1B317"?> - <?define UpgradeCodeRelease = "7A804CBB-648E-4276-9A58-081862DB1B99"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?elseif $(sys.BUILDARCH) = "ARM64"?> - <?define ExplorerContextMenuDialogText = "&$(var.ProductName) $(var.SimpleProductVersion) ($(sys.BUILDARCH))"?> - <?define UpgradeCodePreview = "499e9123-48aa-41df-aa20-6f4d28b54722"?> - <?define UpgradeCodeRelease = "4cc0e36a-17db-4c84-b4f4-560a11e7ddb6"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?else?> - <?define UpgradeCodePreview = "4A699A9C-E904-4024-BCD2-44E098A8C6BD"?> - <?define UpgradeCodeRelease = "ED46CB02-64B3-43FD-A63E-6CF269D8C21C"?> - <?if $(var.IsPreview)=True?> - <?define UpgradeCode = $(var.UpgradeCodePreview)?> - <?else?> - <?define UpgradeCode = $(var.UpgradeCodeRelease)?> - <?endif?> - <?endif?> - - <Bundle Name="PowerShell $(var.WindowsVersion)-$(sys.BUILDARCH)" Version="$(var.WindowsVersion)" Manufacturer="Microsoft Corporation" UpgradeCode="$(var.UpgradeCode)"> - <!-- See https://wixtoolset.org/documentation/manual/v3/bundle/wixstdba/ for a list of WiX standard bootstrapper types. --> - <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"> - <bal:WixStandardBootstrapperApplication LicenseFile="assets\wix\ExeLicense.rtf" LogoFile="assets\ps_black_32x32.ico" /> - </BootstrapperApplicationRef> - <Chain> - <MsiPackage SourceFile="$(var.TargetPath)" Compressed="yes" /> - </Chain> - </Bundle> -</Wix> diff --git a/build.psm1 b/build.psm1 index 737b3e6182f..d353eb251e5 100644 --- a/build.psm1 +++ b/build.psm1 @@ -3003,11 +3003,6 @@ function Start-PSBootstrap { $psInstallFile = [System.IO.Path]::Combine($PSScriptRoot, "tools", "install-powershell.ps1") & $psInstallFile -AddToPath } - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { - Import-Module "$PSScriptRoot\tools\wix\wix.psm1" - $isArm64 = "$env:RUNTIME" -eq 'arm64' - Install-Wix -arm64:$isArm64 - } Write-LogGroupEnd -Title "Install Windows Dependencies" } diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index 3562962e68f..ccb4e5529d7 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -57,17 +57,13 @@ It **requires** that PowerShell Core has been built via `Start-PSBuild` from the #### Windows -The `Start-PSPackage` function delegates to `New-MSIPackage` which creates a Windows Installer Package of PowerShell. +`Start-PSPackage` supports creating ZIP and MSIX packages for Windows. +When called without `-Type` on Windows, it defaults to creating both ZIP and MSIX packages. The packages *must* be published in release mode, so make sure `-Configuration Release` is specified when running `Start-PSBuild`. -It uses the Windows Installer XML Toolset (WiX) to generate a MSI package, -which copies the output of the published PowerShell files to a version-specific folder in Program Files, -and installs a shortcut in the Start Menu. -It can be uninstalled through `Programs and Features`. - Note that PowerShell is always self-contained, thus using it does not require installing it. -The output of `Start-PSBuild` includes a `powershell.exe` executable which can simply be launched. +The output of `Start-PSBuild` includes a `pwsh.exe` executable which can simply be launched. #### Linux / macOS @@ -169,8 +165,8 @@ Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration ```powershell # Create packages for v6.0.0-beta.1 release targeting Windows universal package. # 'win7-x64' / 'win7-x86' should be used for -WindowsRuntime. -Start-PSPackage -Type msi -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' Start-PSPackage -Type zip -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' +Start-PSPackage -Type msix -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' ``` ## NuGet Packages diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj index e6efeac10f0..dddbb915eca 100644 --- a/src/powershell-win-core/powershell-win-core.csproj +++ b/src/powershell-win-core/powershell-win-core.csproj @@ -33,7 +33,7 @@ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> </Content> - <Content Include="..\..\LICENSE.txt;..\..\ThirdPartyNotices.txt;..\powershell-native\Install-PowerShellRemoting.ps1;..\PowerShell.Core.Instrumentation\PowerShell.Core.Instrumentation.man;..\PowerShell.Core.Instrumentation\RegisterManifest.ps1;..\..\assets\MicrosoftUpdate\RegisterMicrosoftUpdate.ps1;..\..\assets\GroupPolicy\PowerShellCoreExecutionPolicy.admx;..\..\assets\GroupPolicy\PowerShellCoreExecutionPolicy.adml;..\..\assets\GroupPolicy\InstallPSCorePolicyDefinitions.ps1"> + <Content Include="..\..\LICENSE.txt;..\..\ThirdPartyNotices.txt;..\powershell-native\Install-PowerShellRemoting.ps1;..\PowerShell.Core.Instrumentation\PowerShell.Core.Instrumentation.man;..\PowerShell.Core.Instrumentation\RegisterManifest.ps1;..\..\assets\GroupPolicy\PowerShellCoreExecutionPolicy.admx;..\..\assets\GroupPolicy\PowerShellCoreExecutionPolicy.adml;..\..\assets\GroupPolicy\InstallPSCorePolicyDefinitions.ps1"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> </Content> diff --git a/test/perf/benchmarks/assets/compiler.test.ps1 b/test/perf/benchmarks/assets/compiler.test.ps1 index 5105ae9b408..be731373036 100644 --- a/test/perf/benchmarks/assets/compiler.test.ps1 +++ b/test/perf/benchmarks/assets/compiler.test.ps1 @@ -2238,26 +2238,6 @@ function Start-PSPackage { } } } - "msi" { - $TargetArchitecture = "x64" - if ($Runtime -match "-x86") { - $TargetArchitecture = "x86" - } - Write-Verbose "TargetArchitecture = $TargetArchitecture" -Verbose - - $Arguments = @{ - ProductNameSuffix = $NameSuffix - ProductSourcePath = $Source - ProductVersion = $Version - AssetsPath = "$RepoRoot\assets" - ProductTargetArchitecture = $TargetArchitecture - Force = $Force - } - - if ($PSCmdlet.ShouldProcess("Create MSI Package")) { - New-MSIPackage @Arguments - } - } "msix" { $Arguments = @{ ProductNameSuffix = $NameSuffix diff --git a/test/powershell/Installer/WindowsInstaller.Tests.ps1 b/test/powershell/Installer/WindowsInstaller.Tests.ps1 deleted file mode 100644 index 66bd08e74f5..00000000000 --- a/test/powershell/Installer/WindowsInstaller.Tests.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -Describe "Windows Installer" -Tags "Scenario" { - - BeforeAll { - $skipTest = -not $IsWindows - $preRequisitesLink = 'https://aka.ms/pscore6-prereq' - $linkCheckTestCases = @( - @{ Name = "Universal C Runtime"; Url = $preRequisitesLink } - @{ Name = "WMF 4.0"; Url = "https://www.microsoft.com/download/details.aspx?id=40855" } - @{ Name = "WMF 5.0"; Url = "https://www.microsoft.com/download/details.aspx?id=50395" } - @{ Name = "WMF 5.1"; Url = "https://www.microsoft.com/download/details.aspx?id=54616" } - ) - } - - It "WiX (Windows Installer XML) file contains pre-requisites link $preRequisitesLink" -Skip:$skipTest { - $wixProductFile = Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\assets\wix\Product.wxs" - (Get-Content $wixProductFile -Raw).Contains($preRequisitesLink) | Should -BeTrue - } - - ## Running 'Invoke-WebRequest' with WMF download URLs has been failing intermittently, - ## because sometimes the URLs lead to a 'this download is no longer available' page. - ## We use a retry logic here. Retry for 5 times with 1 second interval. - # It "Pre-Requisistes link for '<Name>' is reachable: <url>" -TestCases $linkCheckTestCases -Skip:$skipTest { - It "Pre-Requisistes link for '<Name>' is reachable: <url>" -TestCases $linkCheckTestCases -Pending { - param ($Url) - - foreach ($i in 1..5) { - try { - $result = Invoke-WebRequest $Url -UseBasicParsing - break; - } catch { - Start-Sleep -Seconds 1 - } - } - - $result | Should -Not -Be $null - } -} diff --git a/tools/UpdateDotnetRuntime.ps1 b/tools/UpdateDotnetRuntime.ps1 index 339153bcf0c..f62a16cfe14 100644 --- a/tools/UpdateDotnetRuntime.ps1 +++ b/tools/UpdateDotnetRuntime.ps1 @@ -9,9 +9,6 @@ param ( [Parameter()] [switch]$UseNuGetOrg, - [Parameter()] - [switch]$UpdateMSIPackaging, - [Parameter()] [string]$RuntimeSourceFeed, @@ -366,31 +363,6 @@ if ($dotnetUpdate.ShouldUpdate) { Write-Verbose -Message "Updating project files completed." -Verbose - if ($UpdateMSIPackaging) { - if (-not $environment.IsWindows) { - throw "UpdateMSIPackaging can only be done on Windows" - } - - Import-Module "$PSScriptRoot/../build.psm1" -Force - Import-Module "$PSScriptRoot/packaging" -Force - Start-PSBootstrap -Package - Start-PSBuild -Clean -Configuration Release -InteractiveAuth:$InteractiveAuth - - $publishPath = Split-Path (Get-PSOutput) - Remove-Item -Path "$publishPath\*.pdb" - - try { - Start-PSPackage -Type msi -SkipReleaseChecks -InformationVariable wxsData - } catch { - if ($_.Exception.Message -like "Current files to not match *") { - Copy-Item -Path $($wxsData.MessageData.NewFile) -Destination ($wxsData.MessageData.FilesWxsPath) - Write-Verbose -Message "Updating files.wxs file completed." -Verbose - } else { - throw $_ - } - } - } - Update-DevContainer } else { diff --git a/tools/ci.psm1 b/tools/ci.psm1 index b9d150ceacd..33700ac9024 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -241,7 +241,7 @@ function Install-CIPester Write-Verbose "Checking for Pester module (required: $MinimumVersion - $MaximumVersion)" -Verbose # Check if a compatible version of Pester is already installed - $installedPester = Get-Module -Name Pester -ListAvailable | + $installedPester = Get-Module -Name Pester -ListAvailable | Where-Object { $_.Version -ge $MinimumVersion -and $_.Version -le $MaximumVersion } | Sort-Object -Property Version -Descending | Select-Object -First 1 @@ -616,20 +616,9 @@ function Invoke-CIFinish Restore-PSOptions -PSOptionsPath "${buildFolder}/psoptions.json" $preReleaseVersion = $env:CI_FINISH_RELASETAG - # Build packages $preReleaseVersion = "$previewPrefix-$previewLabel.$prereleaseIteration" - switch -regex ($Runtime){ - default { - $runPackageTest = $true - $packageTypes = 'msi', 'zip', 'zip-pdb', 'msix' - } - 'win-arm.*' { - $runPackageTest = $false - $packageTypes = 'msi', 'zip', 'zip-pdb', 'msix' - } - } + # Build packages + $packageTypes = 'zip', 'zip-pdb', 'msix' - Import-Module "$PSScriptRoot\wix\wix.psm1" - Install-Wix -arm64:$true $packages = Start-PSPackage -Type $packageTypes -ReleaseTag $preReleaseVersion -SkipReleaseChecks -WindowsRuntime $Runtime foreach ($package in $packages) { @@ -641,40 +630,9 @@ function Invoke-CIFinish if ($package -is [string]) { $null = $artifacts.Add($package) - } elseif ($package -is [pscustomobject] -and $package.psobject.Properties['msi']) { - $null = $artifacts.Add($package.msi) - $null = $artifacts.Add($package.wixpdb) } } - if ($runPackageTest) { - # the packaging tests find the MSI package using env:PSMsiX64Path - $env:PSMsiX64Path = $artifacts | Where-Object { $_.EndsWith(".msi")} - $architechture = $Runtime.Split('-')[1] - $exePath = New-ExePackage -ProductVersion ($preReleaseVersion -replace '^v') -ProductTargetArchitecture $architechture -MsiLocationPath $env:PSMsiX64Path - Write-Verbose "exe Path: $exePath" -Verbose - $artifacts.Add($exePath) - $env:PSExePath = $exePath - $env:PSMsiChannel = $Channel - $env:PSMsiRuntime = $Runtime - - # Install the latest Pester and import it - $maximumPesterVersion = '4.99' - Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion $maximumPesterVersion -Force - Import-Module Pester -Force -MaximumVersion $maximumPesterVersion - - $testResultPath = Join-Path -Path $env:TEMP -ChildPath "win-package-$channel-$runtime.xml" - - # start the packaging tests and get the results - $packagingTestResult = Invoke-Pester -Script (Join-Path $repoRoot '.\test\packaging\windows\') -PassThru -OutputFormat NUnitXml -OutputFile $testResultPath - - Publish-TestResults -Title "win-package-$channel-$runtime" -Path $testResultPath - - # fail the CI job if the tests failed, or nothing passed - if (-not $packagingTestResult -is [pscustomobject] -or $packagingTestResult.FailedCount -ne 0 -or $packagingTestResult.PassedCount -eq 0) { - throw "Packaging tests failed ($($packagingTestResult.FailedCount) failed/$($packagingTestResult.PassedCount) passed)" - } - } } } catch { Get-Error -InputObject $_ @@ -932,12 +890,12 @@ function New-LinuxPackage } else { "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" } - + # Ensure artifacts directory exists if (-not (Test-Path $artifactsDir)) { New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null } - + Write-Log -message "Artifacts directory: $artifactsDir" Copy-Item $packageObj.FullName -Destination $artifactsDir -Force } @@ -950,7 +908,7 @@ function New-LinuxPackage } else { "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" } - + # Create and package Raspbian .tgz # Build must be clean for Raspbian Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release' @@ -1062,13 +1020,13 @@ Function Test-MergeConflictMarker [string]$OutputPath, [string]$SummaryPath ) - + # Output results to GitHub Actions if ($OutputPath) { "files-checked=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 "conflicts-found=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 } - + # Create GitHub Actions job summary if ($SummaryPath) { $summaryContent = @" @@ -1097,11 +1055,11 @@ $Message # Filter out *.cs files from merge conflict checking $filesToCheck = @($File | Where-Object { $_ -notlike "*.cs" }) $filteredCount = $File.Count - $filesToCheck.Count - + if ($filteredCount -gt 0) { Write-Host "Filtered out $filteredCount *.cs file(s) from merge conflict checking" -ForegroundColor Yellow } - + if ($filesToCheck.Count -eq 0) { Write-Host "No files to check after filtering (all files were *.cs)" -ForegroundColor Yellow Write-NoFilesOutput -Message "All $filteredCount file(s) were filtered out (*.cs files are excluded from merge conflict checking)." -OutputPath $OutputPath -SummaryPath $SummaryPath @@ -1135,14 +1093,14 @@ $Message } $filesChecked++ - + # Get relative path for display $relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) { $filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) } else { $filePath } - + Write-Host " Checking: $relativePath" -ForegroundColor Gray # Search for conflict markers using Select-String diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 8d900902bc2..8d8154e7445 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -4616,11 +4616,6 @@ "FileType": "Product", "Architecture": null }, - { - "Pattern": "RegisterMicrosoftUpdate.ps1", - "FileType": "Product", - "Architecture": null - }, { "Pattern": "System.Management.Automation.dll", "FileType": "Product", diff --git a/tools/packaging/packaging.psd1 b/tools/packaging/packaging.psd1 index 0053428a481..b72c14b80f1 100644 --- a/tools/packaging/packaging.psd1 +++ b/tools/packaging/packaging.psd1 @@ -7,13 +7,10 @@ PowerShellVersion = "5.0" CmdletsToExport = @() FunctionsToExport = @( - 'Compress-ExePackageEngine' - 'Expand-ExePackageEngine' 'Expand-PSSignedBuild' 'Invoke-AzDevOpsLinuxPackageBuild' 'Invoke-AzDevOpsLinuxPackageCreation' 'New-DotnetSdkContainerFxdPackage' - 'New-ExePackage' 'Start-PrepForGlobalToolNupkg' 'New-GlobalToolNupkgSource' 'New-GlobalToolNupkgFromSource' diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 361f82769f0..a551a483c8d 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -52,7 +52,7 @@ function Start-PSPackage { [string]$Name = "powershell", # Ubuntu, CentOS, Fedora, macOS, and Windows packages are supported - [ValidateSet("msix", "deb", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "msi", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] + [ValidateSet("msix", "deb", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] [string[]]$Type, # Generate windows downlevel package @@ -346,7 +346,7 @@ function Start-PSPackage { } elseif ($Environment.IsMacOS) { "osxpkg", "tar" } elseif ($Environment.IsWindows) { - "msi", "msix" + "zip", "msix" } Write-Warning "-Type was not specified, continuing with $Type!" } @@ -493,34 +493,6 @@ function Start-PSPackage { } } } - "msi" { - $TargetArchitecture = "x64" - $r2rArchitecture = "amd64" - if ($Runtime -match "-x86") { - $TargetArchitecture = "x86" - $r2rArchitecture = "i386" - } - elseif ($Runtime -match "-arm64") - { - $TargetArchitecture = "arm64" - $r2rArchitecture = "arm64" - } - - Write-Verbose "TargetArchitecture = $TargetArchitecture" -Verbose - - $Arguments = @{ - ProductNameSuffix = $NameSuffix - ProductSourcePath = $Source - ProductVersion = $Version - AssetsPath = "$RepoRoot\assets" - ProductTargetArchitecture = $TargetArchitecture - Force = $Force - } - - if ($PSCmdlet.ShouldProcess("Create MSI Package")) { - New-MSIPackage @Arguments - } - } "msix" { $Arguments = @{ ProductNameSuffix = $NameSuffix @@ -3769,443 +3741,6 @@ function Get-NugetSemanticVersion $packageSemanticVersion } -# Get the paths to various WiX tools -function Get-WixPath -{ - [CmdletBinding()] - param ( - [bool] $IsProductArchitectureArm = $false - ) - - $wixToolsetBinPath = $IsProductArchitectureArm ? "${env:ProgramFiles(x86)}\Arm Support WiX Toolset *\bin" : "${env:ProgramFiles(x86)}\WiX Toolset *\bin" - - Write-Verbose -Verbose "Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath" - if (-not (Test-Path $wixToolsetBinPath)) - { - if (!$IsProductArchitectureArm) - { - throw "The latest version of Wix Toolset 3.11 is required to create MSI package. Please install it from https://github.com/wixtoolset/wix3/releases" - } - else { - throw "The latest version of Wix Toolset 3.14 is required to create MSI package for arm. Please install it from https://aka.ms/ps-wix-3-14-zip" - } - } - - ## Get the latest if multiple versions exist. - $wixToolsetBinPath = (Get-ChildItem $wixToolsetBinPath).FullName | Sort-Object -Descending | Select-Object -First 1 - - Write-Verbose "Initialize Wix executables..." - $wixHeatExePath = Join-Path $wixToolsetBinPath "heat.exe" - $wixMeltExePath = Join-Path $wixToolsetBinPath "melt.exe" - $wixTorchExePath = Join-Path $wixToolsetBinPath "torch.exe" - $wixPyroExePath = Join-Path $wixToolsetBinPath "pyro.exe" - $wixCandleExePath = Join-Path $wixToolsetBinPath "Candle.exe" - $wixLightExePath = Join-Path $wixToolsetBinPath "Light.exe" - $wixInsigniaExePath = Join-Path $wixToolsetBinPath "Insignia.exe" - - return [PSCustomObject] @{ - WixHeatExePath = $wixHeatExePath - WixMeltExePath = $wixMeltExePath - WixTorchExePath = $wixTorchExePath - WixPyroExePath = $wixPyroExePath - WixCandleExePath = $wixCandleExePath - WixLightExePath = $wixLightExePath - WixInsigniaExePath = $wixInsigniaExePath - } -} - -<# - .Synopsis - Creates a Windows installer MSI package and assumes that the binaries are already built using 'Start-PSBuild'. - This only works on a Windows machine due to the usage of WiX. - .EXAMPLE - # This example shows how to produce a Debug-x64 installer for development purposes. - cd $RootPathOfPowerShellRepo - Import-Module .\build.psm1; Import-Module .\tools\packaging\packaging.psm1 - New-MSIPackage -Verbose -ProductSourcePath '.\src\powershell-win-core\bin\Debug\net8.0\win7-x64\publish' -ProductTargetArchitecture x64 -ProductVersion '1.2.3' -#> -function New-MSIPackage -{ - [CmdletBinding()] - param ( - - # Name of the Product - [ValidateNotNullOrEmpty()] - [string] $ProductName = 'PowerShell', - - # Suffix of the Name - [string] $ProductNameSuffix, - - # Version of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $ProductVersion, - - # Source Path to the Product Files - required to package the contents into an MSI - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $ProductSourcePath, - - # File describing the MSI Package creation semantics - [ValidateNotNullOrEmpty()] - [ValidateScript( {Test-Path $_})] - [string] $ProductWxsPath = "$RepoRoot\assets\wix\Product.wxs", - - # File describing the MSI Package creation semantics - [ValidateNotNullOrEmpty()] - [ValidateScript({Test-Path $_})] - [string] $BundleWxsPath = "$RepoRoot\assets\wix\bundle.wxs", - - # Path to Assets folder containing artifacts such as icons, images - [ValidateNotNullOrEmpty()] - [ValidateScript( {Test-Path $_})] - [string] $AssetsPath = "$RepoRoot\assets", - - # Architecture to use when creating the MSI - [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64", "arm64")] - [ValidateNotNullOrEmpty()] - [string] $ProductTargetArchitecture, - - # Force overwrite of package - [Switch] $Force, - - [string] $CurrentLocation = (Get-Location) - ) - - $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") - - $windowsNames = Get-WindowsNames -ProductName $ProductName -ProductNameSuffix $ProductNameSuffix -ProductVersion $ProductVersion - $productSemanticVersionWithName = $windowsNames.ProductSemanticVersionWithName - $ProductSemanticVersion = $windowsNames.ProductSemanticVersion - $packageName = $windowsNames.PackageName - $ProductVersion = $windowsNames.ProductVersion - Write-Verbose "Create MSI for Product $productSemanticVersionWithName" -Verbose - Write-Verbose "ProductSemanticVersion = $productSemanticVersion" -Verbose - Write-Verbose "packageName = $packageName" -Verbose - Write-Verbose "ProductVersion = $ProductVersion" -Verbose - - $simpleProductVersion = [string]([Version]$ProductVersion).Major - $isPreview = Test-IsPreview -Version $ProductSemanticVersion - if ($isPreview) - { - $simpleProductVersion += '-preview' - } - - $staging = "$PSScriptRoot/staging" - New-StagingFolder -StagingPath $staging -PackageSourcePath $ProductSourcePath - - $assetsInSourcePath = Join-Path $staging 'assets' - - New-Item $assetsInSourcePath -type directory -Force | Write-Verbose - - Write-Verbose "Place dependencies such as icons to $assetsInSourcePath" - Copy-Item "$AssetsPath\*.ico" $assetsInSourcePath -Force - - - - $fileArchitecture = 'amd64' - $ProductProgFilesDir = "ProgramFiles64Folder" - if ($ProductTargetArchitecture -eq "x86") - { - $fileArchitecture = 'x86' - $ProductProgFilesDir = "ProgramFilesFolder" - } - elseif ($ProductTargetArchitecture -eq "arm64") - { - $fileArchitecture = 'arm64' - $ProductProgFilesDir = "ProgramFiles64Folder" - } - - $wixFragmentPath = Join-Path $env:Temp "Fragment.wxs" - - # cleanup any garbage on the system - Remove-Item -ErrorAction SilentlyContinue $wixFragmentPath -Force - - $msiLocationPath = Join-Path $CurrentLocation "$packageName.msi" - $msiPdbLocationPath = Join-Path $CurrentLocation "$packageName.wixpdb" - - if (!$Force.IsPresent -and (Test-Path -Path $msiLocationPath)) { - Write-Error -Message "Package already exists, use -Force to overwrite, path: $msiLocationPath" -ErrorAction Stop - } - - Write-Log "Generating wxs file manifest..." - $arguments = @{ - IsPreview = $isPreview - ProductSourcePath = $staging - ProductName = $ProductName - ProductVersion = $ProductVersion - SimpleProductVersion = $simpleProductVersion - ProductSemanticVersion = $ProductSemanticVersion - ProductVersionWithName = $productVersionWithName - ProductProgFilesDir = $ProductProgFilesDir - FileArchitecture = $fileArchitecture - } - - $buildArguments = New-MsiArgsArray -Argument $arguments - - Test-Bom -Path $staging -BomName windows -Architecture $ProductTargetArchitecture -Verbose - Start-NativeExecution -VerboseOutputOnError { & $wixPaths.wixHeatExePath dir $staging -dr VersionFolder -cg ApplicationFiles -ag -sfrag -srd -scom -sreg -out $wixFragmentPath -var var.ProductSourcePath $buildArguments -v} - - Send-AzdoFile -Path $wixFragmentPath - - $wixObjFragmentPath = Join-Path $env:Temp "Fragment.wixobj" - - # cleanup any garbage on the system - Remove-Item -ErrorAction SilentlyContinue $wixObjFragmentPath -Force - - Start-MsiBuild -WxsFile $ProductWxsPath, $wixFragmentPath -ProductTargetArchitecture $ProductTargetArchitecture -Argument $arguments -MsiLocationPath $msiLocationPath -MsiPdbLocationPath $msiPdbLocationPath - - Remove-Item -ErrorAction SilentlyContinue $wixFragmentPath -Force - - if ((Test-Path $msiLocationPath) -and (Test-Path $msiPdbLocationPath)) - { - Write-Verbose "You can find the WixPdb @ $msiPdbLocationPath" -Verbose - Write-Verbose "You can find the MSI @ $msiLocationPath" -Verbose - [pscustomobject]@{ - msi=$msiLocationPath - wixpdb=$msiPdbLocationPath - } - } - else - { - $errorMessage = "Failed to create $msiLocationPath" - throw $errorMessage - } -} - -function Get-WindowsNames { - param( - # Name of the Product - [ValidateNotNullOrEmpty()] - [string] $ProductName = 'PowerShell', - - # Suffix of the Name - [string] $ProductNameSuffix, - - # Version of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $ProductVersion - ) - - Write-Verbose -Message "Getting Windows Names for ProductName: $ProductName; ProductNameSuffix: $ProductNameSuffix; ProductVersion: $ProductVersion" -Verbose - - $ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion - $ProductVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $ProductVersion -IncrementBuildNumber - - $productVersionWithName = $ProductName + '_' + $ProductVersion - $productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion - - $packageName = $productSemanticVersionWithName - if ($ProductNameSuffix) { - $packageName += "-$ProductNameSuffix" - } - - return [PSCustomObject]@{ - PackageName = $packageName - ProductVersionWithName = $productVersionWithName - ProductSemanticVersion = $ProductSemanticVersion - ProductSemanticVersionWithName = $productSemanticVersionWithName - ProductVersion = $ProductVersion - } -} - -function New-ExePackage { - param( - # Name of the Product - [ValidateNotNullOrEmpty()] - [string] $ProductName = 'PowerShell', - - # Version of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - - [string] $ProductVersion, - - # File describing the MSI Package creation semantics - [ValidateNotNullOrEmpty()] - [ValidateScript({Test-Path $_})] - [string] $BundleWxsPath = "$RepoRoot\assets\wix\bundle.wxs", - - # Architecture to use when creating the MSI - [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64", "arm64")] - [ValidateNotNullOrEmpty()] - [string] $ProductTargetArchitecture, - - # Location of the signed MSI - [Parameter(Mandatory = $true)] - [string] - $MsiLocationPath, - - [string] $CurrentLocation = (Get-Location) - ) - - $productNameSuffix = "win-$ProductTargetArchitecture" - - $windowsNames = Get-WindowsNames -ProductName $ProductName -ProductNameSuffix $productNameSuffix -ProductVersion $ProductVersion - $productSemanticVersionWithName = $windowsNames.ProductSemanticVersionWithName - $packageName = $windowsNames.PackageName - $isPreview = Test-IsPreview -Version $windowsNames.ProductSemanticVersion - - Write-Verbose "Create EXE for Product $productSemanticVersionWithName" -verbose - Write-Verbose "packageName = $packageName" -Verbose - - $exeLocationPath = Join-Path $CurrentLocation "$packageName.exe" - $exePdbLocationPath = Join-Path $CurrentLocation "$packageName.exe.wixpdb" - $windowsVersion = Get-WindowsVersion -packageName $packageName - - Start-MsiBuild -WxsFile $BundleWxsPath -ProductTargetArchitecture $ProductTargetArchitecture -Argument @{ - IsPreview = $isPreview - TargetPath = $MsiLocationPath - WindowsVersion = $windowsVersion - } -MsiLocationPath $exeLocationPath -MsiPdbLocationPath $exePdbLocationPath - - return $exeLocationPath -} - -<# -Allows you to extract the engine of exe package, mainly for signing -Any existing signature will be removed. - #> -function Expand-ExePackageEngine { - param( - # Location of the unsigned EXE - [Parameter(Mandatory = $true)] - [string] - $ExePath, - - # Location to put the expanded engine. - [Parameter(Mandatory = $true)] - [string] - $EnginePath, - - [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64", "arm64")] - [ValidateNotNullOrEmpty()] - [string] $ProductTargetArchitecture - ) - - <# - 2. detach the engine from TestInstaller.exe: - insignia -ib TestInstaller.exe -o engine.exe - #> - - $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") - - $resolvedExePath = (Resolve-Path -Path $ExePath).ProviderPath - $resolvedEnginePath = [System.IO.Path]::GetFullPath($EnginePath) - - Start-NativeExecution -VerboseOutputOnError { & $wixPaths.wixInsigniaExePath -ib $resolvedExePath -o $resolvedEnginePath} -} - -<# -Allows you to replace the engine (installer) in the exe package. -Used to replace the engine with a signed version -#> -function Compress-ExePackageEngine { - param( - # Location of the unsigned EXE - [Parameter(Mandatory = $true)] - [string] - $ExePath, - - # Location of the signed engine - [Parameter(Mandatory = $true)] - [string] - $EnginePath, - - [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64", "arm64")] - [ValidateNotNullOrEmpty()] - [string] $ProductTargetArchitecture - ) - - - <# - 4. re-attach the signed engine.exe to the bundle: - insignia -ab engine.exe TestInstaller.exe -o TestInstaller.exe - #> - - $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") - - $resolvedEnginePath = (Resolve-Path -Path $EnginePath).ProviderPath - $resolvedExePath = (Resolve-Path -Path $ExePath).ProviderPath - - Start-NativeExecution -VerboseOutputOnError { & $wixPaths.wixInsigniaExePath -ab $resolvedEnginePath $resolvedExePath -o $resolvedExePath} -} - -function New-MsiArgsArray { - param( - [Parameter(Mandatory)] - [Hashtable]$Argument - ) - - $buildArguments = @() - foreach ($key in $Argument.Keys) { - $buildArguments += "-d$key=$($Argument.$key)" - } - - return $buildArguments -} - -function Start-MsiBuild { - param( - [string[]] $WxsFile, - [string[]] $Extension = @('WixUIExtension', 'WixUtilExtension', 'WixBalExtension'), - [string] $ProductTargetArchitecture, - [Hashtable] $Argument, - [string] $MsiLocationPath, - [string] $MsiPdbLocationPath - ) - - $outDir = $env:Temp - - $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") - - $extensionArgs = @() - foreach ($extensionName in $Extension) { - $extensionArgs += '-ext' - $extensionArgs += $extensionName - } - - $buildArguments = New-MsiArgsArray -Argument $Argument - - $objectPaths = @() - foreach ($file in $WxsFile) { - $fileName = [system.io.path]::GetFileNameWithoutExtension($file) - $objectPaths += Join-Path $outDir -ChildPath "${filename}.wixobj" - } - - foreach ($file in $objectPaths) { - Remove-Item -ErrorAction SilentlyContinue $file -Force - Remove-Item -ErrorAction SilentlyContinue $file -Force - } - - $resolvedWxsFiles = @() - foreach ($file in $WxsFile) { - $resolvedWxsFiles += (Resolve-Path -Path $file).ProviderPath - } - - Write-Verbose "$resolvedWxsFiles" -Verbose - - Write-Log "running candle..." - Start-NativeExecution -VerboseOutputOnError { & $wixPaths.wixCandleExePath $resolvedWxsFiles -out "$outDir\\" $extensionArgs -arch $ProductTargetArchitecture $buildArguments -v} - - Write-Log "running light..." - # suppress ICE61, because we allow same version upgrades - # suppress ICE57, this suppresses an error caused by our shortcut not being installed per user - # suppress ICE40, REINSTALLMODE is defined in the Property table. - Start-NativeExecution -VerboseOutputOnError {& $wixPaths.wixLightExePath -sice:ICE61 -sice:ICE40 -sice:ICE57 -out $msiLocationPath -pdbout $msiPdbLocationPath $objectPaths $extensionArgs } - - foreach($file in $objectPaths) - { - Remove-Item -ErrorAction SilentlyContinue $file -Force - Remove-Item -ErrorAction SilentlyContinue $file -Force - } -} - <# .Synopsis Creates a Windows AppX MSIX package and assumes that the binaries are already built using 'Start-PSBuild'. @@ -4372,6 +3907,7 @@ function New-MSIXPackage Write-Verbose "Creating msix package" -Verbose Start-NativeExecution -VerboseOutputOnError { & $makeappx pack /o /v /h SHA256 /d $ProductSourcePath /p (Join-Path -Path $CurrentLocation -ChildPath "$packageName.msix") } Write-Verbose "Created $packageName.msix" -Verbose + Join-Path -Path $CurrentLocation -ChildPath "$packageName.msix" } } From 558c886d87c55979758576d19a9e6e105b93f70c Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 17 Apr 2026 10:05:33 -0700 Subject: [PATCH 342/378] Remove package verification from the notice pipeline (#27289) --- .pipelines/apiscan-gen-notice.yml | 4 ---- .pipelines/templates/compliance/generateNotice.yml | 7 ------- 2 files changed, 11 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 9cc83e7136a..df5ebaac091 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -8,9 +8,6 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false - - name: SkipVerifyPackages - type: boolean - default: false variables: # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. @@ -112,4 +109,3 @@ extends: - template: /.pipelines/templates/compliance/generateNotice.yml@self parameters: parentJobs: [] - SkipVerifyPackages: ${{ parameters.SkipVerifyPackages }} diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 90fd08dd8d9..aec44b9b8f6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -4,8 +4,6 @@ parameters: - name: parentJobs type: jobList - - name: SkipVerifyPackages - type: boolean jobs: - job: generateNotice @@ -57,11 +55,6 @@ jobs: inputs: sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - - pwsh: | - $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest - displayName: Verify that packages have license data - condition: eq(${{ parameters.SkipVerifyPackages }}, false) - - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 displayName: 'NOTICE File Generator' inputs: From 6cc1e7071d40162e01fd2b47f6c33a02c0d046e6 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 17 Apr 2026 14:03:11 -0400 Subject: [PATCH 343/378] [master] Update branch for release (#27291) --- CHANGELOG/v7.7/dependencychanges.json | 15 +++ DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest/main/cgmanifest.json | 110 ++++++++---------- 14 files changed, 86 insertions(+), 81 deletions(-) create mode 100644 CHANGELOG/v7.7/dependencychanges.json diff --git a/CHANGELOG/v7.7/dependencychanges.json b/CHANGELOG/v7.7/dependencychanges.json new file mode 100644 index 00000000000..21cd1577251 --- /dev/null +++ b/CHANGELOG/v7.7/dependencychanges.json @@ -0,0 +1,15 @@ +[ + { + "ChangeType": "NonSecurity", + "Branch": "master", + "PackageId": ".NET SDK", + "FromVersion": "11.0.100-preview.2.26159.112", + "ToVersion": "11.0.100-preview.3.26207.106", + "VulnerabilityId": [], + "Severity": [], + "VulnerableRanges": [], + "AdvisoryUrls": [], + "Justification": "Updated .NET SDK. Building with the latest SDK is required.", + "TimestampUtc": "2026-04-17T17:16:15.7099916Z" + } +] diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 7c4a2191467..f8288b53b67 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "11.0.100-preview.1.26104.118", + "sdkImageVersion": "11.0.100-preview.3.26207.106", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index ef31c0723ff..d31f5220d83 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "11.0.100-preview.2.26159.112" + "version": "11.0.100-preview.3.26207.106" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 8e5a6b3f2e3..9552f72c83a 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ <ItemGroup> <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> - <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> <PropertyGroup> diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 8bb897e0095..8ce2a97d67b 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index d6cd95677ab..cc98893c5b6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" /> - <PackageReference Include="System.Drawing.Common" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Drawing.Common" Version="11.0.0-preview.3.26207.106" /> <PackageReference Include="JsonSchema.Net" Version="7.4.0" /> </ItemGroup> diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 1a63891ef77..dadff652e53 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ <ItemGroup> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.Diagnostics.EventLog" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.Diagnostics.EventLog" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> </Project> diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index ecc224713cc..50d431225c7 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ <ItemGroup> <!-- This section is to force the version of non-direct dependencies --> - <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="11.0.0-preview.3.26207.106" /> <!-- the following package(s) are from https://github.com/dotnet/fxdac --> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.IO.Packaging" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.Net.Http.WinHttpHandler" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.IO.Packaging" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.Net.Http.WinHttpHandler" Version="11.0.0-preview.3.26207.106" /> <!-- the following package(s) are from https://github.com/dotnet/wcf --> <PackageReference Include="System.ServiceModel.Http" Version="10.0.652802" /> <PackageReference Include="System.ServiceModel.NetTcp" Version="10.0.652802" /> <PackageReference Include="System.ServiceModel.Primitives" Version="10.0.652802" /> <!-- the source could not be found for the following package(s) --> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> <!-- diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index bc6e4b105de..d7b6d1235da 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ <ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" /> <ProjectReference Include="..\Microsoft.WSMan.Runtime\Microsoft.WSMan.Runtime.csproj" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> <PropertyGroup> diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index fa797a7f0de..beec0c4a495 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ <!-- the Application Insights package --> <PackageReference Include="Microsoft.ApplicationInsights" Version="2.23.0" /> <!-- the following package(s) are from https://github.com/dotnet/corefx --> - <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.DirectoryServices" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.Management" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="11.0.0-preview.2.26159.112" /> - <PackageReference Include="System.Security.Permissions" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.Win32.Registry.AccessControl" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.DirectoryServices" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.Management" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="11.0.0-preview.3.26207.106" /> + <PackageReference Include="System.Security.Permissions" Version="11.0.0-preview.3.26207.106" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0-rc.1" /> diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 906820d262b..37b73426f6c 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.Windows.Compatibility" Version="11.0.0-preview.3.26207.106" /> <PackageReference Include="System.Data.SqlClient" Version="4.9.1" /> </ItemGroup> diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index c632e960a53..3567cd93c68 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="11.0.0-preview.2.26159.112" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="11.0.0-preview.3.26207.106" /> </ItemGroup> </Project> diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 4cf097c7956..a2a9fe041e9 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -30,7 +30,7 @@ <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="XunitXml.TestLogger" Version="8.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" /> </ItemGroup> <ItemGroup> diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 5322bc102bd..5d2de074cae 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -126,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -166,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -176,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -186,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -226,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -336,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -376,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -436,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -446,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -456,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -476,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -536,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -616,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -626,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -646,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -716,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -726,17 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.5" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Text.Encoding.CodePages", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -756,10 +745,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From 2475feb87698ca064e561d85abea5ed643152364 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:49:52 -0400 Subject: [PATCH 344/378] Enable usage in AppContainers (#27266) Co-authored-by: Travis Plunk <travis.plunk@microsoft.com> --- .../engine/Modules/ModuleIntrinsics.cs | 4 ++- .../namespaces/FileSystemProvider.cs | 27 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index 301ee8c3b49..538c4775f0a 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -967,7 +967,9 @@ internal static string GetPersonalModulePath() #if UNIX return Platform.SelectProductNameForDirectory(Platform.XDG_Type.USER_MODULES); #else - string myDocumentsPath = InternalTestHooks.SetMyDocumentsSpecialFolderToBlank ? string.Empty : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + string myDocumentsPath = InternalTestHooks.SetMyDocumentsSpecialFolderToBlank + ? string.Empty + : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify); return string.IsNullOrEmpty(myDocumentsPath) ? null : Path.Combine(myDocumentsPath, Utils.ModuleDirectory); #endif } diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 71de4e8ac67..05c8fff76e0 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -569,7 +569,7 @@ protected override PSDriveInfo NewDrive(PSDriveInfo drive) if (driveIsFixed) { // Since the drive is fixed, ensure the root is valid. - validDrive = Directory.Exists(drive.Root); + validDrive = SafeDoesPathExist(drive.Root); } if (validDrive) @@ -908,7 +908,7 @@ protected override Collection<PSDriveInfo> InitializeDefaultDrives() if (newDrive.DriveType == DriveType.Fixed) { - if (!newDrive.RootDirectory.Exists) + if (!SafeDoesPathExist(newDrive.RootDirectory.FullName)) { continue; } @@ -1227,6 +1227,29 @@ protected override void GetItem(string path) } } + private static bool SafeDoesPathExist(string rootDirectory) + { + if (Directory.Exists(rootDirectory)) + { + return true; + } + + try + { + return (File.GetAttributes(rootDirectory) & FileAttributes.Directory) is not 0; + } + // In some scenarios (like AppContainers) direct access to the root directory may + // be prevented, but more specific paths may be accessible. + catch (UnauthorizedAccessException) + { + return true; + } + catch + { + return false; + } + } + private FileSystemInfo GetFileSystemItem(string path, ref bool isContainer, bool showHidden) { path = NormalizePath(path); From e2784b8867a368f78916829d0c25f2e9a1e2eba3 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:56:25 -0400 Subject: [PATCH 345/378] Update `MaxVisitCount` and `MaxHashtableKeyCount` if `VisitorSafeValueContext` indicates `SkipLimitCheck` is true (#27306) Co-authored-by: Dongbo Wang <dongbow@microsoft.com> --- .../engine/parser/SafeValues.cs | 14 +++++++++----- .../PowerShellData.tests.ps1 | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/SafeValues.cs b/src/System.Management.Automation/engine/parser/SafeValues.cs index 05c87daab5b..38181168a66 100644 --- a/src/System.Management.Automation/engine/parser/SafeValues.cs +++ b/src/System.Management.Automation/engine/parser/SafeValues.cs @@ -47,11 +47,15 @@ public static bool IsAstSafe(Ast ast, GetSafeValueVisitor.SafeValueContext safeV internal IsSafeValueVisitor(GetSafeValueVisitor.SafeValueContext safeValueContext) { _safeValueContext = safeValueContext; + + bool skipSizeCheck = safeValueContext is GetSafeValueVisitor.SafeValueContext.SkipHashtableSizeCheck; + _maxVisitCount = skipSizeCheck ? uint.MaxValue : 5000; + _maxHashtableKeyCount = skipSizeCheck ? int.MaxValue : 500; } internal bool IsAstSafe(Ast ast) { - if ((bool)ast.Accept(this) && _visitCount < MaxVisitCount) + if ((bool)ast.Accept(this) && _visitCount < _maxVisitCount) { return true; } @@ -65,8 +69,8 @@ internal bool IsAstSafe(Ast ast) // This is a check of the number of visits private uint _visitCount = 0; - private const uint MaxVisitCount = 5000; - private const int MaxHashtableKeyCount = 500; + private readonly uint _maxVisitCount; + private readonly int _maxHashtableKeyCount; // Used to determine if we are being called within a GetPowerShell() context, // which does some additional security verification outside of the scope of @@ -330,7 +334,7 @@ public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst) public object VisitHashtable(HashtableAst hashtableAst) { - if (hashtableAst.KeyValuePairs.Count > MaxHashtableKeyCount) + if (hashtableAst.KeyValuePairs.Count > _maxHashtableKeyCount) { return false; } @@ -373,7 +377,7 @@ public static object GetSafeValue(Ast ast, ExecutionContext context, SafeValueCo { t_context = context; - if (safeValueContext == SafeValueContext.SkipHashtableSizeCheck || IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) + if (IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) { return ast.Accept(new GetSafeValueVisitor()); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 index cfba4a4cbed..148993b69b1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 @@ -49,4 +49,10 @@ Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "CI" { $result = Import-PowerShellDataFile $largePsd1Path -SkipLimitCheck $result.Keys.Count | Should -Be 501 } + + It 'Fails if psd1 file is insecure while -SkipLimitCheck is used' { + $path = Setup -f insecure2.psd1 -Content '@{ Foo = [object] (calc.exe) }' -pass + { Import-PowerShellDataFile $path -SkipLimitCheck -ErrorAction Stop } | + Should -Throw -ErrorId "System.InvalidOperationException,Microsoft.PowerShell.Commands.ImportPowerShellDataFileCommand" + } } From 5093967db8e2eb9de77263514ad9aaaf62c5aff8 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 21 Apr 2026 12:05:36 -0700 Subject: [PATCH 346/378] Update Changelog for release v7.6.1 (#27304) --- CHANGELOG/7.6.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CHANGELOG/7.6.md b/CHANGELOG/7.6.md index 47a8d33182f..cd09b76272c 100644 --- a/CHANGELOG/7.6.md +++ b/CHANGELOG/7.6.md @@ -1,5 +1,50 @@ # 7.6 Changelog +## [7.6.1] + +### General Cmdlet Updates and Fixes + +- Delay update notification for one week to ensure all packages become available (#27215) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27179) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 10.0.202</p> + +</summary> + +<ul> +<li>Fix PMC Repo URL for RHEL10 (#27061) (#27062)</li> +<li>Update branch for release (#27287)</li> +<li>Fix package pipeline by adding in PDP-Media directory (#27257)</li> +<li>Pin ready-to-merge.yml reusable workflow to commit SHA (#27245)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tags (#27236)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#27237)</li> +<li>Change the display name of PowerShell-LTS package to PowerShell LTS (#27219)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tokens (#27218)</li> +<li>Redo windows image fix to use latest image (#27217)</li> +<li>Add comment-based help documentation to build.psm1 functions (#27216)</li> +<li>Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27214)</li> +<li>Bump github/codeql-action from 4.34.1 to 4.35.1 (#27184)</li> +<li>Bump github/codeql-action from 4.32.6 to 4.34.1 (#27182)</li> +<li>Select New MSIX Package Name (#27183)</li> +<li>Update the PhoneProductId to be the official LTS id used by Store (#27181)</li> +<li>release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27180)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27177)</li> +<li>Separate Official and NonOfficial templates for ADO pipelines (#27176)</li> +</ul> + +</details> + +[7.6.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0...v7.6.1 + ## [7.6.0] ### General Cmdlet Updates and Fixes From 156906e0504ef82f566376ae53042a1b1f8debf1 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 21 Apr 2026 13:05:14 -0700 Subject: [PATCH 347/378] PMC release: Use slash instead of back-slash for Linux container (#27315) --- .pipelines/templates/release-prep-for-ev2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index e644bece68f..f73caa10450 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -23,7 +23,7 @@ stages: - group: 'mscodehub-code-read-akv' - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false From d50bc2cb73304b18c0505e6d233d61ea361a1220 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:29:46 -0500 Subject: [PATCH 348/378] Correct Variable Template Reference in NonOfficial Pipeline Templates (#27275) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .github/agents/SplitADOPipelines.agent.md | 52 ++++++++++++------- ...Shell-Coordinated_Packages-NonOfficial.yml | 5 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../stages/PowerShell-vPack-Stages.yml | 2 +- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md index 8322f473e7b..9454670061f 100644 --- a/.github/agents/SplitADOPipelines.agent.md +++ b/.github/agents/SplitADOPipelines.agent.md @@ -6,7 +6,7 @@ tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. -A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. +A repository will have under the .pipelines directory a series of yaml files that define the ADO pipelines for the repository. First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this @@ -25,15 +25,31 @@ extends: This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. +## Template Reference Convention (MUST follow) + +All `- template:` references to files **inside this repo** must use the **absolute** form anchored at the repo root, with the `@self` suffix: + +```yaml +- template: /.pipelines/templates/<path>/<file>.yml@self +``` + +Do **not** use relative paths such as `templates/...`, `../templates/...`, or bare filenames. Rationale: + +- Absolute paths resolve identically regardless of where the referring file lives, so moving a pipeline file between directories (for example, into `.pipelines/NonOfficial/`) does not silently break includes. +- Relative paths are resolved by Azure DevOps against the directory of the referring file, which has caused real outages in this repo when a relative include was composed into a nonexistent nested path like `.pipelines/templates/stages/.pipelines/templates/...`. +- The majority of existing includes already use the absolute form; keeping new work consistent reduces review burden. + +The only acceptable non-absolute references are to external repositories resolved via the `resources.repositories` block, for example `v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates`. + ## Refactoring Steps ### Step 1: Extract Shared Templates -For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages-Official.yml`): -1. Create a `./pipelines/templates` directory if it doesn't exist -2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` -3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` +1. Create the `.pipelines/templates/variables` and `.pipelines/templates/stages` directories if they don't exist +2. Extract the **variables section** into `.pipelines/templates/variables/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `.pipelines/templates/stages/PowerShell-Packages-Stages.yml` **IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. @@ -41,7 +57,7 @@ For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Pa The original toggle-based file becomes the Official pipeline: -1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +1. **Keep the file in its original location** (e.g., `.pipelines/PowerShell-Packages-Official.yml` stays where it is) 2. Remove the toggle switch parameter (`templateFile` parameter) 3. Hard-code the Official template reference: ```yaml @@ -51,18 +67,18 @@ The original toggle-based file becomes the Official pipeline: 4. Replace the `variables:` section with a template reference: ```yaml variables: - - template: templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self ``` 5. Replace the `stages:` section with a template reference: ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` ### Step 3: Create NonOfficial Pipeline -1. Create `./pipelines/NonOfficial` directory if it doesn't exist -2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +1. Create `.pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) 3. Copy the structure from the refactored Official pipeline 4. Hard-code the NonOfficial template reference: ```yaml @@ -72,13 +88,13 @@ The original toggle-based file becomes the Official pipeline: 5. Reference the same shared templates: ```yaml variables: - - template: ../templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` -**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. +**Note**: Always use **absolute** template paths of the form `/.pipelines/templates/...@self`. Do not use relative paths like `templates/...` or `../templates/...`. Absolute paths are anchored at the repo root and resolve consistently from any referring file, preventing breakage when files are moved between directories. ### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies @@ -124,29 +140,29 @@ Then you must configure the `ob_release_environment` parameter when referencing #### Official Pipeline Configuration -In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): +In the Official pipeline (e.g., `.pipelines/PowerShell-Packages-Official.yml`): ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Production ``` #### NonOfficial Pipeline Configuration -In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): +In the NonOfficial pipeline (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): ```yaml stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Test ``` #### Update Stages Template to Accept Parameter -The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: +The extracted stages template (e.g., `.pipelines/templates/stages/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: ```yaml parameters: diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 0b417df5c05..69506750c34 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -61,6 +61,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: @@ -90,7 +91,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 9419d3f29b5..0993cd69546 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index b524cb0ff81..4d406fbf9d5 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index 7864513fc2c..ebfc599e42a 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index f1f4211ca8f..071db02cff8 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml index f0d49e8b489..01a83a5b161 100644 --- a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -50,7 +50,7 @@ stages: env: ob_restore_phase: true - - template: .pipelines/templates/SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes From 63544d18bcb533623ddf9d442302a881803adc8b Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:25:39 -0500 Subject: [PATCH 349/378] Download PMC Packages through `TemplateContext` (#27326) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .../PowerShell-Release-Azure-NonOfficial.yml | 8 ++- .../PowerShell-Release-Official-Azure.yml | 2 +- .pipelines/templates/release-prep-for-ev2.yml | 46 ++++++------- .pipelines/templates/release-publish-pmc.yml | 65 ++++++++++++------- 4 files changed, 70 insertions(+), 51 deletions(-) diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 4d406fbf9d5..b0bb4d79b39 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -67,10 +67,16 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: skipPublish: ${{ parameters.skipPublish }} + # NonOfficial: run the publish stage to verify templateContext artifact download, + # but skip the actual Ev2 push to PMC. - template: /.pipelines/templates/release-publish-pmc.yml@self + parameters: + releaseEnvironment: Test + stagePrefix: Test + skipEv2Push: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 24040a2463d..b5f57438925 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -67,7 +67,7 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index f73caa10450..3ad716a3af4 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -11,6 +11,20 @@ stages: displayName: 'Copy EV2 Files to Artifact' pool: type: linux + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_deb + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_rpm + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_x64 + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_arm64 variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -24,6 +38,8 @@ stages: - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false @@ -99,39 +115,17 @@ stages: env: ob_restore_phase: true - - download: PSPackagesOfficial - artifact: 'drop_linux_package_deb' - displayName: 'Download artifact containing .deb_amd64.deb file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_rpm' - displayName: 'Download artifact containing .rh.x64_86.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_x64' - displayName: 'Download artifact containing .cm.x86_64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_arm64' - displayName: 'Download artifact containing .cm.aarch64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - pwsh: | Write-Verbose -Verbose "Copy ESRP signed .deb and .rpm packages" - $downloadedPipelineFolder = Join-Path '$(Pipeline.Workspace)' -ChildPath 'PSPackagesOfficial' + # templateContext.inputs places the PSPackagesOfficial pipelineArtifact files + # directly under $(Pipeline.Workspace), not in per-artifact subfolders. + $downloadedPipelineFolder = '$(Pipeline.Workspace)' $srcFilesFolder = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'SourceFiles' New-Item -Path $srcFilesFolder -ItemType Directory $packagesFolder = Join-Path -Path $srcFilesFolder -ChildPath 'packages' New-Item -Path $packagesFolder -ItemType Directory - $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -Recurse -Directory -Filter "drop_*" | Get-ChildItem -File -Include *.deb, *.rpm + $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -File | Where-Object { $_.Extension -in '.deb', '.rpm' } foreach ($file in $packageFiles) { Write-Verbose -Verbose "copying file: $($file.FullName)" diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml index d5454845211..dc7fc8534e3 100644 --- a/.pipelines/templates/release-publish-pmc.yml +++ b/.pipelines/templates/release-publish-pmc.yml @@ -1,37 +1,56 @@ +parameters: +- name: releaseEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +- name: approvalServiceEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +# OneBranch requires the stage name to be prefixed with the release environment. +# Official uses 'Prod' for Production; NonProd validators require '<env>' (e.g. 'Test', 'PPE'). +- name: stagePrefix + type: string + default: Prod +# When true, the Ev2 push step is skipped. Useful for NonOfficial dry-runs that +# only want to validate artifact download via templateContext.inputs. +- name: skipEv2Push + type: boolean + default: false + stages: -- stage: 'Prod_Release' +- stage: ${{ parameters.stagePrefix }}_Release displayName: 'Deploy packages to PMC with EV2' dependsOn: - PrepForEV2 variables: - name: ob_release_environment - value: "Production" + value: ${{ parameters.releaseEnvironment }} - name: repoRoot value: $(Build.SourcesDirectory) jobs: - - job: Prod_ReleaseJob + - job: ${{ parameters.stagePrefix }}_ReleaseJob displayName: Publish to PMC pool: type: release - - steps: - - task: DownloadPipelineArtifact@2 + templateContext: inputs: - targetPath: '$(Pipeline.Workspace)' - artifact: drop_PrepForEV2_CopyEv2FilesToArtifact - displayName: 'Download drop_PrepForEV2_CopyEv2FilesToArtifact artifact that has all files needed' + - input: pipelineArtifact + artifactName: drop_PrepForEV2_CopyEv2FilesToArtifact - - task: DownloadPipelineArtifact@2 - inputs: - buildType: 'current' - targetPath: '$(Pipeline.Workspace)' - displayName: 'Download to get EV2 Files' - - - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 - displayName: 'Ev2: Push to PMC' - inputs: - UseServerMonitorTask: true - EndpointProviderType: ApprovalService - ApprovalServiceEnvironment: Production - ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot' - RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json' + steps: + - ${{ if not(parameters.skipEv2Push) }}: + - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 + displayName: 'Ev2: Push to PMC' + inputs: + UseServerMonitorTask: true + EndpointProviderType: ApprovalService + ApprovalServiceEnvironment: ${{ parameters.approvalServiceEnvironment }} + ServiceRootPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot' + RolloutSpecPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot/RolloutSpec.json' From 8ac408a172b8d1e0cd440276bf4d6fe921512355 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:42:08 -0400 Subject: [PATCH 350/378] Update CHANGELOG for v7.4.15 (#27314) --- CHANGELOG/7.4.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md index f999c20315f..eb506a7ddbc 100644 --- a/CHANGELOG/7.4.md +++ b/CHANGELOG/7.4.md @@ -1,5 +1,56 @@ # 7.4 Changelog +## [7.4.15] + +### General Cmdlet Updates and Fixes + +- Delay update notification for one week to ensure all packages become available (#27229) +- Close pipe client handles after creating the child ssh process (#27139) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27146) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update .NET SDK to 8.0.420</p> + +</summary> + +<ul> +<li>Fix the container image for vPack, MSIX vPack and Package pipelines (#27018)</li> +<li>Update branch for release (#27279)</li> +<li>Fix package pipeline by adding in PDP-Media directory (#27255)</li> +<li>Pin ready-to-merge.yml reusable workflow to commit SHA (#27247)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tags (#27244)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#27242)</li> +<li>Change the display name of PowerShell-LTS package to PowerShell LTS (#27232)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tokens (#27231)</li> +<li>Redo windows image fix to use latest image (#27230)</li> +<li>Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27228)</li> +<li>Add comment-based help documentation to build.psm1 functions (#27227)</li> +<li>Fix a preview detection test for the packaging script (#27226)</li> +<li>Update the PhoneProductId to be the official LTS id used by Store (#27169)</li> +<li>Select New MSIX Package Name (#27173)</li> +<li>Publish <code>.msixbundle</code> package as a VPack (#27187)</li> +<li>Bump <code>github/codeql-action</code> from 4.32.4 to 4.35.1 (#27143) (#27171) (#27175)</li> +<li><code>release-upload-buildinfo</code>: replace version-comparison channel gating with metadata flags (#27147)</li> +<li>Create infrastructure to create two msixs and msixbundles for LTS and Stable (#27145)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27144)</li> +<li>Bump <code>actions/dependency-review-action</code> from 4.8.3 to 4.9.0 (#27142)</li> +<li>Bump <code>actions/upload-artifact</code> from 6 to 7 (#27141)</li> +<li>Separate Official and NonOfficial templates for ADO pipelines (#27140)</li> +<li>Mirror .NET/runtime ICU version range in PowerShell (#27138)</li> +</ul> + +</details> + +[7.4.15]: https://github.com/PowerShell/PowerShell/compare/v7.4.14...v7.4.15 + ## [7.4.14] ### General Cmdlet Updates and Fixes From 17996679387097b0942e8bea6a155e837ba191ca Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 22 Apr 2026 13:42:33 -0700 Subject: [PATCH 351/378] Update changelog for the v7.5.6 release (#27320) --- CHANGELOG/7.5.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CHANGELOG/7.5.md b/CHANGELOG/7.5.md index d908532ff82..b4f173bcff6 100644 --- a/CHANGELOG/7.5.md +++ b/CHANGELOG/7.5.md @@ -1,5 +1,54 @@ # 7.5 Changelog +## [7.5.6] + +### General Cmdlet Updates and Fixes + +- Delay update notification for one week to ensure all packages become available (#27220) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27166) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 9.0.313</p> + +</summary> + +<ul> +<li>Update branch for the v7.5.6 release (#27268)</li> +<li>Fix package pipeline by adding in <code>PDP-Media</code> directory (#27256)</li> +<li>Pin <code>ready-to-merge.yml</code> reusable workflow to commit SHA (#27246)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tags (#27239)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#27240)</li> +<li>Add comment-based help documentation to <code>build.psm1</code> functions (#27221)</li> +<li>Separate store package creation, skip polling for store publish, clean up <code>PDP-Media</code> (#27225)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tokens (#27224)</li> +<li>Change the display name of "PowerShell-LTS" package to "PowerShell LTS" (#27223)</li> +<li>Redo windows image fix to use latest image (#27222)</li> +<li>Bump <code>github/codeql-action</code> from 4.32.4 to 4.35.1 (#27159) (#27170) (#27174)</li> +<li>Select new MSIX package name (#27172)</li> +<li>Update the <code>PhoneProductId</code> to be the official LTS id used by Store (#27168)</li> +<li>release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27167)</li> +<li>Create infrastructure to create two msixs and msixbundles for LTS and Stable (#27165)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27164)</li> +<li>Create Linux LTS deb/rpm packages for LTS releases (#27163)</li> +<li>Fix the container image for vPack, MSIX vPack and Package pipelines (#27161)</li> +<li>Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27162)</li> +<li>Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#27158)</li> +<li>Bump actions/upload-artifact from 6 to 7 (#27157)</li> +<li>Separate "Official" and "NonOfficial" templates for ADO pipelines (#27155)</li> +</ul> + +</details> + +[7.5.6]: https://github.com/PowerShell/PowerShell/compare/v7.5.5...v7.5.6 + ## [7.5.5] ### Engine Updates and Fixes From 0458f16cc5acd475170afdd546d19021af590e9e Mon Sep 17 00:00:00 2001 From: Anam Navied <anam.naviyou@gmail.com> Date: Fri, 24 Apr 2026 12:33:53 -0400 Subject: [PATCH 352/378] Remove mariner2.0 from PMC mapping (#27068) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- tools/packages.microsoft.com/mapping.json | 32 ----------------------- 1 file changed, 32 deletions(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 154a9582872..7cb212ffee3 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -28,38 +28,6 @@ ], "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, - { - "url": "cbl-mariner-2.0-prod-Microsoft-aarch64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", - "channel": "stable" - }, - { - "url": "cbl-mariner-2.0-prod-Microsoft-x86_64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", - "channel": "stable" - }, - { - "url": "cbl-mariner-2.0-preview-Microsoft-aarch64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", - "channel": "preview" - }, - { - "url": "cbl-mariner-2.0-preview-Microsoft-x86_64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", - "channel": "preview" - }, { "url": "azurelinux-3.0-prod-ms-oss-aarch64", "distribution": [ From 65e6a8055cf5c4bee0911411cdba667bacad2d9d Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 24 Apr 2026 09:52:06 -0700 Subject: [PATCH 353/378] Update PowerShell telemetry to respect the diagnostics and feedback setting on Windows (#27328) --- .../PowerShell.Core.Instrumentation.man | 202 +++++++++++++++--- .../CoreCLR/CorePsPlatform.cs | 9 +- .../engine/remoting/common/PSETWTracer.cs | 4 + .../utils/Telemetry.cs | 10 +- .../utils/WindowsDataCollectionSetting.cs | 185 ++++++++++++++++ .../engine/Basic/Telemetry.Tests.ps1 | 50 +++++ 6 files changed, 427 insertions(+), 33 deletions(-) create mode 100644 src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs diff --git a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man index fb221cfe964..bb4e15351e5 100644 --- a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man +++ b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man @@ -121,6 +121,18 @@ value="0x3002" version="1" /> + <!--Telemetry events--> + <event + channel="C_OPERATIONAL" + level="win:Error" + message="$(string.PS_PROVIDER.event.E_O_TelemetrySettingError.message)" + opcode="Exception" + symbol="TelemetrySettingError" + task="Telemetry" + template="T_TelemetrySettingError" + value="0x3011" + version="1" + /> <!--M3P events--> <event channel="C_ANALYTIC" @@ -2208,17 +2220,41 @@ value="0x6017" version="1" /> - <event - channel="C_ANALYTIC" - keywords="AmsiState" - level="win:Verbose" - message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" - opcode="Method" - symbol="AmsiState" - task="Amsi" - template="T_AmsiState" - value="0x4001" - version="1" + <event + channel="C_ANALYTIC" + keywords="AmsiState" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" + opcode="Method" + symbol="AmsiState" + task="Amsi" + template="T_AmsiState" + value="0x4001" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACQuery" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_WDACQuery.message)" + opcode="Method" + symbol="WDACQuery" + task="WDAC" + template="T_WDACQuery" + value="0x4002" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACAudit" + level="win:Verbose" + message = "$(string.PS_PROVIDER.event.E_A_WDACAudit.message)" + opcode="Method" + symbol="WDACAudit" + task="WDACAudit" + template="T_WDACAudit" + value="0x4003" + version="1" /> </events> <channels> @@ -2409,6 +2445,12 @@ symbol="T_EXPERIMENTALFEATURE" value="107" /> + <task + message="$(string.PS_PROVIDER.task.T_Telemetry.message)" + name="Telemetry" + symbol="T_TELEMETRY" + value="108" + /> <task message="$(string.PS_PROVIDER.task.T_ScheduledJob.message)" name="ScheduledJob" @@ -2427,11 +2469,23 @@ symbol="T_ISEOperation" value="120" /> - <task - message="$(string.PS_PROVIDER.task.T_AmsiState.message)" - name="Amsi" - symbol="T_Amsi" - value="130" + <task + message="$(string.PS_PROVIDER.task.T_AmsiState.message)" + name="Amsi" + symbol="T_Amsi" + value="130" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACQuery.message)" + name="WDAC" + symbol="T_WDAC" + value="131" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACAudit.message)" + name="WDACAudit" + symbol="T_WDACAudit" + value="132" /> </tasks> <opcodes> @@ -2593,11 +2647,23 @@ name="PSWorkflow" symbol="K_PSWORKFLOW" /> - <keyword - mask="0x400" - message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" - name="AmsiState" - symbol="K_AmsiState" + <keyword + mask="0x400" + message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" + name="AmsiState" + symbol="K_AmsiState" + /> + <keyword + mask="0x800" + message="$(string.PS_PROVIDER.keyword.K_WDACQuery.message)" + name="WDACQuery" + symbol="K_WDACQuery" + /> + <keyword + mask="0x1000" + message="$(string.PS_PROVIDER.keyword.K_WDACAudit.message)" + name="WDACAudit" + symbol="K_WDACAudit" /> </keywords> <maps> @@ -4004,6 +4070,20 @@ name="StackTrace" /> </template> + <template tid="T_TelemetrySettingError"> + <data + inType="win:UnicodeString" + name="Name" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="StackTrace" + /> + </template> <template tid="T_TrackingGuid"> <data inType="win:GUID" @@ -4080,16 +4160,48 @@ name="FileName" /> </template> - <template tid="T_AmsiState"> - <data - inType="win:UnicodeString" - name="Action" + <template tid="T_AmsiState"> + <data + inType="win:UnicodeString" + name="Action" /> - <data - inType="win:UnicodeString" - name="AmsiContext" + <data + inType="win:UnicodeString" + name="AmsiContext" /> - </template> + </template> + <template tid="T_WDACQuery"> + <data + inType="win:UnicodeString" + name="QueryName" + /> + <data + inType="win:UnicodeString" + name="FileName" + /> + <data + inType="win:Int32" + name="QuerySuccess" + /> + <data + inType="win:Int32" + name="QuerySResult" + /> + </template> + <template tid="T_WDACAudit"> + <data + inType="win:UnicodeString" + name="Title" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="FullyQualifiedId" + /> + </template> </templates> </provider> </events> @@ -5535,6 +5647,14 @@ id="PS_PROVIDER.task.T_ExperimentalFeature.message" value="PowerShell Experimental Features" /> + <string + id="PS_PROVIDER.event.E_O_TelemetrySettingError.message" + value="Failed to retrieve diagnostics and feedback setting from Windows.%n Exception: %1 %n Message: %2 %n StackTrace: %3 %n" + /> + <string + id="PS_PROVIDER.task.T_Telemetry.message" + value="PowerShell Telemetry" + /> <string id="PS_PROVIDER.task.T_NamedPipe.message" value="PowerShell Named Pipe IPC" @@ -5719,6 +5839,30 @@ id="PS_PROVIDER.event.E_O_REMOTE_NAMEDPIPE_DISCONNECT.message" value="PowerShell IPC disconnect on process: %1 in AppDomain: %2 for User: %3." /> + <string + id="PS_PROVIDER.event.E_A_WDACQuery.message" + value="WDAC Query. %n %t Query: %1 %n %t File: %2 %n %t SuccessCode: %3 %n %t ResultCode: %4" + /> + <string + id="PS_PROVIDER.keyword.K_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.task.T_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.event.E_A_WDACAudit.message" + value="WDAC Audit. %n %t Title: %1 %n %t Message: %2 %n %t FullyQualifiedId: %3" + /> + <string + id="PS_PROVIDER.keyword.K_WDACAudit.message" + value="WDAC Audit" + /> + <string + id="PS_PROVIDER.task.T_WDACAudit.message" + value="WDAC Audit" + /> </stringTable> </resources> </localization> diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 8be65502543..4cbb346fb14 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -179,9 +179,12 @@ public static bool IsStaSupported { int result = Interop.Windows.CoInitializeEx(IntPtr.Zero, Interop.Windows.COINIT_APARTMENTTHREADED); - // If 0 is returned the thread has been initialized for the first time - // as an STA and thus supported and needs to be uninitialized. - if (result > 0) + // Per COM documentation: Each successful call to CoInitializeEx (including S_FALSE) + // must be balanced by a corresponding call to CoUninitialize. + // - S_OK (0) means we initialized for the first time. + // - S_FALSE (1) means already initialized, but still increments the reference count. + // Both require CoUninitialize to decrement the reference count. + if (result >= 0) { Interop.Windows.CoUninitialize(); } diff --git a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs index 2fd2dc0a913..989ad33e987 100644 --- a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs +++ b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs @@ -166,6 +166,9 @@ internal enum PSEventId : int ExperimentalFeature_InvalidName = 0x3001, ExperimentalFeature_ReadConfig_Error = 0x3002, + // Windows Diagnostics And Usage Data Settings + Telemetry_Setting_Error = 0x3011, + // Scheduled Jobs ScheduledJob_Start = 0xD001, ScheduledJob_Complete = 0xD002, @@ -240,6 +243,7 @@ internal enum PSTask : int ProviderStop = 0x69, ExecutePipeline = 0x6A, ExperimentalFeature = 0x6B, + Telemetry = 0x6C, ScheduledJob = 0x6E, NamedPipe = 0x6F, ISEOperation = 0x78, diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 9a67f4bb6ed..fbb7f588283 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -177,12 +177,20 @@ public static class ApplicationInsightsTelemetry /// </summary> static ApplicationInsightsTelemetry() { - // If we can't send telemetry, there's no reason to do any of this CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); +#if !UNIX + if (CanSendTelemetry) + { + // Respect the diagnostics and feedback setting in Windows. + CanSendTelemetry = WindowsDataCollectionSetting.CanCollectDiagnostics(PlatformDataCollectionLevel.Enhanced); + } +#endif + if (!CanSendTelemetry) { + // Avoid the initialization work if we can't send telemetry. return; } diff --git a/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs new file mode 100644 index 00000000000..5f8b607550a --- /dev/null +++ b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if !UNIX + +using System; +using System.Management.Automation.Internal; +using System.Management.Automation.Tracing; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.PowerShell.Telemetry; + +internal enum PlatformDataCollectionLevel : int +{ + /// <summary> + /// Minimum — only security-related data. Enterprise/education editions only. + /// </summary> + Security = 0, + + /// <summary> + /// Device info, capabilities, and basic reliability data. + /// </summary> + Basic = 1, + + /// <summary> + /// More detailed usage and reliability data, including app/feature usage patterns. + /// Removed as a user-facing option in Windows 11 (collapsed into Full). + /// </summary> + Enhanced = 2, + + /// <summary> + /// All of the above plus advanced diagnostics data that can help Microsoft fix problems. + /// </summary> + Full = 3, +} + +/// <summary> +/// Minimal projection of <c>IInspectable</c>, the base interface for all WinRT objects. +/// Slots 3–5 in every WinRT interface vtable (after <c>IUnknown</c>'s QueryInterface/AddRef/Release). +/// </summary> +[GeneratedComInterface] +[Guid("AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90")] +internal partial interface IInspectable +{ + void GetIids(out uint iidCount, out nint iids); + + nint GetRuntimeClassName(); + + int GetTrustLevel(); +} + +/// <summary> +/// Projection of the WinRT interface <c>Windows.System.Profile.IPlatformDiagnosticsAndUsageDataSettingsStatics</c> +/// (IID B6E24C1B-7B1C-4B32-8C62-A66597CE723A). +/// Vtable slots 6–9, following the three <c>IInspectable</c> slots. +/// </summary> +[GeneratedComInterface] +[Guid("B6E24C1B-7B1C-4B32-8C62-A66597CE723A")] +internal partial interface IPlatformDiagnosticsAndUsageDataSettingsStatics : IInspectable +{ + PlatformDataCollectionLevel GetCollectionLevel(); + + long AddCollectionLevelChanged(nint handler); + + void RemoveCollectionLevelChanged(long token); + + // WinRT marshals bool as a byte; use byte to avoid any MarshalAs ambiguity with the source generator. + byte CanCollectDiagnostics(PlatformDataCollectionLevel level); +} + +/// <summary> +/// Wraps <c>Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings</c> using compile-time COM interop +/// and source-generated P/Invoke. No extra runtime DLLs are required. +/// </summary> +internal static partial class WindowsDataCollectionSetting +{ + /// <summary> + /// Returns <see langword="true"/> if the device's diagnostic data collection policy permits collecting at or above <paramref name="level"/>. + /// </summary> + /// <param name="level">The minimum <see cref="PlatformDataCollectionLevel"/> to test against.</param> + internal static bool CanCollectDiagnostics(PlatformDataCollectionLevel level) + { + const string ClassName = "Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings"; + + // When initializing WinRT on the calling thread, use the multi-threaded apartment (MTA). + // This is to cover the case where PowerShell gets used in a thread-pool thread. + // See the doc at https://learn.microsoft.com/windows/win32/api/roapi/ne-roapi-ro_init_type + const int RO_INIT_MULTITHREADED = 1; + + // Return values for 'RoInitialize': + // - S_OK (0) - we successfully initialized; must call 'RoUninitialize'. + // - S_FALSE (1) - already initialized with the same apartment type; must still call 'RoUninitialize'. + // - RPC_E_CHANGED_MODE - already initialized with a different apartment type; WinRT still works, do NOT call 'RoUninitialize'. + const int RPC_E_CHANGED_MODE = unchecked((int)0x80010106); + + int initHr = -1; + nint hstring = default; + nint factoryPtr = default; + + try + { + // Initialize WinRT on the calling thread. 'RoGetActivationFactory' requires it. + initHr = RoInitialize(RO_INIT_MULTITHREADED); + if (initHr < 0 && initHr != RPC_E_CHANGED_MODE) + { + // The call to initialize the Windows Runtime failed. + // Throw an exception with the HRESULT error code to provide more context on the failure. + Marshal.ThrowExceptionForHR(initHr); + } + + Marshal.ThrowExceptionForHR( + WindowsCreateString(ClassName, (uint)ClassName.Length, out hstring)); + + Guid iid = new("B6E24C1B-7B1C-4B32-8C62-A66597CE723A"); + Marshal.ThrowExceptionForHR( + RoGetActivationFactory(hstring, ref iid, out factoryPtr)); + + var comWrappers = new StrategyBasedComWrappers(); + var comObject = comWrappers.GetOrCreateObjectForComInstance(factoryPtr, CreateObjectFlags.None); + var platformSetting = (IPlatformDiagnosticsAndUsageDataSettingsStatics)comObject; + + return platformSetting.CanCollectDiagnostics(level) != 0; + } + catch (Exception ex) + { + // Log any exceptions that occur during this process, but swallow them and return false to disable telemetry rather than crashing the product. + // This API is only used to gate telemetry collection, so failure should be non-fatal. + PSEtwLog.LogOperationalError( + PSEventId.Telemetry_Setting_Error, + PSOpcode.Exception, + PSTask.Telemetry, + PSKeyword.UseAlwaysOperational, + ex.GetType().FullName, + ex.Message, + ex.StackTrace); + + return false; + } + finally + { + if (factoryPtr != default) + { + Marshal.Release(factoryPtr); + } + + if (hstring != default) + { + _ = WindowsDeleteString(hstring); + } + + // Per COM documentation: Each successful call to 'RoInitialize' (including S_FALSE) + // must be balanced by a corresponding call to 'RoUninitialize'. + if (initHr >= 0) + { + RoUninitialize(); + } + } + } + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll", StringMarshalling = StringMarshalling.Utf16)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsCreateString( + string sourceString, + uint length, + out nint hstring); + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsDeleteString(nint hstring); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoGetActivationFactory(nint activatableClassId, ref Guid iid, out nint factory); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoInitialize(int initType); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial void RoUninitialize(); +} + +#endif diff --git a/test/powershell/engine/Basic/Telemetry.Tests.ps1 b/test/powershell/engine/Basic/Telemetry.Tests.ps1 index 2378b9e5a66..0da08316a56 100644 --- a/test/powershell/engine/Basic/Telemetry.Tests.ps1 +++ b/test/powershell/engine/Basic/Telemetry.Tests.ps1 @@ -5,8 +5,53 @@ # these tests aren't going to check that telemetry is being sent # only that we're not treating the telemetry.uuid file correctly +function Get-OSTelemetryLevel { + <# + .SYNOPSIS + Returns the effective Windows Telemetry level (0-3). + Logic: Checks GPO overrides, then System preferences, then defaults to 1. + #> + + $gpoPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" + $sysPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" + $valueName = "AllowTelemetry" + + # 1. Check the "Managed" Policy (Group Policy) + if (Test-Path $gpoPath) { + $gpoValue = Get-ItemProperty -Path $gpoPath -Name $valueName -ErrorAction SilentlyContinue + if ($gpoValue -and $gpoValue.$valueName) { + return [int]$gpoValue.$valueName + } + } + + # 2. Check the "User/System" Preference (Settings App) + if (Test-Path $sysPath) { + $sysValue = Get-ItemProperty -Path $sysPath -Name $valueName -ErrorAction SilentlyContinue + if ($sysValue -and $sysValue.$valueName) { + return [int]$sysValue.$valueName + } + } + + # 3. Fallback to OS Default (Basic/Required) + return 1 +} + Describe "Telemetry for shell startup" -Tag CI { BeforeAll { + $skipTelemetryTests = $false + + if ($IsWindows) { + ## Skip telemetry tests if the OS telemetry level is less than 2 (Enhanced) -- PS telemetry is disabled in this case. + $osTelemetryLevel = Get-OSTelemetryLevel + $skipTelemetryTests = $osTelemetryLevel -lt 2 + } + + if ($skipTelemetryTests) { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues["it:skip"] = $true + return + } + # if the telemetry file exists, move it out of the way # the member is internal, but we can retrieve it via reflection $cacheDir = [System.Management.Automation.Platform].GetField("CacheDirectory","NonPublic,Static").GetValue($null) @@ -23,6 +68,11 @@ Describe "Telemetry for shell startup" -Tag CI { } AfterAll { + if ($skipTelemetryTests) { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + return + } + # check and reset the telemetry.uuid file if ( $uuidFileExists ) { if ( Test-Path -Path "${uuidPath}.original" ) { From d356e3f0e225bad1cb2f9617f6a4cc3a18c3708f Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:19:06 -0700 Subject: [PATCH 354/378] Fix changelog grab failure when only one header exists. (#27371) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .pipelines/templates/release-githubNuget.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index e7c36a49fe6..27a358c7e75 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -89,11 +89,21 @@ jobs: $changelog = Get-Content -Path $filePath $headingPattern = "^## \[\d+\.\d+\.\d+" - $headingStartLines = $changelog | Select-String -Pattern $headingPattern | Select-Object -ExpandProperty LineNumber + $headingStartLines = @($changelog | Select-String -Pattern $headingPattern | Select-Object -ExpandProperty LineNumber) + + if ($headingStartLines.Count -eq 0) { + throw "No release heading matching '$headingPattern' found in $filePath" + } + $startLine = $headingStartLines[0] - $endLine = $headingStartLines[1] - 1 - - $clContent = $changelog | Select-Object -Skip ($startLine-1) -First ($endLine - $startLine) | Out-String + if ($headingStartLines.Count -ge 2) { + $endLine = $headingStartLines[1] - 1 + } else { + # Only one release heading present; take through end of file. + $endLine = $changelog.Count + } + + $clContent = $changelog | Select-Object -Skip ($startLine-1) -First ($endLine - $startLine + 1) | Out-String $StringBuilder = [System.Text.StringBuilder]::new($clContent, $clContent.Length + 2kb) $StringBuilder.AppendLine().AppendLine() > $null From 9db3471c8fd1f8d47e101f2ef485a9fde484420a Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 28 Apr 2026 12:00:46 -0700 Subject: [PATCH 355/378] Update `metadata.json` for the new servicing and preview releases (#27307) --- tools/metadata.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index 57433aec4c6..b2c8b561502 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,10 +1,10 @@ { - "StableReleaseTag": "v7.6.0", - "PreviewReleaseTag": "v7.6.0-rc.1", + "StableReleaseTag": "v7.6.1", + "PreviewReleaseTag": "v7.7.0-preview.1", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.6.0", - "LTSReleaseTag": ["v7.4.14", "v7.6.0"], - "NextReleaseTag": "v7.7.0-preview.1", + "ReleaseTag": "v7.6.1", + "LTSReleaseTag": ["v7.4.15", "v7.6.1"], + "NextReleaseTag": "v7.7.0-preview.2", "LTSRelease": { "PublishToChannels": false, "Package": false }, "StableRelease": { "PublishToChannels": false, "Package": false } } From 11dc00159a1c1529aad26a48adcdfcde3a74ec99 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:07:04 -0700 Subject: [PATCH 356/378] Merge release/v7.7.0-preview.1 into master (#27374) Co-authored-by: Justin Chung <chungjustin@microsoft.com> Co-authored-by: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Co-authored-by: Travis Plunk <travis.plunk@microsoft.com> Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Co-authored-by: Dongbo Wang <dongbow@microsoft.com> Co-authored-by: Anam Navied <anam.naviyou@gmail.com> --- CHANGELOG/preview.md | 250 +++++++ ThirdPartyNotices.txt | 1540 +++++++++-------------------------------- 2 files changed, 579 insertions(+), 1211 deletions(-) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 8e97635bada..8f23d37c9bb 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,2 +1,252 @@ # Preview Changelog +## [7.7.0-preview.1] + +### Breaking Changes + +- Add `ValidateNotNullOrEmpty` attribute to the `-Property` of `Format-Table/List/Custom` (#26552) +- Fix to use accurate message for validating a string argument is not null and not an empty string (#26668) +- Correct handling of explicit `-[Operator]:$false` parameter values in `Where-Object` (#26485) (Thanks @yotsuda!) + +### Engine Updates and Fixes + +- Update `MaxVisitCount` and `MaxHashtableKeyCount` if `VisitorSafeValueContext` indicates `SkipLimitCheck` is true +(#27308) +- Enable usage in AppContainers (#27305) +- Delay update notification for one week to ensure all packages become available (#27095) +- Fix up default value for parameters with the `in` modifier (#26785) (Thanks @jborean93!) +- Fix `WSManInstance` COM interface with `ResourceURI` (#26692) (Thanks @jborean93!) +- Refactor the module path construction code to make it more robust and easier to maintain (#26565) +- Fix checks for local user config file paths (#26269) + +### General Cmdlet Updates and Fixes + +- Add verbose message to `Get-Service` when properties cannot be returned (#27109) (Thanks @reabr!) +- Fix `Remove-Item` confirmation message to use provider path instead (#27123) (Thanks @scuzqy!) +- PSStyle: validate background index against `BackgroundColorMap` (#27106) (Thanks @cuiweixie!) +- Update PowerShell Profile DSC resource manifests to allow null for content (#26929) +- Add `SubjectAlternativeName` property to the `Signature` object returned from `Get-AuthenticodeSignature` (#26252) +- Mark `-NoTypeInformation` as obsolete no-op and evaluate `-IncludeTypeInformation` on by value on Csv cmdlets (#26719) (Thanks @yotsuda!) +- Support `TargetObject` position in `ParserErrors` (#26649) (Thanks @jborean93!) +- Fix the CLR internal error and null ref exception when running `show-command` with PowerShell API (#26669) +- Fix `Test-Json` false positive errors when using `oneOf` or `anyOf` in schema (#26618) (Thanks @yotsuda!) +- Add `ToRegex` method to `WildcardPattern` class (#26515) (Thanks @yotsuda!) +- Add `-ExcludeProperty` parameter to `Format-*` cmdlets (#26514) (Thanks @yotsuda!) +- Fix NOTES section formatting in comment-based help (#26512) (Thanks @yotsuda!) +- Disable AMSI content logging in release (#26235) (Thanks @xtqqczze!) +- Add tab completion for `$PSBoundParameters.Keys` switch cases and access patterns (#26483) (Thanks @yotsuda!) +- Fix formatting to properly handle the `Reset` VT sequences that appear in the middle of a string (#26424) +- Add `-Extension` parameter to `Join-Path` cmdlet (#26482) (Thanks @yotsuda!) +- Make `Export-Csv` `-Append` and `-NoHeader` mutually exclusive (#26472) (Thanks @yotsuda!) +- Respect `-Qualifier/-NoQualifier/-Leaf/-IsAbsolute:$false` in `Split-Path` (#26474) (Thanks @yotsuda!) +- Respect `-UseWindowsPowerShell:$false` in `New-PSSession` (#26469) (Thanks @yotsuda!) +- Respect `-Repeat/-MtuSize/-Traceroute:$false` in `Test-Connection` (#26479) (Thanks @yotsuda!) +- Fix `Invoke-RestMethod` to support read-only files in multipart form data (#26454) (Thanks @yotsuda!) +- Respect `-ListAvailable:$false` in `Get-TimeZone` (#26463) (Thanks @yotsuda!) +- Respect `-Shuffle:$false` in `Get-SecureRandom` (#26460) (Thanks @yotsuda!) +- Respect `-Shuffle:$false` in `Get-Random` (#26457) (Thanks @yotsuda!) +- DSC v3 resource for Powershell Profile (#26157) +- Make the experimental feature `PSFeedbackProvider` stable (#26343) +- Make some experimental features stable (#26348) +- Add `PSApplicationOutputEncoding` variable (#21219) (Thanks @jborean93!) +- Dynamically evaluate width of `LastWriteTime` for formatting output on Unix (#24624) (Thanks @MathiasMagnus!) +- Handle null reference exception in CsvCommands.cs: `ConvertPSObjectToCSV` (#26144) (Thanks @mikkas456!) +- Improve `ValidateLength` error message consistency and refactor validation tests (#25806) (Thanks @jorgeasaurus!) +- Correct handling of explicit `-Since:$false` parameter value in `Get-Uptime` (#26141) (Thanks @logiclrd!) +- Add property and event for debug attach (#25788) (Thanks @jborean93!) +- Fix memory leak in `GetFileShares` (#25896) (Thanks @xtqqczze!) +- Correct handling of explicit `-Empty:$false` parameter value in `New-Guid` (#26140) (Thanks @logiclrd!) + +### Code Cleanup + +<details> + +<summary> + +<p>We thank the following contributors!</p> +<p>@xtqqczze, @yotsuda, @ThioJoe, @rwp0, @amritanand-py</p> + +</summary> + +<ul> +<li>Fix <code>IDisposable</code> implementation in sealed classes (#26215) (Thanks @xtqqczze!)</li> +<li>Enable CA1852: Seal internal types (#25890) (Thanks @xtqqczze!)</li> +<li>Remove obsolete <code>CA2006</code> rule suppression (#25939) (Thanks @xtqqczze!)</li> +<li>Use consistent indentation in the file <code>HelpersCommon.psm1</code> (#26608)</li> +<li>Centralize <code>ExcludeProperty</code> filter application in <code>ViewGenerator</code> base class (#26574) (Thanks @yotsuda!)</li> +<li>Refactor <code>IsComputerNameValid</code> character validation (#26274) (Thanks @xtqqczze!)</li> +<li>Remove obsolete test/docker/networktest directory (#26388)</li> +<li>Avoid regex for exact word matching in <code>DscClassCache</code> (#26306) (Thanks @xtqqczze!)</li> +<li>Enable analyzers: Use char overload (#26301) (Thanks @xtqqczze!)</li> +<li>Enable CA1200: Avoid using cref tags with a prefix (#26298) (Thanks @xtqqczze!)</li> +<li>Remove unused timeout variable from <code>RemoteHyperVTests</code> class (#26297) (Thanks @xtqqczze!)</li> +<li>Enable CA2022: Avoid inexact read with <code>Stream.Read</code> (#25814) (Thanks @xtqqczze!)</li> +<li>Fix a few simple typos in comments and string outputs (#25805) (Thanks @ThioJoe!)</li> +<li>Remove unused Azure Devops windows CI workflows (#26245)</li> +<li>Fix CA1837: Use <code>Environment.ProcessId</code> (#26242) (Thanks @xtqqczze!)</li> +<li>Enable IDE0080: RemoveConfusingSuppressionForIsExpression (#26206) (Thanks @xtqqczze!)</li> +<li>Remove redundant <code>CharSet</code> from <code>StructLayout</code> attributes. Part 1 (#26216) (Thanks @xtqqczze!)</li> +<li>Fix IDE0083: UseNotPattern (#26213) (Thanks @xtqqczze!)</li> +<li>Fix <code>IDE0049</code> for <code>string</code> in <code>System.Management.Automation</code> (#25921) (Thanks @xtqqczze!)</li> +<li>Fix <code>IDE0049</code> for <code>object</code> in <code>System.Management.Automation</code>. Part 1 (#25923) (Thanks @xtqqczze!)</li> +<li>Replace stackallocs with collection expressions (#25803) (Thanks @xtqqczze!)</li> +<li>Capitalize Windows in <code>PSNativeWindowsTildeExpansion</code> experimental feature description (#25266) (Thanks @rwp0!)</li> +<li>Fix <code>SA1028</code>: Code should not contain trailing whitespace. Part 1. (#26203) (Thanks @xtqqczze!)</li> +<li>Fix IDE0083: UseNotPattern (#26209) (Thanks @xtqqczze!)</li> +<li>Fix CA1852: Seal internal types. Part 1 (#26205) (Thanks @xtqqczze!)</li> +<li>Enable IDE0019: InlineAsTypeCheck (#25920) (Thanks @xtqqczze!)</li> +<li>Fix mismatched indentation in <code>.config/suppress.json</code> (#26192) (Thanks @xtqqczze!)</li> +<li>Replace custom method with <code>File.ReadAllText()</code> in ScriptAnalysis.cs (#26060) (Thanks @amritanand-py!)</li> +<li>Avoid possible multiple enumerations in <code>ImportModuleCommand.IsPs1xmlFileHelper_IsPresentInEntries</code> (#26104) (Thanks @xtqqczze!)</li> +<li>Enable <code>SA1206</code>: Declaration keywords should follow order (#24973) (Thanks @xtqqczze!)</li> +<li>Disable IDE0049: PreferBuiltInOrFrameworkType (#26094) (Thanks @xtqqczze!)</li> +<li>Enable CA1853: Unnecessary call to <code>Dictionary.ContainsKey(key)</code> (#26106) (Thanks @xtqqczze!)</li> +<li>Enable CA1860: Avoid using <code>Enumerable.Any()</code> extension method (#26109) (Thanks @xtqqczze!)</li> +<li>Enable CA1858: Use <code>StartsWith</code> instead of <code>IndexOf</code> (#26107) (Thanks @xtqqczze!)</li> +<li>Add <code>CodeQL</code> suppressions for <code>NativeCommandProcessor</code> (#26729)</li> +</ul> + +</details> + +### Tools + +- Add GitOps policy to auto-label backport candidates when CL-BuildPackaging is added (#26881) +- Add Pester CI Analysis Skill (#26806) +- Delete unused winget release script (#26683) +- Improve error message from `Start-NativeExecution` (#26500) (Thanks @logiclrd!) +- Add default CODEOWNERS entry for maintainers (#26660) +- Add Attack Surface Analyzer Script (#26379) +- Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26350) +- Add reusable get-changed-files action and refactor existing actions (#26355) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26322) +- Create github copilot setup workflow (#26285) +- Update dependabot.yml to monitor release/* branches (#26251) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27057) +- Fix `Import-Module.Tests.ps1` to handle Arm32 platform (#26862) +- Add comprehensive PowerShell class tests for `ConvertTo-Json` (#26769) (Thanks @yotsuda!) +- Add comprehensive `PSCustomObject` tests for `ConvertTo-Json` (#26743) (Thanks @yotsuda!) +- Add GitHub Actions annotations for Pester test failures (#26789) +- Add comprehensive depth and multilevel composition tests for `ConvertTo-Json` (#26744) (Thanks @yotsuda!) +- Add comprehensive array and dictionary tests for `ConvertTo-Json` (#26742) (Thanks @yotsuda!) +- Add comprehensive scalar type tests for `ConvertTo-Json` (#26736) (Thanks @yotsuda!) +- Fix the fuzzy test (#26402) +- Add Fuzz Tests (#26384) +- Fix merge conflict checker for empty file lists and filter *.cs files (#26365) +- Fix linux_packaging job being skipped when only packaging files change (#26315) +- Use `[initialsessionstate]` type accelerator (#25912) (Thanks @xtqqczze!) +- Add markdown link verification for PRs (#26219) +- Check for `GetWindowPlacement` success (#26122) (Thanks @xtqqczze!) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>We thank the following contributors!</p> +<p>@powercode, @kasperk81, @xtqqczze</p> + +</summary> + +<ul> +<li>Update branch for release (#27291)</li> +<li>Remove package verification from the notice pipeline (#27289)</li> +<li>Remove MSI from publishing pipeline (#27213)</li> +<li>Externalize <code>findMissingNotices</code> target framework selection with ordered Windows fallback (#27269)</li> +<li>Fix the package pipeline by adding in PDP-Media directory (#27254)</li> +<li>Bump actions/checkout from 4 to 6.0.2 (#27206)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#150) (#27209)</li> +<li>Pin ready-to-merge.yml reusable workflow to commit SHA (#27204)</li> +<li>Change the display name of <code>PowerShell-LTS</code> MSIX package to "PowerShell LTS" (#27203)</li> +<li>[StepSecurity] ci: Harden GitHub Actions (#27201)</li> +<li>[StepSecurity] ci: Harden GitHub Actions (#27202)</li> +<li>Redo windows image fix to use latest image (#27198)</li> +<li>Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27024)</li> +<li>Revert "Fetch latest ICU release version dynamically" (#27127)</li> +<li>Update package references and move to .NET SDK 11.0-preview.2 (#27117)</li> +<li>Add comment-based help documentation to <code>build.psm1</code> functions (#27122) (Thanks @powercode!)</li> +<li>Bump github/codeql-action from 3.30.3 to 4.35.1 (#27120)</li> +<li>Select New MSIX Package Name (#27096)</li> +<li>Separate Official and NonOfficial templates for ADO pipelines (#26897)</li> +<li>Update the <code>PhoneProductId</code> to be the official LTS id used by Store (#27077)</li> +<li>release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27074)</li> +<li>Update build to create two msix's and msixbundles for LTS and Stable (#27056)</li> +<li>Update <code>metadata.json</code> for the v7.6.0 release (#27054)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27052)</li> +<li>Fix PMC repo URL for RHEL10 (#27059)</li> +<li>Create Linux LTS deb/rpm packages for LTS releases (#27049)</li> +<li>Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27039)</li> +<li>Fix the container image for vPack, MSIX vPack and Package pipelines (#27015)</li> +<li>Update <code>Microsoft.PowerShell.PSResourceGet</code> version to 1.2.0 (#27003)</li> +<li>Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26893)</li> +<li>Bump actions/upload-artifact from 4 to 7 (#26914)</li> +<li>Bump actions/dependency-review-action from 4.7.3 to 4.9.0 (#26938)</li> + +<li>Hardcode Official templates (#26928)</li> +<li>Add PMC packages for debian13 and rhel10 (#26912)</li> +<li>Split TPN manifest and Component Governance manifest (#26891)</li> +<li>Add version in description and pass store task on failure (#26885)</li> +<li>Correct the package name for .deb and .rpm packages (#26877)</li> +<li>Fix a preview detection test for the packaging script (#26882)</li> +<li>Exclude .exe packages from publishing to GitHub (#26859)</li> +<li>Update metadata.json for v7.6.0-rc.1 (#26856)</li> +<li>Fetch latest ICU release version dynamically (#26827) (Thanks @kasperk81!)</li> +<li>Update <code>LangVersion</code> to <code>preview</code> (#26214) (Thanks @xtqqczze!)</li> +<li>Update to .NET 11 SDK and update dependencies (#26783)</li> +<li>Update outdated package references (#26771)</li> +<li>Create es-metadata (#26759)</li> +<li>Add policy to restrict the <code>Approved-LowRisk</code> label (#26728)</li> +<li>Move PowerShell build to depend on .NET SDK 10.0.102 (#26697)</li> +<li>Update metadata.json to update the Latest attribute with a better name (#26380)</li> +<li>Update outdated package references (#26656)</li> +<li>Bring release changes from the v7.6.0-preview.6 release branch (#26627)</li> +<li>Update build to use .NET SDK 10.0.100 (#26448)</li> +<li>Update the macos package name for preview releases to match the previous pattern (#26429)</li> +<li>Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26427)</li> +<li>Fix template path for rebuild branch check in package.yml (#26425)</li> +<li>Update the WCF packages to the latest version that is compatible with v4.10.3 (#26406)</li> +<li>Add rebuild branch support with conditional MSIX signing (#26415)</li> +<li>Optimize/split windows package signing (#26403)</li> +<li>Improve ADO package build and validation across platforms (#26398)</li> +<li>Update outdated test package references (#26368)</li> +<li>Delete this way of collecting feedback (#26364)</li> +<li>Update the <code>Microsoft.PowerShell.Native</code> package version (#26347)</li> +<li>Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26326)</li> +<li>Bump actions/setup-dotnet from 4 to 5 (#26327)</li> +<li>Update SDK to 10.0.100-rc.2.25502.107 (#26305)</li> +<li>Replace <code>fpm</code> with <code>dpkg-deb</code> for DEB package generation (#26281)</li> +<li>Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26268)</li> +<li>Separate Store Automation Service Endpoints, Resolve AppID (#26210)</li> +<li>Update concurrency groups to prevent merge runs and pull request runs from canceling each other (#26257)</li> +<li>Update release tags to version 7.5.4 and 7.4.13 (#26258)</li> +<li>Update outdated package references (#26148)</li> +<li>Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26243)</li> +<li>Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26225)</li> +<li>Update vPack name (#26090)</li> +<li>Update <code>metadata.json</code> for v7.6.0-preview.5 release (#26158)</li> +<li>Bump ossf/scorecard-action from 2.4.2 to 2.4.3 (#26128)</li> +</ul> + +</details> + +### Documentation and Help Content + +- Check in `7.6.md` after v7.6.0 release (#27063) +- Update changelog for release v7.5.5 (#27014) +- Add 7.4.14 changelog (#26998) +- Update `SECURITY.md` to remove email reporting option (#26653) +- Update changelog for the release v7.6.0-preview.6 (#26597) +- Explain the parameter `-UseNuGetOrg` in build documentation (#26507) (Thanks @logiclrd!) +- Update backport prompt (#26392) +- Add a backport prompt for copilot (#26383) +- Update `linux.md` documentation to reflect current CI build configuration (#26255) +- Add GitHub Copilot instruction files for PowerShell CI build system (#26253) +- Add documentation for publishing Pester test results in GitHub Actions (#26254) +- Remove Gitter from README (#26200) (Thanks @xtqqczze!) +- Remove nightly build status section from README.md (#26227) (Thanks @xtqqczze!) +- Update changelog for v7.5.4 and v7.4.13 (#26202) + +[7.7.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-rc.1...v7.7.0-preview.1 diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 8abff24592f..4d033a0f682 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Markdig.Signed 0.42.0 - BSD-2-Clause +Markdig.Signed 0.45.0 - BSD-2-Clause @@ -170,7 +170,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 9.0.9 - MIT +Microsoft.Bcl.AsyncInterfaces 10.0.3 - MIT Copyright (c) 2021 @@ -193,7 +193,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -214,7 +214,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -231,36 +230,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.14.0 - MIT +Microsoft.CodeAnalysis.Common 5.0.0 - MIT (c) Microsoft Corporation @@ -280,7 +264,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.14.0 - MIT +Microsoft.CodeAnalysis.CSharp 5.0.0 - MIT (c) Microsoft Corporation @@ -305,7 +289,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 9.0.9 - MIT +Microsoft.Extensions.ObjectPool 10.0.3 - MIT Copyright Jorn Zaefferer @@ -395,7 +379,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.9 - MIT +Microsoft.Win32.Registry.AccessControl 10.0.3 - MIT Copyright (c) 2021 @@ -418,7 +402,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -439,7 +423,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -456,36 +439,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.9 - MIT +Microsoft.Win32.SystemEvents 10.0.3 - MIT Copyright (c) 2021 @@ -508,7 +476,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -529,7 +497,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -546,36 +513,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.9 - MIT +Microsoft.Windows.Compatibility 10.0.3 - MIT (c) Microsoft Corporation @@ -628,7 +580,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -651,7 +603,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -672,7 +624,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -689,36 +640,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -741,7 +677,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -762,7 +698,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -779,36 +714,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -831,7 +751,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -852,7 +772,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -869,36 +788,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -921,7 +825,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -942,7 +846,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -959,36 +862,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1011,7 +899,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1032,7 +920,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1049,36 +936,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1101,7 +973,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1122,7 +994,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1139,36 +1010,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1191,7 +1047,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1212,7 +1068,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1229,36 +1084,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) <year> <copyright holders> -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1281,7 +1121,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1302,7 +1142,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1319,36 +1158,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1371,7 +1195,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1392,7 +1216,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1409,36 +1232,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1461,7 +1269,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1482,7 +1290,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1499,36 +1306,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1551,7 +1343,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1572,7 +1364,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1589,36 +1380,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1641,7 +1417,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1662,7 +1438,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1679,36 +1454,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1731,7 +1491,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1752,7 +1512,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1769,36 +1528,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1821,7 +1565,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1842,7 +1586,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1859,30 +1602,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -1933,7 +1661,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1956,7 +1684,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1977,7 +1705,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1994,36 +1721,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -2046,7 +1758,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2067,7 +1779,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2084,36 +1795,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -2136,7 +1832,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2157,7 +1853,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2174,36 +1869,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) <year> <copyright holders> -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.CodeDom 9.0.9 - MIT +System.CodeDom 10.0.3 - MIT Copyright (c) 2021 @@ -2226,7 +1906,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2247,7 +1927,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2264,36 +1943,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ComponentModel.Composition 9.0.9 - MIT +System.ComponentModel.Composition 10.0.3 - MIT Copyright (c) 2021 @@ -2316,7 +1980,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2337,7 +2001,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2354,36 +2017,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.9 - MIT +System.ComponentModel.Composition.Registration 10.0.3 - MIT Copyright (c) 2021 @@ -2406,7 +2054,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2427,7 +2075,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2444,36 +2091,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.9 - MIT +System.Configuration.ConfigurationManager 10.0.3 - MIT Copyright (c) 2021 @@ -2496,7 +2128,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2517,7 +2149,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2534,36 +2165,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Data.Odbc 9.0.9 - MIT +System.Data.Odbc 10.0.3 - MIT Copyright (c) 2021 @@ -2586,7 +2202,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2607,7 +2223,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2624,36 +2239,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Data.OleDb 9.0.9 - MIT +System.Data.OleDb 10.0.3 - MIT Copyright (c) 2021 @@ -2676,7 +2276,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2697,7 +2297,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2714,30 +2313,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -2762,7 +2346,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.9 - MIT +System.Diagnostics.EventLog 10.0.3 - MIT Copyright (c) 2021 @@ -2785,7 +2369,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2806,7 +2390,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2823,36 +2406,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.9 - MIT +System.Diagnostics.PerformanceCounter 10.0.3 - MIT Copyright (c) 2021 @@ -2875,7 +2443,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2896,7 +2464,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2913,36 +2480,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices 9.0.9 - MIT +System.DirectoryServices 10.0.3 - MIT Copyright (c) 2021 @@ -2965,7 +2517,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2986,7 +2538,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3003,36 +2554,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.9 - MIT +System.DirectoryServices.AccountManagement 10.0.3 - MIT Copyright (c) 2021 @@ -3055,7 +2591,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3076,7 +2612,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3093,36 +2628,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) <year> <copyright holders> -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.9 - MIT +System.DirectoryServices.Protocols 10.0.3 - MIT Copyright (c) 2021 @@ -3145,7 +2665,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3166,7 +2686,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3183,36 +2702,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Drawing.Common 9.0.9 - MIT +System.Drawing.Common 10.0.3 - MIT (c) Microsoft Corporation @@ -3247,7 +2751,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.9 - MIT +System.IO.Packaging 10.0.3 - MIT Copyright (c) 2021 @@ -3270,7 +2774,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3291,7 +2795,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3308,36 +2811,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.IO.Ports 9.0.9 - MIT +System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -3360,7 +2848,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3381,7 +2869,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3398,36 +2885,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Management 9.0.9 - MIT +System.Management 10.0.3 - MIT Copyright (c) 2021 @@ -3450,7 +2922,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3471,7 +2943,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3488,36 +2959,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.9 - MIT +System.Net.Http.WinHttpHandler 10.0.3 - MIT Copyright (c) 2021 @@ -3540,7 +2996,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3561,7 +3017,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3578,72 +3033,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.Private.ServiceModel 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Reflection.Context 9.0.9 - MIT +System.Reflection.Context 10.0.3 - MIT Copyright (c) 2021 @@ -3666,7 +3070,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3687,7 +3091,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3704,36 +3107,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Runtime.Caching 9.0.9 - MIT +System.Runtime.Caching 10.0.3 - MIT Copyright (c) 2021 @@ -3756,7 +3144,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3777,7 +3165,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3794,36 +3181,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.9 - MIT +System.Security.Cryptography.Pkcs 10.0.3 - MIT Copyright (c) 2021 @@ -3846,7 +3218,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3867,7 +3239,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3884,36 +3255,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.9 - MIT +System.Security.Cryptography.ProtectedData 10.0.3 - MIT Copyright (c) 2021 @@ -3936,7 +3292,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3957,7 +3313,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3974,36 +3329,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.9 - MIT +System.Security.Cryptography.Xml 10.0.3 - MIT Copyright (c) 2021 @@ -4026,7 +3366,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4047,7 +3387,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4064,36 +3403,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Permissions 9.0.9 - MIT +System.Security.Permissions 10.0.3 - MIT Copyright (c) 2021 @@ -4116,7 +3440,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4137,7 +3461,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4154,113 +3477,26 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.ServiceModel.Duplex 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.ServiceModel.Http 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ServiceModel.NetTcp 4.10.3 - MIT +System.ServiceModel.Http 10.0.652802 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4291,12 +3527,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Primitives 4.10.3 - MIT +System.ServiceModel.NetFramingBase 10.0.652802 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4327,12 +3563,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Security 4.10.3 - MIT +System.ServiceModel.NetTcp 10.0.652802 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4363,66 +3599,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.9 - MIT +System.ServiceModel.Primitives 10.0.652802 - MIT -Copyright (c) 2021 -Copyright (c) Six Labors (c) Microsoft Corporation -Copyright (c) 2022 FormatJS -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -Copyright (c) 1998 Microsoft -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 2015 Andrew Gallant -Copyright (c) 2022, Wojciech Mula -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2022, Geoff Langdale -Copyright (c) 2005-2020 Rich Felker -Copyright (c) 2012-2021 Yann Collet -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2018 Nemanja Mijailovic -Copyright 2012 the V8 project authors -Copyright (c) 1999 Lucent Technologies -Copyright (c) 2008-2016, Wojciech Mula -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2011-2015 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -(c) 1995-2024 Jean-loup Gailly and Mark Adler -Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> Copyright (c) .NET Foundation and Contributors -Copyright (c) 2012 - present, Victor Zverovich -Copyright (c) 2006 Jb Evain (jbevain@gmail.com) -Copyright (c) 2008-2020 Advanced Micro Devices, Inc. -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Portions (c) International Organization for Standardization 1986 -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright (c) 1980, 1986, 1993 The Regents of the University of California -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4453,7 +3635,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.9 - MIT +System.ServiceModel.Syndication 10.0.3 - MIT Copyright (c) 2021 @@ -4476,7 +3658,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4497,7 +3679,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4514,36 +3695,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Speech 9.0.9 - MIT +System.ServiceProcess.ServiceController 10.0.3 - MIT Copyright (c) 2021 @@ -4566,7 +3732,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4587,7 +3753,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4604,36 +3769,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Threading.AccessControl 9.0.9 - MIT +System.Speech 10.0.3 - MIT Copyright (c) 2021 @@ -4656,7 +3806,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4677,7 +3827,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4694,30 +3843,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -4759,7 +3893,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.9 - MIT +System.Windows.Extensions 10.0.3 - MIT Copyright (c) 2021 @@ -4782,7 +3916,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4803,7 +3937,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos <m-ou.se@m-ou.se> -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4820,30 +3953,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) <year> <copyright holders> -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- From da95729be5a451575ad6c8dbec6d29ee0dcc1ebc Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Wed, 22 Apr 2026 12:32:40 -0700 Subject: [PATCH 357/378] Add macOS binary code signing and package notarization We still need to apply the template signing so that Guardian tasks pass and so that script files are signed. After doing what's essentially Windows signing, we sign and harden the binaries for macOS. Then we do the same for the PKG installer, and finally notarize it. The ESRP signing service requires a zip of files for Apple signing at all stages. Now that we can use it via the OneBranch signing task we no longer need the service connection or variable group that was trying to set it up. Notarization requires the BundleId from Get-MacOSPackageIdentifierInfo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/mac-package-build.yml | 65 ++++++++++++++++++---- .pipelines/templates/mac.yml | 32 +++++++++++ tools/packaging/packaging.psd1 | 1 + 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 6585773c743..154cb6c0257 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -76,6 +76,14 @@ jobs: # Diagnostics is not critical it passes every time it runs continueOnError: true + - pwsh: | + $signedDir = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/drop_macos_sign_${{ parameters.buildArchitecture }}/Signed-${{ parameters.buildArchitecture }}" + Get-ChildItem $signedDir -Recurse -Include 'pwsh', '*.dylib' | ForEach-Object { + codesign --verify --deep --strict --verbose=4 $_.FullName + if ($LASTEXITCODE -ne 0) { throw "codesign verification failed for $($_.FullName)" } + } + displayName: 'Verify Apple codesign on signed binaries' + - pwsh: | # Add -SkipReleaseChecks as a mitigation to unblock release. # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. @@ -158,7 +166,12 @@ jobs: Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } + $packageInfo = Get-MacOSPackageIdentifierInfo -Version '$(Version)' -LTS:$LTS + Write-Verbose -Verbose "BundleId: $($packageInfo.PackageIdentifier)" + Write-Host "##vso[task.setvariable variable=BundleId;isOutput=true]$($packageInfo.PackageIdentifier)" + displayName: 'Package ${{ parameters.buildArchitecture}}' + name: packageStep env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) @@ -178,7 +191,8 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - name: BuildArch value: ${{ parameters.buildArchitecture }} - - group: mscodehub-macos-package-signing + - name: BundleId + value: $[ dependencies.package_macOS_${{ parameters.buildArchitecture }}.outputs['packageStep.BundleId'] ] steps: - download: current @@ -216,32 +230,59 @@ jobs: inline_operation: | [ { - "KeyCode": "$(KeyCode)", + "KeyCode": "CP-401337-Apple", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", "Parameters": { - "Hardening": "Enable", - "OpusInfo": "http://microsoft.com" + "Hardening": "--options=runtime" } } ] + - task: onebranch.pipeline.signing@1 + displayName: 'OneBranch Notarize Package' + inputs: + command: 'sign' + files_to_sign: '**/*-osx-*.zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "CP-401337-Apple", + "OperationCode": "MacAppNotarize", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "BundleId": "$(BundleId)" + } + } + ] + timeoutInMinutes: 120 + - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File + if (-not (Test-Path $(ob_outputDirectory))) { + $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory + } + + $expandDir = "$(Pipeline.Workspace)/pkgExpand" + $null = New-Item -Path $expandDir -ItemType Directory -Force + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" + Expand-Archive -Path $_ -DestinationPath $expandDir -Verbose + } - if (-not (Test-Path $_)) { - throw "Package not found: $_" - } - - if (-not (Test-Path $(ob_outputDirectory))) { - $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory - } + # ESRP's signing pipeline nests the PKG inside a '<hash>.zip.unzipped' subfolder + $pkgFile = Get-ChildItem -Path $expandDir -Filter '*.pkg' -Recurse -File + if (-not $pkgFile) { + throw "Package not found in: $signedPkg" + } - Expand-Archive -Path $_ -DestinationPath $(ob_outputDirectory) -Verbose + $pkgFile | ForEach-Object { + Move-Item -Path $_ -Destination $(ob_outputDirectory) -Verbose } Write-Verbose -Verbose "Expanded pkg file:" diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 1699207c657..38b83423057 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -144,4 +144,36 @@ jobs: binPath: $(DropRootPath) OfficialBuild: $(ps_official_build) + # Apple-sign the Mach-O binaries inside the signed output. + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Compress-Archive -Path "$signedDir/*" -DestinationPath $zipFile -Force + displayName: Compress signed folder for Apple signing + + - task: onebranch.pipeline.signing@1 + displayName: Apple CodeSign Mach-O binaries + inputs: + command: 'sign' + files_to_sign: 'macho-$(BuildArchitecture).zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "CP-401337-Apple", + "OperationCode": "MacAppDeveloperSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "Hardening": "--options=runtime" + } + } + ] + + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Expand-Archive -Path $zipFile -DestinationPath $signedDir -Force -Verbose + displayName: Expand Apple-signed Mach-O binaries into signed output + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/tools/packaging/packaging.psd1 b/tools/packaging/packaging.psd1 index b72c14b80f1..d7c27b2c3cc 100644 --- a/tools/packaging/packaging.psd1 +++ b/tools/packaging/packaging.psd1 @@ -23,6 +23,7 @@ 'Test-PackageManifest' 'Update-PSSignedBuildFolder' 'Test-Bom' + 'Get-MacOSPackageIdentifierInfo' ) RootModule = "packaging.psm1" RequiredModules = @("build") From b9bd8cbc59762f4e4d4dc81a08e6b7417efd2937 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:11:13 -0700 Subject: [PATCH 358/378] Apply macOS entitlements to pwsh Uses codesign in the macOS build step to apply entitlements from a plist. This is required for the hardened runtime (which is required for notarization). See: https://learn.microsoft.com/en-us/dotnet/core/install/macos-notarization-issues#default-entitlements Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/mac.yml | 8 ++++++++ assets/macos-entitlements.plist | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 assets/macos-entitlements.plist diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 38b83423057..b22149d5e46 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -69,6 +69,14 @@ jobs: $psOptPath = "$(OB_OUTPUTDIRECTORY)/psoptions.json" Save-PSOptions -PSOptionsPath $psOptPath + $entitlements = "$(PowerShellRoot)/assets/macos-entitlements.plist" + $pwshBin = "$(OB_OUTPUTDIRECTORY)/pwsh" + Write-Verbose -Verbose "Applying entitlements to $pwshBin" + codesign --sign - --force --options runtime --entitlements $entitlements $pwshBin + if ($LASTEXITCODE -ne 0) { + throw "codesign failed with exit code $LASTEXITCODE" + } + # Since we are using custom pool for macOS, we need to use artifact.upload to publish the artifacts Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName]$(OB_OUTPUTDIRECTORY)" diff --git a/assets/macos-entitlements.plist b/assets/macos-entitlements.plist new file mode 100644 index 00000000000..9d534f4f4bf --- /dev/null +++ b/assets/macos-entitlements.plist @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.cs.allow-jit</key> + <true/> + <key>com.apple.security.cs.allow-unsigned-executable-memory</key> + <true/> + <key>com.apple.security.cs.allow-dyld-environment-variables</key> + <true/> + <key>com.apple.security.cs.disable-library-validation</key> + <true/> +</dict> +</plist> From ddff03a50fefa22ab16fec5e595153676fae9284 Mon Sep 17 00:00:00 2001 From: Anam Navied <anam.naviyou@gmail.com> Date: Tue, 5 May 2026 14:29:02 -0400 Subject: [PATCH 359/378] Create PowerShell package for arm debian distribution (#26925) --- .pipelines/templates/linux-package-build.yml | 1 + .../release-validate-packagenames.yml | 2 +- .../stages/PowerShell-Packages-Stages.yml | 7 ++++ .../linux/package-validation.tests.ps1 | 33 ++++++++++--------- tools/packaging/packaging.psm1 | 22 +++++++++++-- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index bb7ed723f42..1487455107e 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -124,6 +124,7 @@ jobs: 'tar' { 'Signed-linux-x64', 'powershell*.tar.gz' } 'tar-alpine-fxdependent' { 'Signed-fxdependent-noopt-linux-musl-x64', 'powershell*.tar.gz' } 'deb' { 'Signed-linux-x64', 'powershell*.deb' } + 'deb-arm64' { 'Signed-linux-arm64', 'powershell*.deb' } 'rpm-fxdependent' { 'Signed-fxdependent-linux-x64', 'powershell*.rpm' } 'rpm-fxdependent-arm64' { 'Signed-fxdependent-linux-arm64', 'powershell*.rpm' } 'rpm' { 'Signed-linux-x64', 'powershell*.rpm' } diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 7271ffc05a8..5953366ffd7 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -109,7 +109,7 @@ jobs: - pwsh: | $message = @() Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.deb | ForEach-Object { - if($_.Name -notmatch 'powershell(-preview|-lts)?_\d+\.\d+\.\d+([\-~][a-z]*.\d+)?-\d\.deb_amd64\.deb') + if($_.Name -notmatch 'powershell(-preview|-lts)?_\d+\.\d+\.\d+([\-~][a-z]*.\d+)?-\d\.deb_(amd64|arm64)\.deb') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index b1efb2a8097..285a9035d0a 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -87,6 +87,13 @@ stages: packageType: deb jobName: deb + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm64' + signedDrop: 'drop_linux_sign_linux_arm64' + packageType: deb-arm64 + jobName: deb_arm64 + - template: /.pipelines/templates/linux-package-build.yml@self parameters: unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 index 594a729fa77..3b961120f2f 100644 --- a/test/packaging/linux/package-validation.tests.ps1 +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -9,20 +9,20 @@ Describe "Linux Package Name Validation" { } else { $env:SYSTEM_ARTIFACTSDIRECTORY } - + if (-not $artifactsDir) { throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set." } - + Write-Verbose "Artifacts directory: $artifactsDir" -Verbose } - + Context "RPM Package Names" { It "Should have valid RPM package names" { $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue - + $rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory" - + $invalidPackages = @() # Regex pattern for valid RPM package names. # Breakdown: @@ -42,25 +42,26 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid RPM package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "DEB Package Names" { It "Should have valid DEB package names" { $debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue - + $debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory" - + $invalidPackages = @() # Regex pattern for valid DEB package names. # Valid examples: # - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb # - powershell-lts_7.4.13-1.deb_amd64.deb # - powershell_7.4.13-1.deb_amd64.deb + # - powershell_7.6.0-1.deb_arm64.deb # Breakdown: # ^powershell : Starts with 'powershell' # (-preview|-lts)? : Optionally '-preview' or '-lts' @@ -78,19 +79,19 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid DEB package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "Tar.Gz Package Names" { It "Should have valid tar.gz package names" { $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue - + $tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory" - + $invalidPackages = @() foreach ($package in $tarPackages) { # Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz @@ -100,17 +101,17 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid tar.gz package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "Package Existence" { It "Should find at least one package in artifacts directory" { $allPackages = Get-ChildItem -Path $artifactsDir -Recurse -Include *.rpm, *.tar.gz, *.deb -ErrorAction SilentlyContinue - + $allPackages.Count | Should -BeGreaterThan 0 -Because "At least one package should exist in the artifacts directory" } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index a551a483c8d..085c2478cdc 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -52,7 +52,7 @@ function Start-PSPackage { [string]$Name = "powershell", # Ubuntu, CentOS, Fedora, macOS, and Windows packages are supported - [ValidateSet("msix", "deb", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] + [ValidateSet("msix", "deb", "deb-arm64", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] [string[]]$Type, # Generate windows downlevel package @@ -613,6 +613,24 @@ function Start-PSPackage { } } } + 'deb-arm64' { + $Arguments = @{ + Type = 'deb' + PackageSourcePath = $Source + Name = $Name + Version = $Version + Force = $Force + NoSudo = $NoSudo + LTS = $LTS + HostArchitecture = "arm64" + } + foreach ($Distro in $Script:DebianDistributions) { + $Arguments["Distribution"] = $Distro + if ($PSCmdlet.ShouldProcess("Create DEB Package for $Distro")) { + New-UnixPackage @Arguments + } + } + } 'rpm' { $Arguments = @{ Type = 'rpm' @@ -1032,7 +1050,7 @@ function New-UnixPackage { # This is a string because strings are appended to it [string]$Iteration = "1", - # Host architecture values allowed for deb type packages: amd64 + # Host architecture values allowed for deb type packages: amd64, arm64 # Host architecture values allowed for rpm type packages include: x86_64, aarch64, native, all, noarch, any # Host architecture values allowed for osxpkg type packages include: x86_64, arm64 [string] From 3d13188032c3784ecbf7a9cb6111aefe6bf7ba61 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:43:50 -0700 Subject: [PATCH 360/378] Fix executable permissions for pwsh and createdump The tarball staging path used `Copy-Item`, which on *nix doesn't preserve the source file mode, so `pwsh` ended up 644 in the `.tar.gz`. The Debian, RPM, and macOS PKG paths explicitly `chmod` everything to 644 and then bump `pwsh` back to 755, which silently demoted `createdump` (the .NET helper that produces crash minidumps) along with it. Now we `chmod 755` both executables in all package staging paths, guarded by `Test-Path` since fxdependent builds don't bundle `createdump`. Also added regression tests which check the permissions of `pwsh` inside the Linux and macOS tarballs before we upload them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/linux-package-build.yml | 7 ++++++ .pipelines/templates/mac-package-build.yml | 4 ++++ tools/packaging/packaging.psm1 | 24 +++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 1487455107e..56988523a8a 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -193,6 +193,13 @@ jobs: $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "pkgPath: $pkgPath" Copy-Item -Path $pkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + + if ($pkgPath -like '*.tar.gz') { + $entry = & tar -tzvf $pkgPath | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $pkgPath : $entry" + } + } displayName: 'Copy artifacts to output directory' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 154cb6c0257..416ee9f40cb 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -162,6 +162,10 @@ jobs: foreach($t in $tarPkgPath) { $file = $t.FullName + $entry = & tar -tzvf $file | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $file : $entry" + } Write-Verbose -verbose "Uploading $file to macos-pkgs" Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 085c2478cdc..e88e8f191aa 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -794,6 +794,18 @@ function New-TarballPackage { $Staging = "$PSScriptRoot/staging" New-StagingFolder -StagingPath $Staging -PackageSourcePath $PackageSourcePath -R2RVerification $R2RVerification + # Ensure PowerShell executable has correct permissions in tarball + $pwshInStaging = Join-Path $Staging 'pwsh' + if (Test-Path -LiteralPath $pwshInStaging) { + Start-NativeExecution { chmod 755 $pwshInStaging } + } + + # Included .NET executable for producing crash dumps + $createdumpInStaging = Join-Path $Staging 'createdump' + if (Test-Path -LiteralPath $createdumpInStaging) { + Start-NativeExecution { chmod 755 $createdumpInStaging } + } + if (Get-Command -Name tar -CommandType Application -ErrorAction Ignore) { if ($Force -or $PSCmdlet.ShouldProcess("Create tarball package")) { $options = "-czf" @@ -1212,7 +1224,11 @@ function New-UnixPackage { find $Staging -type f | xargs chmod 644 chmod 644 $ManGzipInfo.GzipFile # refers to executable, does not vary by channel - chmod 755 "$Staging/pwsh" #only the executable file should be granted the execution permission + chmod 755 "$Staging/pwsh" # only the executable file should be granted the execution permission + # Included .NET executable for producing crash dumps + if (Test-Path "$Staging/createdump") { + chmod 755 "$Staging/createdump" + } } } @@ -1892,6 +1908,12 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) Start-NativeExecution { chmod 755 $pwshPath } } + # Included .NET executable for producing crash dumps + $createdumpPath = "$targetPath/createdump" + if (Test-Path $createdumpPath) { + Start-NativeExecution { chmod 755 $createdumpPath } + } + # Calculate md5sums for all files in data directory (excluding symlinks) $md5sumsFile = Join-Path $debianDir "md5sums" $md5Content = "" From d49ade659720172dcb2276bd46d59df29585bea2 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:15:06 -0700 Subject: [PATCH 361/378] Move ESRP key codes into the `certificate_logical_to_actual` variable group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `CP-…` key codes used for ESRP signing are now set from ADO via the `certificate_logical_to_actual` variable group. The templates reference the following variables instead of literal codes: - `$(authenticode_cert_id)` - `$(authenticode_test_cert_id)` - `$(nuget_cert_id)` - `$(apple_cert_id)` - `$(pgp_linux_cert_id)` - `$(pgp_release_cert_id)` `nupkg.yml`, `mac-package-build.yml`, and `linux-package-build.yml` pick up the new group import. `linux-package-build.yml` also now selects the PGP signing profile based on whether `jobName` starts with `mariner`, so `PowerShell-Packages-Stages.yml` no longer threads a `signingProfile` parameter in for the two Mariner jobs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/linux-package-build.yml | 14 +++++++++++--- .pipelines/templates/mac-package-build.yml | 6 ++++-- .pipelines/templates/mac.yml | 2 +- .pipelines/templates/nupkg.yml | 5 +++-- .pipelines/templates/shouldSign.yml | 6 +++--- .../stages/PowerShell-Packages-Stages.yml | 2 -- .pipelines/templates/windows-hosted-build.yml | 2 +- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 56988523a8a..0d8324f1e14 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -3,7 +3,6 @@ parameters: signedeDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb' - signingProfile: 'CP-450779-pgpdetached' jobs: - job: ${{ parameters.jobName }} @@ -20,6 +19,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -34,8 +34,16 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - - name: SigningProfile - value: ${{ parameters.signingProfile }} + # PGP signing profile selection: Mariner (Azure Linux) packages ship through + # a different distribution channel and must be signed with the Mariner release + # key; all other Linux packages use the standard PowerShell Linux key. Both + # key codes come from the `certificate_logical_to_actual` variable group. + - ${{ if startsWith(parameters.jobName, 'mariner') }}: + - name: SigningProfile + value: $(pgp_release_cert_id) + - ${{ else }}: + - name: SigningProfile + value: $(pgp_linux_cert_id) steps: - checkout: self diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 416ee9f40cb..89dab90aa04 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -22,6 +22,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -187,6 +188,7 @@ jobs: type: windows variables: + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -234,7 +236,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", @@ -253,7 +255,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppNotarize", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index b22149d5e46..cd492994617 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -168,7 +168,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index c296aadc242..043c0b1f75c 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -23,6 +23,7 @@ jobs: - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual steps: - checkout: self @@ -208,7 +209,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\nupkg' @@ -268,7 +269,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\globaltools' diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 551297f3aaa..f3701acbc97 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -6,11 +6,11 @@ parameters: steps: - powershell: | $shouldSign = $true - $authenticodeCert = 'CP-230012' - $msixCert = 'CP-230012' + $authenticodeCert = '$(authenticode_cert_id)' + $msixCert = '$(authenticode_cert_id)' if($env:IS_DAILY -eq 'true') { - $authenticodeCert = 'CP-460906' + $authenticodeCert = '$(authenticode_test_cert_id)' } if($env:SKIP_SIGNING -eq 'Yes') { diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index 285a9035d0a..399d242aa4b 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -100,7 +100,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' packageType: rpm-fxdependent #mariner-x64 jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -108,7 +107,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' packageType: rpm-fxdependent-arm64 #mariner-arm64 jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index a2933e90817..0f7c1f8fb2e 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -315,7 +315,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(ob_outputDirectory)\globaltool' condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) From 36673f6d463a7349e1dd412d87e961aa2cef587a Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 1 May 2026 13:56:07 -0700 Subject: [PATCH 362/378] Correct typo in package parameters It's been this way for a couple years which means we've been passing...something else? --- .pipelines/templates/linux-package-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 0d8324f1e14..e37d8555533 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -1,6 +1,6 @@ parameters: unsignedDrop: 'drop_linux_build_linux_x64' - signedeDrop: 'drop_linux_sign_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb' From 11eb3744784f7c4d43e911a0853ddb20952fffce Mon Sep 17 00:00:00 2001 From: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> Date: Tue, 5 May 2026 21:56:48 +0200 Subject: [PATCH 363/378] Improve `Get-WinEvent -ListLog` exception handling (#27395) --- .../GetEventCommand.cs | 42 +++++++++++++------ .../resources/GetEventResources.resx | 6 +++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs index c7a07bab6ec..0ce68a31d73 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs @@ -518,9 +518,11 @@ private void ProcessListLog() || (wildLogPattern.IsMatch(logName))) { + EventLogConfiguration logObj; + EventLogInformation logInfoObj; try { - EventLogConfiguration logObj = new(logName, eventLogSession); + logObj = new EventLogConfiguration(logName, eventLogSession); // // Skip direct channels matching the wildcard unless -Force is present. @@ -533,19 +535,25 @@ private void ProcessListLog() continue; } - EventLogInformation logInfoObj = eventLogSession.GetLogInformation(logName, PathType.LogName); - - PSObject outputObj = new(logObj); + bMatchFound = true; + logInfoObj = eventLogSession.GetLogInformation(logName, PathType.LogName); + } + catch (UnauthorizedAccessException exc) + { + string exceptionMsg = string.Format(CultureInfo.InvariantCulture, GetEventResources.LogInfoNoAccess, logName); + var newExc = new UnauthorizedAccessException(exceptionMsg, exc); - outputObj.Properties.Add(new PSNoteProperty("FileSize", logInfoObj.FileSize)); - outputObj.Properties.Add(new PSNoteProperty("IsLogFull", logInfoObj.IsLogFull)); - outputObj.Properties.Add(new PSNoteProperty("LastAccessTime", logInfoObj.LastAccessTime)); - outputObj.Properties.Add(new PSNoteProperty("LastWriteTime", logInfoObj.LastWriteTime)); - outputObj.Properties.Add(new PSNoteProperty("OldestRecordNumber", logInfoObj.OldestRecordNumber)); - outputObj.Properties.Add(new PSNoteProperty("RecordCount", logInfoObj.RecordCount)); + string recommendationMsg = GetEventResources.SuggestElevation; + var eRecord = new ErrorRecord(newExc, "LogInfoNoAccess", ErrorCategory.PermissionDenied, logName) + { + ErrorDetails = new ErrorDetails(string.Empty) + { + RecommendedAction = recommendationMsg + } + }; - WriteObject(outputObj); - bMatchFound = true; + WriteError(eRecord); + continue; } catch (Exception exc) { @@ -556,6 +564,16 @@ private void ProcessListLog() WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null)); continue; } + + PSObject outputObj = new(logObj); + outputObj.Properties.Add(new PSNoteProperty("FileSize", logInfoObj.FileSize)); + outputObj.Properties.Add(new PSNoteProperty("IsLogFull", logInfoObj.IsLogFull)); + outputObj.Properties.Add(new PSNoteProperty("LastAccessTime", logInfoObj.LastAccessTime)); + outputObj.Properties.Add(new PSNoteProperty("LastWriteTime", logInfoObj.LastWriteTime)); + outputObj.Properties.Add(new PSNoteProperty("OldestRecordNumber", logInfoObj.OldestRecordNumber)); + outputObj.Properties.Add(new PSNoteProperty("RecordCount", logInfoObj.RecordCount)); + + WriteObject(outputObj); } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx index f8f41ecc2f5..53bf9afe0e3 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx @@ -255,6 +255,12 @@ The defined template is following: <data name="LogInfoUnavailable" xml:space="preserve"> <value>To access the '{0}' log start PowerShell with elevated user rights. Error: {1}</value> </data> + <data name="LogInfoNoAccess" xml:space="preserve"> + <value>Access denied for log: '{0}'.</value> + </data> + <data name="SuggestElevation" xml:space="preserve"> + <value>Launch PowerShell with elevated user rights.</value> + </data> <data name="NoEventMessage" xml:space="preserve"> <value>Cannot retrieve event message text.</value> </data> From b4d5395e8964207b2c8a4d3e298e93584c34f14e Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 5 May 2026 13:28:14 -0700 Subject: [PATCH 364/378] Update the `MSIXBundle-VPack` pipeline to create VPack for both LTS and Stable channel packages (#27384) --- .pipelines/MSIXBundle-vPack-Official.yml | 199 +++++------------- .../templates/create-msixbundle-vpack.yml | 178 ++++++++++++++++ 2 files changed, 230 insertions(+), 147 deletions(-) create mode 100644 .pipelines/templates/create-msixbundle-vpack.yml diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 08edd0367bd..2461d3cd310 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -138,12 +138,6 @@ extends: if (-not $matched) { throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" } - - # Extract minor version and verify it's even (LTS versions only) - $minorVersion = [int]$Matches[1] - if($minorVersion % 2 -ne 0) { - throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" - } displayName: Stop any preview release env: ob_restore_phase: true @@ -270,7 +264,7 @@ extends: Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose if (-not (Test-Path $signedFilesPath\pwsh.exe)) { - throw "pwsh.exe not found in $signedFilesPath" + throw "pwsh.exe not found in $signedFilesPath" } Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose @@ -278,166 +272,77 @@ extends: Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" Get-PSOptions | Write-Verbose -Verbose - ## Generated packages are placed in the current directory by default. - Set-Location $repoRoot - Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS - - $msixPkgNameFilter = "PowerShell*.msix" - $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File - $msixPkgPath = $msixPkgFile.FullName - Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" - - $pkgDir = '$(ob_outputDirectory)\pkgs' - $null = New-Item -ItemType Directory -Path $pkgDir -Force - Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose - displayName: 'Build MSIX Package (Unsigned)' - - ### END OF Packaging ### - - - pwsh: | - Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse - displayName: 'List Unsigned Package' - - - stage: Pack_MSIXBundle_And_Sign - displayName: 'Pack and sign MSIXBundle' - dependsOn: [Build_MSIX_Package] - jobs: - - job: Bundle - pool: - type: windows - variables: - ArtifactPlatform: 'windows' - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_artifactBaseName: drop_pack_msixbundle - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell7.Store.app' - ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. - ob_createvpack_propsFile: false - ob_createvpack_provData: true - ob_createvpack_metadata: '$(Build.SourceVersion)' - ob_createvpack_versionAs: string - ob_createvpack_version: '$(Version)' - ob_createvpack_verbose: true - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. - env: - ob_restore_phase: true + $metadata = Get-Content "$repoRoot\tools\metadata.json" -Raw | ConvertFrom-Json + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: no + $publishLTS = $metadata.LTSRelease.PublishToChannels + $publishStable = $metadata.StableRelease.PublishToChannels - - template: /.pipelines/templates/shouldSign.yml@self + Write-Verbose -Verbose "Publish LTS: $publishLTS" + Write-Verbose -Verbose "Publish Stable: $publishStable" - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_x64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for x64 + if (-not $publishLTS -and -not $publishStable) { + throw "metadata.json indicates no channels to publish to." + } - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_arm64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for arm64 + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$publishLTS - # Finds the makeappx tool on the machine. - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(Version)' - $cmd = Get-Command makeappx.exe -ErrorAction Ignore - if ($cmd) { - Write-Verbose -Verbose 'makeappx available in PATH' - $exePath = $cmd.Source - } else { - $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | - Where-Object { $_.DirectoryName -match 'x64' } | - Select-Object -Last 1 - $exePath = $makeappx.FullName - Write-Verbose -Verbose "makeappx was found: $exePath" + if ($publishLTS -and $publishStable) { + $enabledChannels = "LTS,Stable" + Write-Verbose -Verbose "Publish to both LTS and Stable channels. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath } - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Find makeappx tool - retryCountOnTaskFailure: 1 - - pwsh: | - $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' - $null = New-Item -Path $sourceDir -ItemType Directory -Force + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -Recurse -File | ForEach-Object FullName + Write-Verbose -Verbose "Unsigned msix package(s): $msixPkgFile" - $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse - foreach ($msixFile in $msixFiles) { - $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose - } + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgFile -Destination $pkgDir -Force -Verbose - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - - $makeappx = '$(MakeAppxPath)' - $outputDir = "$sourceDir\output" - New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - if ($LASTEXITCODE -ne 0) { - throw "makeappx bundle failed with exit code $LASTEXITCODE" + if (-not $enabledChannels) { + $enabledChannels = $publishLTS ? 'LTS' : ($publishStable ? 'Stable' : 'None') } - Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 - $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + ## Create an output variable for the enabled channels so that downstream stages can use it. + $vstsCommandString = "vso[task.setvariable variable=EnabledChannels;isOutput=true]$enabledChannels" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - displayName: Create MsixBundle - retryCountOnTaskFailure: 1 + name: BuildMSIXPackage + displayName: 'Build MSIX Package (Unsigned)' - - task: onebranch.pipeline.signing@1 - displayName: Sign MsixBundle - inputs: - command: 'sign' - signing_profile: $(MSIXProfile) - files_to_sign: '**/*.msixbundle' - search_root: '$(BundleDir)' + ### END OF Packaging ### - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" - - $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName - if ($signature.Status -ne 'Valid') { - throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" - } + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - pwsh: | + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + Remove-Item -Path $signedFilesPath -Recurse -Force -Verbose + displayName: 'Remove Signed-$(Runtime) folder' - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] - Write-Verbose -Verbose "Uploaded Bundle:" - Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose - displayName: 'Stage msixbundle for VPack' + variables: + EnabledChannels: $[ stageDependencies.Build_MSIX_Package.Build.outputs['x64.BuildMSIXPackage.EnabledChannels'] ] - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 200 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + jobs: + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'LTS' + createVPack: ${{ parameters.createVPack }} + + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'Stable' + createVPack: ${{ parameters.createVPack }} - stage: Publish_Symbols displayName: 'Publish Symbols' diff --git a/.pipelines/templates/create-msixbundle-vpack.yml b/.pipelines/templates/create-msixbundle-vpack.yml new file mode 100644 index 00000000000..df46523675f --- /dev/null +++ b/.pipelines/templates/create-msixbundle-vpack.yml @@ -0,0 +1,178 @@ +parameters: + - name: Channel + type: string + - name: createVPack + type: boolean + +jobs: +- job: Bundle_${{ parameters.Channel }} + condition: contains(variables['EnabledChannels'], '${{ parameters.Channel }}') + pool: + type: windows + + variables: + ArtifactPlatform: 'windows' + Channel: ${{ parameters.Channel }} + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: 'drop_pack_$(Channel)' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_packagename: 'PowerShell7-$(Channel).Store.app' + ob_createvpack_owneralias: 'dongbow' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application ($(Channel))' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. + ob_createvpack_propsFile: false + ob_createvpack_provData: true + ob_createvpack_metadata: '$(Build.SourceVersion)' + ob_createvpack_versionAs: string + ob_createvpack_version: '$(Version)' + ob_createvpack_verbose: true + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $channel = '$(Channel)' + if ($channel -eq 'LTS') { + Write-Verbose -Verbose "LTS channel. Remove Stable MSIX packages" + $stablePkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -notlike '*-LTS-*.msix' } | ForEach-Object FullName + + if ($stablePkgs) { + Remove-Item -Path $stablePkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No Stable MSIX package was found." + } + } + else { + Write-Verbose -Verbose "Stable channel. Remove LTS MSIX packages" + $ltsPkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -like '*-LTS-*.msix' } | ForEach-Object FullName + + if ($ltsPkgs) { + Remove-Item -Path $ltsPkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No LTS MSIX package was found." + } + } + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $channel = '$(Channel)' + $targetFileName = if ($channel -eq 'LTS') { + 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + } else { + 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' + } + $targetPath = Join-Path '$(ob_outputDirectory)' $targetFileName + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack enabled: $(ob_createvpack_enabled)" -Verbose + Write-Verbose "VPack Name: $(ob_createvpack_packagename)" -Verbose + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version From faf1e0e4f49fb6a17fbb140a12aee25f46e5bdcb Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Tue, 5 May 2026 15:01:05 -0700 Subject: [PATCH 365/378] Update `Microsoft.PowerShell.Native` to the latest GA version (#27400) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index beec0c4a495..b16516c1b01 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -40,7 +40,7 @@ <PackageReference Include="System.Security.Permissions" Version="11.0.0-preview.3.26207.106" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> - <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0-rc.1" /> + <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0" /> <!-- Signing APIs --> <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> </ItemGroup> From e9b4d67e2bc218430ddf277e821010776df8bcc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 17:16:22 -0700 Subject: [PATCH 366/378] Bump github/codeql-action from 4.35.1 to 4.35.3 (#27394) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index bb90de8e264..71f222a6072 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 + uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 + uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 7b3711666aa..18d7bc7c445 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 + uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 with: sarif_file: results.sarif From 92e80a3950a4209c08bc00554e7556623575a3cb Mon Sep 17 00:00:00 2001 From: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> Date: Wed, 6 May 2026 19:11:06 +0200 Subject: [PATCH 367/378] Add missing resource strings for `Get-WinEvent` (#27397) --- .../resources/GetEventResources.resx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx index 53bf9afe0e3..5c66f2b9e94 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/resources/GetEventResources.resx @@ -291,4 +291,25 @@ The defined template is following: <data name="LogCountLimitExceeded" xml:space="preserve"> <value>Log count ({0}) is exceeded Windows Event Log API limit ({1}). Adjust filter to return less log names.</value> </data> + <data name="ListLogParamHelp" xml:space="preserve"> + <value>Specifies the event logs. Wildcards are permitted.</value> + </data> + <data name="GetLogParamHelp" xml:space="preserve"> + <value>Specifies the event logs that this cmdlet gets events from. Wildcards are permitted.</value> + </data> + <data name="ListProviderParamHelp" xml:space="preserve"> + <value>Specifies the event log providers that this cmdlet gets.</value> + </data> + <data name="GetProviderParamHelp" xml:space="preserve"> + <value>Specifies the event log providers from which this cmdlet gets events.</value> + </data> + <data name="PathParamHelp" xml:space="preserve"> + <value>Specifies the path to the event log files that this cmdlet gets events from.</value> + </data> + <data name="MaxEventsParamHelp" xml:space="preserve"> + <value>Specifies the maximum number of events that are returned.</value> + </data> + <data name="ComputerNameParamHelp" xml:space="preserve"> + <value>Specifies the name of the computer from which this cmdlet gets data.</value> + </data> </root> From 87ff80b151c8018cab271f96cd8fad385217ac91 Mon Sep 17 00:00:00 2001 From: Anam Navied <anam.naviyou@gmail.com> Date: Wed, 6 May 2026 16:28:52 -0400 Subject: [PATCH 368/378] Specify `linux-arm64` runtime if package type is `deb-arm64` in `packaging.psm1` (#27401) --- tools/packaging/packaging.psm1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index e88e8f191aa..39127804b17 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -121,6 +121,9 @@ function Start-PSPackage { elseif ($Type.Count -eq 1 -and $Type[0] -eq "tar-alpine-fxdependent") { New-PSOptions -Configuration "Release" -Runtime 'fxdependent-noopt-linux-musl-x64' -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } } + elseif ($Type.Count -eq 1 -and $Type[0] -eq "deb-arm64") { + New-PSOptions -Configuration "Release" -Runtime 'linux-arm64' -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } + } else { New-PSOptions -Configuration "Release" -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } } From 81fd5923a1222afe300058479aa08e3c2be83f5a Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 6 May 2026 22:05:48 +0100 Subject: [PATCH 369/378] Fix `IDE0049` in `System.Management.Automation` [Part 2] (#27378) --- src/System.Management.Automation/help/HelpCommentsParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/help/HelpCommentsParser.cs b/src/System.Management.Automation/help/HelpCommentsParser.cs index 36d0cb6450e..b4a21e04d69 100644 --- a/src/System.Management.Automation/help/HelpCommentsParser.cs +++ b/src/System.Management.Automation/help/HelpCommentsParser.cs @@ -951,7 +951,7 @@ internal static bool IsCommentHelpText(List<Token> commentBlock) var result = new List<Language.Token>(); // Any whitespace between the token and the first comment is allowed. - int nextMaxStartLine = Int32.MaxValue; + int nextMaxStartLine = int.MaxValue; for (int i = startIndex; i < tokens.Length; i++) { From 850d5387f6ff57686ee107dae7a22687695d01d6 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 6 May 2026 22:06:04 +0100 Subject: [PATCH 370/378] Fix `IDE0049` in `System.Management.Automation` [Part 3] (#27379) --- .../engine/parser/TypeResolver.cs | 8 ++++---- src/System.Management.Automation/engine/parser/ast.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/TypeResolver.cs b/src/System.Management.Automation/engine/parser/TypeResolver.cs index 72258a4f459..73d44e94fbe 100644 --- a/src/System.Management.Automation/engine/parser/TypeResolver.cs +++ b/src/System.Management.Automation/engine/parser/TypeResolver.cs @@ -745,7 +745,7 @@ internal static class CoreTypes { typeof(Guid), new[] { "guid" } }, { typeof(Hashtable), new[] { "hashtable" } }, { typeof(int), new[] { "int", "int32" } }, - { typeof(Int16), new[] { "short", "int16" } }, + { typeof(short), new[] { "short", "int16" } }, { typeof(long), new[] { "long", "int64" } }, { typeof(CimInstance), new[] { "ciminstance" } }, { typeof(CimClass), new[] { "cimclass" } }, @@ -778,9 +778,9 @@ internal static class CoreTypes { typeof(BigInteger), new[] { "bigint" } }, { typeof(SecureString), new[] { "securestring" } }, { typeof(TimeSpan), new[] { "timespan" } }, - { typeof(UInt16), new[] { "ushort", "uint16" } }, - { typeof(UInt32), new[] { "uint", "uint32" } }, - { typeof(UInt64), new[] { "ulong", "uint64" } }, + { typeof(ushort), new[] { "ushort", "uint16" } }, + { typeof(uint), new[] { "uint", "uint32" } }, + { typeof(ulong), new[] { "ulong", "uint64" } }, { typeof(Uri), new[] { "uri" } }, { typeof(ValidateCountAttribute), new[] { "ValidateCount" } }, { typeof(ValidateDriveAttribute), new[] { "ValidateDrive" } }, diff --git a/src/System.Management.Automation/engine/parser/ast.cs b/src/System.Management.Automation/engine/parser/ast.cs index 0325cf94aeb..ba5c48a2752 100644 --- a/src/System.Management.Automation/engine/parser/ast.cs +++ b/src/System.Management.Automation/engine/parser/ast.cs @@ -7939,7 +7939,7 @@ public override Ast Copy() /// <summary> /// The static type produced after the cast is normally the type named by <see cref="Type"/>, but in some cases - /// it may not be, in which, <see cref="Object"/> is assumed. + /// it may not be, in which, <see cref="object"/> is assumed. /// </summary> public override Type StaticType { From 1919ba8c472add85dc687ab3c32021cf234577af Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 7 May 2026 00:44:34 +0100 Subject: [PATCH 371/378] Fix `IDE0049` in `System.Management.Automation` [Part 4] (#27380) --- .../engine/remoting/client/RemotingProtocol2.cs | 4 ++-- .../engine/remoting/commands/InvokeCommandCommand.cs | 2 +- .../engine/remoting/commands/PSRemotingCmdlet.cs | 4 ++-- .../engine/remoting/commands/StartJob.cs | 2 +- .../engine/remoting/commands/WaitJob.cs | 2 +- .../engine/remoting/commands/getrunspacecommand.cs | 2 +- .../engine/remoting/common/RunspaceConnectionInfo.cs | 6 +++--- .../engine/remoting/common/fragmentor.cs | 6 +++--- .../engine/remoting/fanin/BaseTransportManager.cs | 12 ++++++------ .../engine/remoting/fanin/PriorityCollection.cs | 6 +++--- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/client/RemotingProtocol2.cs b/src/System.Management.Automation/engine/remoting/client/RemotingProtocol2.cs index 4c5aec933b4..441a3f62fed 100644 --- a/src/System.Management.Automation/engine/remoting/client/RemotingProtocol2.cs +++ b/src/System.Management.Automation/engine/remoting/client/RemotingProtocol2.cs @@ -1551,7 +1551,7 @@ private void HandleInputDataReady(object sender, EventArgs e) /// <param name="inputstream"></param> private void WriteInput(ObjectStreamBase inputstream) { - Collection<object> inputObjects = inputstream.ObjectReader.NonBlockingRead(Int32.MaxValue); + Collection<object> inputObjects = inputstream.ObjectReader.NonBlockingRead(int.MaxValue); foreach (object inputObject in inputObjects) { @@ -1562,7 +1562,7 @@ private void WriteInput(ObjectStreamBase inputstream) if (!inputstream.IsOpen) { // Write any data written after the NonBlockingRead call above. - inputObjects = inputstream.ObjectReader.NonBlockingRead(Int32.MaxValue); + inputObjects = inputstream.ObjectReader.NonBlockingRead(int.MaxValue); foreach (object inputObject in inputObjects) { diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs index 0dd769537c6..e340a1acbdb 100644 --- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs @@ -226,7 +226,7 @@ public override PSCredential Credential [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)] [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)] [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)] - [ValidateRange((int)1, (int)UInt16.MaxValue)] + [ValidateRange((int)1, (int)ushort.MaxValue)] public override int Port { get diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index 8a5df652470..ee06dc22130 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -606,7 +606,7 @@ public virtual PSCredential Credential /// </remarks> [Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)] [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)] - [ValidateRange((int)1, (int)UInt16.MaxValue)] + [ValidateRange((int)1, (int)ushort.MaxValue)] public virtual int Port { get; set; } /// <summary> @@ -4149,7 +4149,7 @@ internal static string ExtractMessage( try { // WinRM returns both signed and unsigned 32 bit string values. Convert to signed 32 bit integer. - Int64 eCode = Convert.ToInt64(errorCodeString, System.Globalization.NumberFormatInfo.InvariantInfo); + long eCode = Convert.ToInt64(errorCodeString, System.Globalization.NumberFormatInfo.InvariantInfo); unchecked { errorCode = (int)eCode; diff --git a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs index 05611d8c0ae..9913ec64ced 100644 --- a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs +++ b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs @@ -277,7 +277,7 @@ public override string ConfigurationName /// <summary> /// Overriding to suppress this parameter. /// </summary> - public override Int32 ThrottleLimit + public override int ThrottleLimit { get { diff --git a/src/System.Management.Automation/engine/remoting/commands/WaitJob.cs b/src/System.Management.Automation/engine/remoting/commands/WaitJob.cs index 3bbc4463fe8..6964a1154b5 100644 --- a/src/System.Management.Automation/engine/remoting/commands/WaitJob.cs +++ b/src/System.Management.Automation/engine/remoting/commands/WaitJob.cs @@ -46,7 +46,7 @@ public class WaitJobCommand : JobCmdletBase, IDisposable /// </summary> [Parameter] [Alias("TimeoutSec")] - [ValidateRange(-1, Int32.MaxValue)] + [ValidateRange(-1, int.MaxValue)] public int Timeout { get diff --git a/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs index fb6bf348aba..22af9adf9ff 100644 --- a/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs @@ -283,7 +283,7 @@ public string CertificateThumbprint /// </remarks> [Parameter(ParameterSetName = GetPSSessionCommand.ComputerNameParameterSet)] [Parameter(ParameterSetName = GetPSSessionCommand.ComputerInstanceIdParameterSet)] - [ValidateRange((int)1, (int)UInt16.MaxValue)] + [ValidateRange((int)1, (int)ushort.MaxValue)] public int Port { get; set; } /// <summary> diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 242bde2ac53..475dc705674 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -225,7 +225,7 @@ public int OpenTimeout // The timer constructor will throw an exception // for any value greater than Int32.MaxValue // hence this is the maximum possible limit - _openTimeout = Int32.MaxValue; + _openTimeout = int.MaxValue; } } } @@ -270,7 +270,7 @@ public int OpenTimeout /// The maximum allowed idle timeout duration (in ms) that can be set on a Runspace. This is a read-only property /// that is set once the Runspace is successfully created and opened. /// </summary> - public int MaxIdleTimeout { get; internal set; } = Int32.MaxValue; + public int MaxIdleTimeout { get; internal set; } = int.MaxValue; /// <summary> /// Populates session options from a PSSessionOption instance. @@ -2505,7 +2505,7 @@ private static string[] ParseArgv(ProcessStartInfo psi) var argvList = new List<string>(); argvList.Add(psi.FileName); - var argsToParse = String.Join(' ', psi.ArgumentList).Trim(); + var argsToParse = string.Join(' ', psi.ArgumentList).Trim(); var argsLength = argsToParse.Length; for (int i = 0; i < argsLength; ) { diff --git a/src/System.Management.Automation/engine/remoting/common/fragmentor.cs b/src/System.Management.Automation/engine/remoting/common/fragmentor.cs index e0a82e46cf2..c451ba32f45 100644 --- a/src/System.Management.Automation/engine/remoting/common/fragmentor.cs +++ b/src/System.Management.Automation/engine/remoting/common/fragmentor.cs @@ -757,11 +757,11 @@ private void WriteCurrentFragmentAndReset() PSEtwLog.LogAnalyticVerbose( PSEventId.SentRemotingFragment, PSOpcode.Send, PSTask.None, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, - (Int64)(_currentFragment.ObjectId), - (Int64)(_currentFragment.FragmentId), + (long)(_currentFragment.ObjectId), + (long)(_currentFragment.FragmentId), _currentFragment.IsStartFragment ? 1 : 0, _currentFragment.IsEndFragment ? 1 : 0, - (UInt32)(_currentFragment.BlobLength), + (uint)(_currentFragment.BlobLength), new PSETWBinaryBlob(_currentFragment.Blob, 0, _currentFragment.BlobLength)); // finally write into memory stream diff --git a/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs index 0859a54965f..c3cf3b278aa 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/BaseTransportManager.cs @@ -213,7 +213,7 @@ public abstract class BaseTransportManager : IDisposable // This value instructs the server to use whatever setting it has for idle timeout. internal const int UseServerDefaultIdleTimeout = -1; - internal const uint UseServerDefaultIdleTimeoutUInt = UInt32.MaxValue; + internal const uint UseServerDefaultIdleTimeoutUInt = uint.MaxValue; // Minimum allowed idle timeout time is 60 seconds. internal const int MinimumIdleTimeout = 60 * 1000; @@ -390,9 +390,9 @@ internal void OnDataAvailableCallback(RemoteDataObject<PSObject> remoteObject) PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, remoteObject.RunspacePoolId.ToString(), remoteObject.PowerShellId.ToString(), - (UInt32)(remoteObject.Destination), - (UInt32)(remoteObject.DataType), - (UInt32)(remoteObject.TargetInterface)); + (uint)(remoteObject.Destination), + (uint)(remoteObject.DataType), + (uint)(remoteObject.TargetInterface)); // This might throw exceptions which the caller handles. PowerShellGuidObserver.SafeInvoke(remoteObject.PowerShellId, EventArgs.Empty); @@ -1414,8 +1414,8 @@ private void OnDataAvailable(byte[] dataToSend, bool isEndFragment) _runspacePoolInstanceId.ToString(), _powerShellInstanceId.ToString(), dataToSend.Length.ToString(CultureInfo.InvariantCulture), - (UInt32)_dataType, - (UInt32)_targetInterface); + (uint)_dataType, + (uint)_targetInterface); SendDataToClient(dataToSend, isEndFragment && _shouldFlushData, _reportAsPending, isEndFragment); } diff --git a/src/System.Management.Automation/engine/remoting/fanin/PriorityCollection.cs b/src/System.Management.Automation/engine/remoting/fanin/PriorityCollection.cs index 4d8535ca4a9..a0f38a78a07 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/PriorityCollection.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/PriorityCollection.cs @@ -561,11 +561,11 @@ internal void ProcessRawData(byte[] data, OnDataAvailableCallback callback) PSEtwLog.LogAnalyticVerbose( PSEventId.ReceivedRemotingFragment, PSOpcode.Receive, PSTask.None, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, - (Int64)objectId, - (Int64)fragmentId, + (long)objectId, + (long)fragmentId, sFlag ? 1 : 0, eFlag ? 1 : 0, - (UInt32)blobLength, + (uint)blobLength, new PSETWBinaryBlob(oneFragment, FragmentedRemoteObject.HeaderLength, blobLength)); byte[] extraData = null; From f14d8611ba80f7c29409c0824f5651096a734b83 Mon Sep 17 00:00:00 2001 From: Anam Navied <anam.naviyou@gmail.com> Date: Mon, 11 May 2026 13:16:22 -0400 Subject: [PATCH 372/378] Add Instruction to ensure Copyright header is present at start of script and module files (#27408) --- .../script-module-file-format.instructions.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/instructions/script-module-file-format.instructions.md diff --git a/.github/instructions/script-module-file-format.instructions.md b/.github/instructions/script-module-file-format.instructions.md new file mode 100644 index 00000000000..922e0d4aa31 --- /dev/null +++ b/.github/instructions/script-module-file-format.instructions.md @@ -0,0 +1,27 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# Script and Module File Format + +These instructions define required file-level formatting for PowerShell scripts and module files in this repository. + +## Copyright Header + +If a change adds a new `.ps1` file or `.psm1` file or touches an existing one, the file should start with the copyright and license header and have an empty line after it, as shown in the example below: + +```powershell +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +``` + +Do not place blank lines, comments, or code before this header. + +## Requirements + +- Add the copyright header when creating a new `.ps1` or `.psm1` file. +- Preserve the header when editing an existing `.ps1` or `.psm1` file. +- If an existing `.ps1` or `.psm1` file is missing the header, only modify that file to add the header if a change touches that file. Do not make a change to add the header if the file is not being modified. From 146c046878c1a34cd241df425c994193b4b15ade Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 11 May 2026 19:50:27 +0100 Subject: [PATCH 373/378] Remove eager initialization of `_startupScripts` to enable lazy thread-safe initialization (#25767) --- src/System.Management.Automation/engine/InitialSessionState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 62308282d17..a6d50f47443 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -2124,7 +2124,7 @@ public virtual HashSet<string> StartupScripts } } - private HashSet<string> _startupScripts = new HashSet<string>(); + private HashSet<string> _startupScripts; private readonly object _syncObject = new object(); From 7164700777df63b6f20e0cccc546a382792f4632 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Mon, 11 May 2026 11:55:07 -0700 Subject: [PATCH 374/378] Update `README.md` to call out `PowerShell.Core.Instrumentation` needs to be in sync between `PowerShell` and `PowerShell-Native` repos (#27399) --- src/PowerShell.Core.Instrumentation/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PowerShell.Core.Instrumentation/README.md b/src/PowerShell.Core.Instrumentation/README.md index 65c8d19fbcb..4701116036b 100644 --- a/src/PowerShell.Core.Instrumentation/README.md +++ b/src/PowerShell.Core.Instrumentation/README.md @@ -1,5 +1,7 @@ # PowerShell.Core.Instrumentation -The code under `PowerShell.Core.Instrumentation` is being migrated to [PowerShell-native](https://github.com/PowerShell/PowerShell-native) repository. -Please make PRs to the new repository. -Code under here will be removed once the move is complete. \ No newline at end of file +The `PowerShell.Core.Instrumentation.man` has actually been migrated to [PowerShell-Native](https://github.com/PowerShell/PowerShell-Native/tree/master/src/PowerShell.Core.Instrumentation) repository. +The corresponding manifest resource DLL `PowerShell.Core.Instrumentation.dll` is now produced in the release build of `PowerShell-Native` and is shipped in the `Microsoft.PowerShell.Native` NuGet package. + +However, we still need to keep `PowerShell.Core.Instrumentation.man` in the PowerShell repository because the PowerShell packages for Windows ship the manifest file and `RegisterManifest.ps1` for users to register the manifest resource DLL if they want to. +Therefore, when making changes to `PowerShell.Core.Instrumentation.man`, make sure your changes are made to both repositories -- **this file needs to be kept in sync between those 2 repositories**. From c9ac205fda367148eb537fdfaf0be7d56f151d35 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Mon, 11 May 2026 11:59:37 -0700 Subject: [PATCH 375/378] Handle empty-string and null-value results returned from custom argument completer more properly (#27398) --- .../System.Management.Automation.csproj | 2 +- .../CommandCompletion/CompletionAnalysis.cs | 5 +- .../CommandCompletion/CompletionCompleters.cs | 47 ++++-- .../Host/TabCompletion/BugFix.Tests.ps1 | 146 ++++++++++++++++++ 4 files changed, 188 insertions(+), 12 deletions(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index b16516c1b01..f3e1d0dd9e8 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -42,7 +42,7 @@ <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0" /> <!-- Signing APIs --> - <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> + <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> </ItemGroup> <PropertyGroup> diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs index a6b6f4170b3..9c4a61a6833 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs @@ -601,7 +601,10 @@ internal List<CompletionResult> GetResults(PowerShell powerShell, out int replac completionContext.ExecutionContext.LanguageMode = PSLanguageMode.ConstrainedLanguage; } - return GetResultHelper(completionContext, out replacementIndex, out replacementLength); + List<CompletionResult> results = GetResultHelper(completionContext, out replacementIndex, out replacementLength); + CompletionCompleters.RemoveLastNullCompletionResult(results); + + return results; } finally { diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 73406e449bf..80cead788d3 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -2675,14 +2675,17 @@ private static bool InvokeScriptArgumentCompleter( scriptBlock, new object[] { commandName, parameterName, wordToComplete, commandAst, GetBoundArgumentsAsHashtable(context) }, resultList); - if (result) - { - resultList.Add(CompletionResult.Null); - } return result; } + /// <summary> + /// Invoke the custom argument completer and process its return values. + /// If we consider the completion successful, we add a null instance of the type 'CompletionResult' + /// to the end of the 'result' list to indicate that the argument completion has been processed, so we + /// will not go through the default argument completion even if the 'result' list is still empty. + /// </summary> + /// <returns>'true' if the argument completion was successful. 'false' otherwise.</returns> private static bool InvokeScriptArgumentCompleter( ScriptBlock scriptBlock, object[] argumentsToCompleter, @@ -2702,20 +2705,44 @@ private static bool InvokeScriptArgumentCompleter( return false; } + if (customResults.Count is 1 && customResults[0] is { BaseObject: "" } or null) + { + // If the script block returns a single empty string or a null value, we will treat it as if it has + // completed successfully but has no results to return. + // This allows a custom completer to suppress the default completions that we may fall back otherwise. + result.Add(CompletionResult.Null); + return true; + } + + int initialCount = result.Count; + foreach (var customResult in customResults) { - var resultAsCompletion = customResult.BaseObject as CompletionResult; - if (resultAsCompletion != null) + if (customResult is null) + { + continue; + } + + if (customResult.BaseObject is CompletionResult resultAsCompletion) { result.Add(resultAsCompletion); continue; } var resultAsString = customResult.ToString(); - result.Add(new CompletionResult(resultAsString)); + if (!string.IsNullOrEmpty(resultAsString)) + { + result.Add(new CompletionResult(resultAsString)); + } } - return true; + bool success = result.Count > initialCount; + if (success) + { + result.Add(CompletionResult.Null); + } + + return success; } // All the methods for native command argument completion will add a null instance of the type CompletionResult to the end of the @@ -2723,9 +2750,9 @@ private static bool InvokeScriptArgumentCompleter( // and has been processed already. So if the "result" list is still empty afterward, we will not go through the default argument completion anymore. #region Native Command Argument Completion - private static void RemoveLastNullCompletionResult(List<CompletionResult> result) + internal static void RemoveLastNullCompletionResult(List<CompletionResult> result) { - if (result.Count > 0 && result[result.Count - 1].Equals(CompletionResult.Null)) + if (result?.Count > 0 && result[^1].Equals(CompletionResult.Null)) { result.RemoveAt(result.Count - 1); } diff --git a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 index a7191d06e9b..2280d141ac3 100644 --- a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 @@ -149,4 +149,150 @@ Describe "Tab completion bug fix" -Tags "CI" { Pop-Location } } + + Context 'Native CLI argument completion' { + BeforeAll { + $testDir = Join-Path $TestDrive "TempTestDir" + $file1 = Join-Path $testDir "abc.ps1" + $file2 = Join-Path $testDir "def.py" + + New-Item -ItemType Directory -Path $testDir > $null + New-Item -ItemType File -Path $file1 > $null + New-Item -ItemType File -Path $file2 > $null + + $dirSep = [System.IO.Path]::DirectorySeparatorChar + $relative_name_abc = ".${dirSep}abc.ps1" + $relative_name_def = ".${dirSep}def.py" + } + + AfterAll { + ## Unregister the completer for 'ping' to avoid affecting other tests. + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock $null + } + + It 'Completer script block returning nothing should fall back to file name completion' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches | Should -Not -BeNullOrEmpty + $result.CompletionMatches.Count | Should -Be 2 + $result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc + $result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def + } finally { + Pop-Location + } + } + + It 'Completer script block returning $null should suppress default completion fallback' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return $null + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + ## This call should not throw, and should suppress the default file name completion fallback, returning no results. + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 0 + } finally { + Pop-Location + } + } + + It 'Completer script block returning empty string should suppress default completion fallback' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return '' + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + ## This call should not throw, and should suppress the default file name completion fallback, returning no results. + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 0 + } finally { + Pop-Location + } + } + + It 'Completer script block returning empty-string-only array should fall back to default completion' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return '', '' + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + ## This call should not throw, and should fall back to the default completion. + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 2 + $result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc + $result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def + } finally { + Pop-Location + } + } + + It 'Completer script block returning null-value-only array should fall back to default completion' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return $null, $null + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + ## This call should not throw, and should fall back to the default completion. + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 2 + $result.CompletionMatches[0].CompletionText | Should -BeExactly $relative_name_abc + $result.CompletionMatches[1].CompletionText | Should -BeExactly $relative_name_def + } finally { + Pop-Location + } + } + + It 'Completer script block returning a single string works as expected' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return 'hello' + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 1 + $result.CompletionMatches[0].CompletionText | Should -BeExactly "hello" + } finally { + Pop-Location + } + } + + It 'Completer script block returning an array that contains non-empty-or-null strings works as expected' { + register-ArgumentCompleter -Native -CommandName ping -ScriptBlock { + param($WordToComplete, $CommandAst, $CursorPosition) + return '', 'hello', $null, 'world' + } + + try { + Push-Location -Path $testDir + $cmd = "ping " + $result = TabExpansion2 -inputScript $cmd -cursorColumn $cmd.Length + $result.CompletionMatches.Count | Should -Be 2 + $result.CompletionMatches[0].CompletionText | Should -BeExactly "hello" + $result.CompletionMatches[1].CompletionText | Should -BeExactly "world" + } finally { + Pop-Location + } + } + } } From ebe59b2b6a26ffafaad3c023f4e022dd9886f8d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 15:25:46 -0700 Subject: [PATCH 376/378] Bump github/codeql-action from 4.35.3 to 4.35.4 (#27404) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 71f222a6072..3ef564eba90 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 + uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 + uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 18d7bc7c445..935c8ff93bb 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v3.29.5 + uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 with: sarif_file: results.sarif From 0a6ec9605c1f9a369d36c12873a4d80be7a9829e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 15:25:58 -0700 Subject: [PATCH 377/378] Bump actions/dependency-review-action from 4.9.0 to 5.0.0 (#27411) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 3b610326e44..84f0b03fa32 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 From 90d3b7f2e355e457d92b6929f6b4cfe4fa651e35 Mon Sep 17 00:00:00 2001 From: Steve Lee <slee@microsoft.com> Date: Wed, 13 May 2026 11:37:26 -0700 Subject: [PATCH 378/378] Add `appLicensing` capability to Appx manifest to allow it run without acquiring a Store license (#27412) --- assets/AppxManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/AppxManifest.xml b/assets/AppxManifest.xml index 50a8c7af45d..dfcd95935d9 100644 --- a/assets/AppxManifest.xml +++ b/assets/AppxManifest.xml @@ -43,6 +43,7 @@ <Capabilities> <Capability Name="internetClient" /> + <rescap:Capability Name="appLicensing" /> <rescap:Capability Name="runFullTrust" /> <rescap:Capability Name="unvirtualizedResources" /> <rescap:Capability Name="packageManagement" />