diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 3ef564eba90..8ace8be0742 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -41,13 +41,13 @@ jobs: with: fetch-depth: '0' - - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: global-json-file: ./global.json # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # 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@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v3.29.5 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 27ceac59bbd..3391afa0749 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@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index f89ce8caa83..141dffb6e89 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -172,7 +172,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: global-json-file: ./global.json - name: Bootstrap packaging @@ -231,7 +231,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 935c8ff93bb..7ac6df36ccb 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: SARIF file path: results.sarif @@ -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@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v3.29.5 + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 8d0255d4443..119e5c158f2 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -64,7 +64,7 @@ jobs: shell: pwsh - name: Setup .NET - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 with: global-json-file: ./global.json @@ -84,7 +84,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index c643917edd0..87c9dad9edc 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -28,7 +28,7 @@ jobs: fetch-depth: 1000 - name: Setup .NET - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: ${{ inputs.test_results_artifact_name }} diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 996991c22a0..420a96c3017 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -22,6 +22,26 @@ parameters: # parameters are shown up in ADO UI in a build queue time - R1 - Netlock default: "R1" +- name: IsEarlyAccess + type: boolean + default: false +- name: EarlyAccessFeed + displayName: Early Access Feed + type: string + default: 'net11' + values: + - 'net8' + - 'net9' + - 'net10' + - 'net11' +- name: DOTNET_RUNTIME_VERSION + displayName: Runtime version of early access build + type: string + default: ' ' +- name: DOTNET_SDK_VERSION + displayName: SDK version of early access build + type: string + default: ' ' name: msixbundle_vPack_$(Build.SourceBranchName)_Prod.True_Create.${{ parameters.createVPack }}_$(date:yyyyMMdd).$(rev:rr) @@ -48,9 +68,19 @@ variables: value: ${{ parameters.ReleaseTagVar }} - name: netiso value: ${{ parameters.netiso }} + - name: IsEarlyAccess + value: ${{ parameters.IsEarlyAccess }} + - name: EARLY_ACCESS_FEED + value: ${{ parameters.EarlyAccessFeed }} + - name: DOTNET_RUNTIME_VERSION + value: ${{ parameters.DOTNET_RUNTIME_VERSION }} + - name: DOTNET_SDK_VERSION + value: ${{ parameters.DOTNET_SDK_VERSION }} - group: certificate_logical_to_actual # used within signing task - group: MSIXSigningProfile - group: msixTools + - ${{ if eq(parameters.IsEarlyAccess, true) }}: + - group: DotNetPrivateBuildAccess - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv @@ -95,9 +125,33 @@ extends: tsaOptionsFile: .config/tsaoptions.json stages: + - stage: prep + displayName: 'Prepare early access .NET' + dependsOn: [] + jobs: + - ${{ if eq(parameters.IsEarlyAccess, true) }}: + - template: /.pipelines/templates/downloadDotnetEarlyAccess.yml@self + parameters: + DotnetRuntimeVersion: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DotnetSdkVersion: ${{ parameters.DOTNET_SDK_VERSION }} + - ${{ else }}: + - job: skip_download_dotnet_early_access + displayName: 'Skip early access .NET download' + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - pwsh: Write-Host 'IsEarlyAccess is false; skipping early access .NET download.' + - stage: Build_MSIX_Package displayName: 'Build and create MSIX packages' - dependsOn: [] + dependsOn: [prep] jobs: - job: Build pool: @@ -114,6 +168,10 @@ extends: ArtifactPlatform: 'windows' ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' ob_artifactBaseName: drop_build_$(Architecture) + IsEarlyAccess: ${{ parameters.IsEarlyAccess }} + EARLY_ACCESS_FEED: ${{ parameters.EarlyAccessFeed }} + DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} steps: - checkout: self @@ -210,6 +268,9 @@ extends: Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols folder' env: + ${{ if eq(parameters.IsEarlyAccess, true) }}: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + VSS_NUGET_EXTERNAL_FEED_ENDPOINTS: $(VSS_NUGET_EXTERNAL_FEED_ENDPOINTS) 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. diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 2ffa0b94513..353e2f6e854 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -13,6 +13,7 @@ parameters: - 'net8' - 'net9' - 'net10' + - 'net11' - name: ReleaseTagVar displayName: Release Tag type: string diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 29d209df7bb..aa42fb19dac 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -38,6 +38,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - 'net8' - 'net9' - 'net10' + - 'net11' - name: DOTNET_RUNTIME_VERSION displayName: Runtime version of early access build type: string diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index fb1c5af40e2..c2d71b7a633 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -36,6 +36,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - 'net8' - 'net9' - 'net10' + - 'net11' - name: IsEarlyAccess type: boolean default: false diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 6d41528af66..9fb94c4c208 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -40,6 +40,7 @@ parameters: - 'net8' - 'net9' - 'net10' + - 'net11' - name: DOTNET_RUNTIME_VERSION displayName: Runtime version of early access build type: string @@ -121,4 +122,3 @@ extends: DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} IsEarlyAccess: ${{ parameters.IsEarlyAccess }} - diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 7cade8188a0..d8223676e81 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -38,6 +38,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - 'net8' - 'net9' - 'net10' + - 'net11' - name: DOTNET_RUNTIME_VERSION displayName: Runtime version of early access build type: string @@ -120,4 +121,3 @@ extends: DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} - diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 0f403b6e7d3..10ad7f7677a 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -36,6 +36,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - 'net8' - 'net9' - 'net10' + - 'net11' - name: IsEarlyAccess type: boolean default: false diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 48d63a81e20..8afdf11eef6 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -29,6 +29,26 @@ parameters: # parameters are shown up in ADO UI in a build queue time - R1 - Netlock default: "R1" +- name: IsEarlyAccess + type: boolean + default: false +- name: EarlyAccessFeed + displayName: Early Access Feed + type: string + default: 'net11' + values: + - 'net8' + - 'net9' + - 'net10' + - 'net11' +- name: DOTNET_RUNTIME_VERSION + displayName: Runtime version of early access build + type: string + default: ' ' +- name: DOTNET_SDK_VERSION + displayName: SDK version of early access build + type: string + default: ' ' name: vPack_$(Build.SourceBranchName)_Prod_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) @@ -38,6 +58,10 @@ variables: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} netiso: ${{ parameters.netiso }} + IsEarlyAccess: ${{ parameters.IsEarlyAccess }} + EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} + DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} resources: repositories: @@ -85,3 +109,7 @@ extends: parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} + IsEarlyAccess: ${{ parameters.IsEarlyAccess }} + EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} + DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 629e8387a4f..63786ada233 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -15,6 +15,7 @@ parameters: - 'net8' - 'net9' - 'net10' + - 'net11' - name: DOTNET_RUNTIME_VERSION displayName: Runtime version of early access build type: string diff --git a/.pipelines/templates/insert-nuget-config-azfeed.yml b/.pipelines/templates/insert-nuget-config-azfeed.yml index b40b0872edf..e724acb8659 100644 --- a/.pipelines/templates/insert-nuget-config-azfeed.yml +++ b/.pipelines/templates/insert-nuget-config-azfeed.yml @@ -68,6 +68,7 @@ steps: 'net8' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-8-early-access/nuget/v3/index.json' } 'net9' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-9-early-access/nuget/v3/index.json' } 'net10' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-10-early-access/nuget/v3/index.json' } + 'net11' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-11-early-access/nuget/v3/index.json' } default { throw "Unknown early access feed URL: $earlyAccessFeed" } } $powerShellRepoUri = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell/nuget/v3/index.json' diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml index f0a253e5ccd..4d097aca3b7 100644 --- a/.pipelines/templates/release-validate-sdk.yml +++ b/.pipelines/templates/release-validate-sdk.yml @@ -99,6 +99,7 @@ jobs: 'net8' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-8-early-access/nuget/v3/index.json' } 'net9' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-9-early-access/nuget/v3/index.json' } 'net10' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-10-early-access/nuget/v3/index.json' } + 'net11' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-11-early-access/nuget/v3/index.json' } default { throw "Unknown early access feed URL: $earlyAccessFeed" } } } diff --git a/.pipelines/templates/stages/PowerShell-Release-Stages.yml b/.pipelines/templates/stages/PowerShell-Release-Stages.yml index d922b224b97..f48f9ea5321 100644 --- a/.pipelines/templates/stages/PowerShell-Release-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Release-Stages.yml @@ -71,6 +71,7 @@ stages: IsEarlyAccess: ${{ parameters.IsEarlyAccess }} DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} + EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} dotnetArch: 'osx-x64' - template: /.pipelines/templates/release-validate-sdk.yml@self @@ -82,6 +83,7 @@ stages: IsEarlyAccess: ${{ parameters.IsEarlyAccess }} DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} + EarlyAccessFeed: ${{ parameters.EarlyAccessFeed }} dotnetArch: 'linux-x64' - stage: gbltool diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml index 404936440f8..bf493192b81 100644 --- a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -3,9 +3,45 @@ parameters: type: boolean - name: vPackName type: string + - name: IsEarlyAccess + type: boolean + default: false + - name: EarlyAccessFeed + type: string + default: 'net11' + - name: DOTNET_RUNTIME_VERSION + type: string + default: ' ' + - name: DOTNET_SDK_VERSION + type: string + default: ' ' stages: +- stage: prep + displayName: 'Prepare early access .NET' + jobs: + - ${{ if eq(parameters.IsEarlyAccess, true) }}: + - template: /.pipelines/templates/downloadDotnetEarlyAccess.yml@self + parameters: + DotnetRuntimeVersion: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DotnetSdkVersion: ${{ parameters.DOTNET_SDK_VERSION }} + - ${{ else }}: + - job: skip_download_dotnet_early_access + displayName: 'Skip early access .NET download' + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - pwsh: Write-Host 'IsEarlyAccess is false; skipping early access .NET download.' + - stage: BuildStage + dependsOn: [prep] jobs: - job: BuildJob pool: @@ -41,6 +77,10 @@ stages: ob_createvpack_verbose: true ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' ob_createvpack_description: PowerShell $(architecture) $(version) + IsEarlyAccess: ${{ parameters.IsEarlyAccess }} + EARLY_ACCESS_FEED: ${{ parameters.EarlyAccessFeed }} + DOTNET_RUNTIME_VERSION: ${{ parameters.DOTNET_RUNTIME_VERSION }} + DOTNET_SDK_VERSION: ${{ parameters.DOTNET_SDK_VERSION }} # Some official-build adapters force the injected validator on despite templateContext. # Exclude this payload from that validator; it is validated below with the tools-only policy. ob_sdl_codeSignValidation_excludes: '-|**\*.ps1;-|**\*.psm1;-|**\*.ps1xml;-|**\*.psd1;-|**\*.exe;-|**\*.dll' @@ -147,13 +187,18 @@ stages: 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 + - ${{ if eq(parameters.IsEarlyAccess, true) }}: + - template: /.pipelines/templates/install-dotnet.yml@self + parameters: + architecture: win-x64 + - ${{ else }}: + - 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 @@ -204,6 +249,8 @@ stages: displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ${{ if eq(parameters.IsEarlyAccess, true) }}: + VSS_NUGET_EXTERNAL_FEED_ENDPOINTS: $(VSS_NUGET_EXTERNAL_FEED_ENDPOINTS) 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. diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml index d87334aef44..f61a41f40b8 100644 --- a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -9,6 +9,7 @@ parameters: - 'net8' - 'net9' - 'net10' + - 'net11' - name: ReleaseTagVar type: string default: 'fromBranch' diff --git a/.pipelines/templates/variables/PowerShell-Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml index a9849a14252..c4b26637dd9 100644 --- a/.pipelines/templates/variables/PowerShell-Packages-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml @@ -18,6 +18,7 @@ parameters: - 'net8' - 'net9' - 'net10' + - 'net11' - name: IsEarlyAccess type: boolean default: false diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml index 7f00a5e0e2a..ad5d5ed6095 100644 --- a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -8,6 +8,23 @@ parameters: - name: netiso type: string default: 'R1' + - name: IsEarlyAccess + type: boolean + default: false + - name: EarlyAccessFeed + type: string + default: 'net11' + values: + - 'net8' + - 'net9' + - 'net10' + - 'net11' + - name: DOTNET_RUNTIME_VERSION + type: string + default: ' ' + - name: DOTNET_SDK_VERSION + type: string + default: ' ' variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -30,6 +47,14 @@ variables: value: none - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} + - name: IsEarlyAccess + value: ${{ parameters.IsEarlyAccess }} + - name: EARLY_ACCESS_FEED + value: ${{ parameters.EarlyAccessFeed }} + - name: DOTNET_RUNTIME_VERSION + value: ${{ parameters.DOTNET_RUNTIME_VERSION }} + - name: DOTNET_SDK_VERSION + value: ${{ parameters.DOTNET_SDK_VERSION }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - group: DotNetPrivateBuildAccess diff --git a/build.psm1 b/build.psm1 index 1c9a602e5c1..bcf625e681e 100644 --- a/build.psm1 +++ b/build.psm1 @@ -959,6 +959,7 @@ function Switch-PSNugetConfig { 'net8' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-8-early-access/nuget/v3/index.json' } 'net9' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-9-early-access/nuget/v3/index.json' } 'net10' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-10-early-access/nuget/v3/index.json' } + 'net11' { 'https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-net-11-early-access/nuget/v3/index.json' } default { throw "Unknown early access feed URL: $earlyAccess" } } diff --git a/src/System.Management.Automation/resources/cs/PSConfigurationStrings.cs.resx b/src/System.Management.Automation/resources/cs/PSConfigurationStrings.cs.resx index 900b72e9fc1..3b9b822587c 100644 --- a/src/System.Management.Automation/resources/cs/PSConfigurationStrings.cs.resx +++ b/src/System.Management.Automation/resources/cs/PSConfigurationStrings.cs.resx @@ -120,4 +120,10 @@ PowerShell přestal fungovat kvůli problému se zabezpečením: Konfigurační soubor nejde přečíst: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/de/PSConfigurationStrings.de.resx b/src/System.Management.Automation/resources/de/PSConfigurationStrings.de.resx index 73dd8f23625..af7f81cc1e6 100644 --- a/src/System.Management.Automation/resources/de/PSConfigurationStrings.de.resx +++ b/src/System.Management.Automation/resources/de/PSConfigurationStrings.de.resx @@ -120,4 +120,10 @@ PowerShell funktioniert aufgrund eines Sicherheitsproblems nicht mehr: Die Konfigurationsdatei kann nicht gelesen werden: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/es/PSConfigurationStrings.es.resx b/src/System.Management.Automation/resources/es/PSConfigurationStrings.es.resx index 7c833695182..11845c0604a 100644 --- a/src/System.Management.Automation/resources/es/PSConfigurationStrings.es.resx +++ b/src/System.Management.Automation/resources/es/PSConfigurationStrings.es.resx @@ -120,4 +120,10 @@ PowerShell ha dejado de funcionar debido a un problema de seguridad: no se puede leer el archivo de configuración: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/fr/PSConfigurationStrings.fr.resx b/src/System.Management.Automation/resources/fr/PSConfigurationStrings.fr.resx index 30ee6c66a25..675c35d2797 100644 --- a/src/System.Management.Automation/resources/fr/PSConfigurationStrings.fr.resx +++ b/src/System.Management.Automation/resources/fr/PSConfigurationStrings.fr.resx @@ -120,4 +120,10 @@ PowerShell a cessé de fonctionner en raison d’un problème de sécurité : impossible de lire le fichier de configuration : {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/it/PSConfigurationStrings.it.resx b/src/System.Management.Automation/resources/it/PSConfigurationStrings.it.resx index dceea43e1d5..0ac300af31f 100644 --- a/src/System.Management.Automation/resources/it/PSConfigurationStrings.it.resx +++ b/src/System.Management.Automation/resources/it/PSConfigurationStrings.it.resx @@ -120,4 +120,10 @@ PowerShell ha smesso di funzionare a causa di un problema di sicurezza: non è possibile leggere il file di configurazione: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/ja/PSConfigurationStrings.ja.resx b/src/System.Management.Automation/resources/ja/PSConfigurationStrings.ja.resx index 15fd480ced2..8f1f04ca6aa 100644 --- a/src/System.Management.Automation/resources/ja/PSConfigurationStrings.ja.resx +++ b/src/System.Management.Automation/resources/ja/PSConfigurationStrings.ja.resx @@ -120,4 +120,10 @@ PowerShell はセキュリティ上の問題により動作を停止しました: 構成ファイル {0} を読み取れません + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/ko/PSConfigurationStrings.ko.resx b/src/System.Management.Automation/resources/ko/PSConfigurationStrings.ko.resx index 5cc6ae88f91..99e19d62223 100644 --- a/src/System.Management.Automation/resources/ko/PSConfigurationStrings.ko.resx +++ b/src/System.Management.Automation/resources/ko/PSConfigurationStrings.ko.resx @@ -120,4 +120,10 @@ 보안 문제로 인해 PowerShell이 작동을 중지했습니다. 구성 파일을 읽을 수 없습니다. {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/pl/PSConfigurationStrings.pl.resx b/src/System.Management.Automation/resources/pl/PSConfigurationStrings.pl.resx index e7b5611cdb7..97cbc5d2c5e 100644 --- a/src/System.Management.Automation/resources/pl/PSConfigurationStrings.pl.resx +++ b/src/System.Management.Automation/resources/pl/PSConfigurationStrings.pl.resx @@ -120,4 +120,10 @@ Program PowerShell przestał działać z powodu problemu z zabezpieczeniami: nie można odczytać pliku konfiguracji: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/pt-BR/PSConfigurationStrings.pt-BR.resx b/src/System.Management.Automation/resources/pt-BR/PSConfigurationStrings.pt-BR.resx index 45b469db758..2789312d804 100644 --- a/src/System.Management.Automation/resources/pt-BR/PSConfigurationStrings.pt-BR.resx +++ b/src/System.Management.Automation/resources/pt-BR/PSConfigurationStrings.pt-BR.resx @@ -120,4 +120,10 @@ PowerShell has stopped working because of a security issue: Cannot read the configuration file: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/ru/PSConfigurationStrings.ru.resx b/src/System.Management.Automation/resources/ru/PSConfigurationStrings.ru.resx index 93bdaf35be1..2bd071f89e4 100644 --- a/src/System.Management.Automation/resources/ru/PSConfigurationStrings.ru.resx +++ b/src/System.Management.Automation/resources/ru/PSConfigurationStrings.ru.resx @@ -120,4 +120,10 @@ Windows PowerShell перестал работать из-за проблемы безопасности: Не удается прочитать файл конфигурации: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/tr/PSConfigurationStrings.tr.resx b/src/System.Management.Automation/resources/tr/PSConfigurationStrings.tr.resx index 63176ae2286..dc9dd515352 100644 --- a/src/System.Management.Automation/resources/tr/PSConfigurationStrings.tr.resx +++ b/src/System.Management.Automation/resources/tr/PSConfigurationStrings.tr.resx @@ -120,4 +120,10 @@ PowerShell, bir güvenlik sorunu nedeniyle çalışmayı durdurdu: Yapılandırma dosyası okunamıyor: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/zh-Hans/PSConfigurationStrings.zh-Hans.resx b/src/System.Management.Automation/resources/zh-Hans/PSConfigurationStrings.zh-Hans.resx index bcff924d325..190d5dc53d3 100644 --- a/src/System.Management.Automation/resources/zh-Hans/PSConfigurationStrings.zh-Hans.resx +++ b/src/System.Management.Automation/resources/zh-Hans/PSConfigurationStrings.zh-Hans.resx @@ -120,4 +120,10 @@ 由于安全问题,PowerShell 已停止工作: 无法读取配置文件: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/resources/zh-Hant/PSConfigurationStrings.zh-Hant.resx b/src/System.Management.Automation/resources/zh-Hant/PSConfigurationStrings.zh-Hant.resx index 3cc5246e898..b5660495fee 100644 --- a/src/System.Management.Automation/resources/zh-Hant/PSConfigurationStrings.zh-Hant.resx +++ b/src/System.Management.Automation/resources/zh-Hant/PSConfigurationStrings.zh-Hant.resx @@ -120,4 +120,10 @@ PowerShell 已因安全性問題而停止運作: 無法讀取設定檔: {0} + + Cannot read the PowerShell configuration file '{0}': {1}. Falling back to default settings. + + + Cannot read setting '{0}' from PowerShell configuration file '{1}': {2}. Falling back to default for this setting. + \ No newline at end of file diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index fbb7f588283..79f73e3777d 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -1009,15 +1009,31 @@ private static Guid GetUniqueIdentifier() try { // CreateUniqueIdentifierAndFile shouldn't throw, but the mutex might - using var m = new Mutex(true, "CreateUniqueUserId"); - m.WaitOne(); + using var mutex = new Mutex(initiallyOwned: false, name: "CreateUniqueUserId"); + bool mutexAcquired = false; try { - return CreateUniqueIdentifierAndFile(s_uuidPath); + try + { + mutexAcquired = mutex.WaitOne(millisecondsTimeout: 200); + } + catch (AbandonedMutexException) + { + // WaitOne transfers ownership before throwing for an abandoned mutex. + mutexAcquired = true; + } + + if (mutexAcquired) + { + return CreateUniqueIdentifierAndFile(s_uuidPath); + } } finally { - m.ReleaseMutex(); + if (mutexAcquired) + { + mutex.ReleaseMutex(); + } } } catch (Exception) diff --git a/test/powershell/dsc/dsc.profileresource.Tests.ps1 b/test/powershell/dsc/dsc.profileresource.Tests.ps1 index cb357c7350b..4f89a8a1377 100644 --- a/test/powershell/dsc/dsc.profileresource.Tests.ps1 +++ b/test/powershell/dsc/dsc.profileresource.Tests.ps1 @@ -3,6 +3,13 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { BeforeAll { + + $isMsix = $pshome -like '*WindowsApps*' + if ($isMsix) { + Write-Verbose "Running in MSIX context. Marking tests as pending." -Verbose + return + } + $DSC_ROOT = $env:DSC_ROOT $skipCleanup = $false @@ -46,6 +53,10 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { return } + if ($isMsix) { + return + } + # Restore original profile $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost if (Test-Path "$TestDrive/currentuser-currenthost-profile.bak") { @@ -69,6 +80,12 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { } It 'DSC resource is located at $PSHome' { + + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $resourceFile = Join-Path -Path $PSHome -ChildPath 'pwsh.profile.resource.ps1' $resourceFile | Should -Exist @@ -77,16 +94,31 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { } It 'DSC resource can be found' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + (& $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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 @@ -98,18 +130,33 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { } It 'DSC resource can set current user all hosts profile' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $exportOutput = (& $dscExe config export --file $PSScriptRoot/psprofile_export.dsc.yaml -o json) | ConvertFrom-Json $exportOutput.resources | Should -HaveCount 4 @@ -123,6 +170,12 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdminOnWindows', 'RequireSudoOnUnix' { BeforeAll { + $isMsix = $pshome -like '*WindowsApps*' + if ($isMsix) { + Write-Verbose "Running in MSIX context. Marking tests as pending." -Verbose + return + } + $DSC_ROOT = $env:DSC_ROOT $skipCleanup = $false @@ -166,6 +219,10 @@ Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdm return } + if ($isMsix) { + return + } + $env:PATH = $originalPath $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost @@ -189,24 +246,44 @@ Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdm } It 'DSC resource can set all users all hosts profile' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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' { + if ($isMsix) { + Set-ItResult -Pending -Because "Running in MSIX context. Skipping test." + return + } + $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/engine/Basic/Telemetry.Tests.ps1 b/test/powershell/engine/Basic/Telemetry.Tests.ps1 index 0da08316a56..7b6b21885d5 100644 --- a/test/powershell/engine/Basic/Telemetry.Tests.ps1 +++ b/test/powershell/engine/Basic/Telemetry.Tests.ps1 @@ -65,6 +65,22 @@ Describe "Telemetry for shell startup" -Tag CI { $PWSH = (Get-Process -Id $PID).MainModule.FileName $telemetrySet = Test-Path -Path env:POWERSHELL_TELEMETRY_OPTOUT $SendingTelemetry = $env:POWERSHELL_TELEMETRY_OPTOUT + + function Invoke-TelemetryTestProcess { + param( + [Parameter(Mandatory)] + [string[]] $Argument + ) + + $startInfo = [System.Diagnostics.ProcessStartInfo]::new() + $startInfo.FileName = $PWSH + $startInfo.UseShellExecute = $false + foreach ($argumentValue in $Argument) { + $startInfo.ArgumentList.Add($argumentValue) + } + + return [System.Diagnostics.Process]::Start($startInfo) + } } AfterAll { @@ -108,6 +124,101 @@ Describe "Telemetry for shell startup" -Tag CI { $uuidPath | Should -Exist } + It "Should not block concurrent telemetry-enabled shell startup when the uuid file is missing" { + $env:POWERSHELL_TELEMETRY_OPTOUT = "no" + $holderReadyPath = Join-Path -Path $TestDrive -ChildPath "telemetry-holder.ready" + $holderStopPath = Join-Path -Path $TestDrive -ChildPath "telemetry-holder.stop" + $holderScriptPath = Join-Path -Path $TestDrive -ChildPath "telemetry-holder.ps1" + @' +param($ReadyPath, $StopPath) + +[void][Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry]::CanSendTelemetry +[System.IO.File]::WriteAllText($ReadyPath, "") +while (-not [System.IO.File]::Exists($StopPath)) { + Start-Sleep -Milliseconds 100 +} +'@ | Set-Content -LiteralPath $holderScriptPath + + $holderProcess = $null + $childProcess = $null + try { + $holderProcess = Invoke-TelemetryTestProcess -Argument @( + "-NoProfile", + "-File", + $holderScriptPath, + $holderReadyPath, + $holderStopPath + ) + + Wait-UntilTrue -sb { Test-Path -LiteralPath $holderReadyPath } -TimeoutInMilliseconds 15000 -IntervalInMilliseconds 100 | + Should -BeTrue + $uuidPath | Should -Exist + Remove-Item -LiteralPath $uuidPath + + $childProcess = Invoke-TelemetryTestProcess -Argument @("-NoProfile", "-Command", "exit") + $childProcess.WaitForExit(15000) | Should -BeTrue + $childProcess.ExitCode | Should -Be 0 + $uuidPath | Should -Exist + } + finally { + if ($childProcess -and -not $childProcess.HasExited) { + $childProcess.Kill($true) + $childProcess.WaitForExit() + } + + if ($childProcess) { + $childProcess.Dispose() + } + + [System.IO.File]::WriteAllText($holderStopPath, "") + if ($holderProcess -and -not $holderProcess.WaitForExit(5000)) { + $holderProcess.Kill($true) + $holderProcess.WaitForExit() + } + + if ($holderProcess) { + $holderProcess.Dispose() + } + } + } + + It "Should stop creating the uuid file when the telemetry mutex times out" { + $env:POWERSHELL_TELEMETRY_OPTOUT = "no" + $mutex = [System.Threading.Mutex]::new($false, "CreateUniqueUserId") + $mutexAcquired = $false + $childProcess = $null + try { + try { + $mutexAcquired = $mutex.WaitOne(5000) + } + catch [System.Threading.AbandonedMutexException] { + $mutexAcquired = $true + } + + $mutexAcquired | Should -BeTrue -Because "the test must own the mutex to force the child to time out" + $childProcess = Invoke-TelemetryTestProcess -Argument @("-NoProfile", "-Command", "exit") + $childProcess.WaitForExit(15000) | Should -BeTrue + $childProcess.ExitCode | Should -Be 0 + $uuidPath | Should -Not -Exist + } + finally { + if ($childProcess -and -not $childProcess.HasExited) { + $childProcess.Kill($true) + $childProcess.WaitForExit() + } + + if ($childProcess) { + $childProcess.Dispose() + } + + if ($mutexAcquired) { + $mutex.ReleaseMutex() + } + + $mutex.Dispose() + } + } + It "Should create a uuid file by default" { if ( Test-Path env:POWERSHELL_TELEMETRY_OPTOUT ) { Remove-Item -Path env:POWERSHELL_TELEMETRY_OPTOUT } & $PWSH -NoProfile -Command "exit"