diff --git a/.config/suppress.json b/.config/suppress.json new file mode 100644 index 00000000000..55e607b1b0c --- /dev/null +++ b/.config/suppress.json @@ -0,0 +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" + } + ] +} diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json new file mode 100644 index 00000000000..7552bd7226c --- /dev/null +++ b/.config/tsaoptions.json @@ -0,0 +1,11 @@ +{ + "instanceUrl": "https://msazure.visualstudio.com", + "projectName": "One", + "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core\\pwsh", + "notificationAliases": [ + "adityap@microsoft.com", + "dongbow@microsoft.com", + "pmeinecke@microsoft.com", + "tplunk@microsoft.com" + ] +} diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index af18c5ffe6f..417a83573c0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. #------------------------------------------------------------------------------------------------------------- -FROM mcr.microsoft.com/powershell/test-deps:ubuntu-18.04 +FROM mcr.microsoft.com/powershell/test-deps:ubuntu-18.04@sha256:20154a16708d4a92ebe81393361f27c7567e6553869e89dd6abdd198cc8ba309 # Avoid warnings by switching to noninteractive ENV DEBIAN_FRONTEND=noninteractive diff --git a/.devcontainer/fedora30/Dockerfile b/.devcontainer/fedora30/Dockerfile index ae8d15ebd54..f13fb087805 100644 --- a/.devcontainer/fedora30/Dockerfile +++ b/.devcontainer/fedora30/Dockerfile @@ -3,7 +3,7 @@ # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. #------------------------------------------------------------------------------------------------------------- -FROM mcr.microsoft.com/powershell:preview-fedora-30 +FROM mcr.microsoft.com/powershell:preview-fedora-30@sha256:f405d4d60f8d196532da75038c76c052084ef02121f8e2d3852080ff4a230a5a # Configure apt and install packages RUN dnf install -y git procps wget findutils \ diff --git a/.editorconfig b/.editorconfig index efe9133c8ff..d2ac76dc9cd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -49,6 +49,9 @@ indent_style = tab # Dotnet code style settings: [*.cs] +# Ignore xUnit analyzer rule "Do not use blocking task operations in test method" +dotnet_diagnostic.xUnit1031.severity = none + # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26e01101693..d4adcefefad 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,72 +6,60 @@ # Area: Performance # @adityapatwardhan -# Area: Portability -# @JamesWTruher - # Area: Security -# @TravisEz13 @PaulHigin -src/System.Management.Automation/security/wldpNativeMethods.cs @TravisEz13 @PaulHigin - -# Area: Documentation -.github/ @joeyaiello @TravisEz13 +src/System.Management.Automation/security/wldpNativeMethods.cs @TravisEz13 @seeminglyscience -# Area: Test -# @JamesWTruher @TravisEz13 @adityapatwardhan - -# Area: Cmdlets Core -# @JamesWTruher @SteveL-MSFT @anmenaga +# Area: CI Build +.github/workflows @PowerShell/powershell-maintainers +.github/actions @PowerShell/powershell-maintainers # Now, areas that should have paths or filters, although we might not have them defined # According to the docs, order here must be by precedence of the filter, with later rules overwritting # but the feature seems to make taking a union of all the matching rules. # Area: Cmdlets Management -src/Microsoft.PowerShell.Commands.Management/ @daxian-dbw @adityapatwardhan +# src/Microsoft.PowerShell.Commands.Management/ @daxian-dbw @adityapatwardhan # Area: Utility Cmdlets -src/Microsoft.PowerShell.Commands.Utility/ @JamesWTruher @PaulHigin +# src/Microsoft.PowerShell.Commands.Utility/ # Area: Console -src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw @anmenaga @TylerLeonhardt - -# Area: Demos -demos/ @joeyaiello @SteveL-MSFT @HemantMahawar +# src/Microsoft.PowerShell.ConsoleHost/ @daxian-dbw # Area: DSC -src/System.Management.Automation/DscSupport @TravisEz13 @SteveL-MSFT +# src/System.Management.Automation/DscSupport @TravisEz13 @SteveL-MSFT # Area: Engine # src/System.Management.Automation/engine @daxian-dbw # Area: Debugging # Must be below engine to override -src/System.Management.Automation/engine/debugger/ @PaulHigin +# src/System.Management.Automation/engine/debugger/ # Area: Help -src/System.Management.Automation/help @adityapatwardhan +src/System.Management.Automation/help @adityapatwardhan @daxian-dbw # Area: Intellisense # @daxian-dbw # Area: Language -src/System.Management.Automation/engine/parser @daxian-dbw +src/System.Management.Automation/engine/parser @daxian-dbw @seeminglyscience # Area: Providers -src/System.Management.Automation/namespaces @anmenaga +# src/System.Management.Automation/namespaces # Area: Remoting -src/System.Management.Automation/engine/remoting @PaulHigin +src/System.Management.Automation/engine/remoting @daxian-dbw @TravisEz13 # Areas: Build # Must be last -*.config @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.props @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.yml @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -*.csproj @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -build.* @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -tools/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin -docker/ @daxian-dbw @TravisEz13 @adityapatwardhan @anmenaga @PaulHigin +*.config @PowerShell/powershell-maintainers +*.props @PowerShell/powershell-maintainers +*.yml @PowerShell/powershell-maintainers +*.csproj @PowerShell/powershell-maintainers +build.* @PowerShell/powershell-maintainers +tools/ @PowerShell/powershell-maintainers +# docker/ @PowerShell/powershell-maintainers # Area: Compliance tools/terms @TravisEz13 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6ad155756b5..27089847987 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,35 +11,21 @@ ## PR Checklist - [ ] [PR has a meaningful title](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - - Use the present tense and imperative mood when describing your changes + - Use the present tense and imperative mood when describing your changes - [ ] [Summarized changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - [ ] [Make sure all `.h`, `.cpp`, `.cs`, `.ps1` and `.psm1` files have the correct copyright header](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) -- [ ] This PR is ready to merge and is not [Work in Progress](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---work-in-progress). - - If the PR is work in progress, please add the prefix `WIP:` or `[ WIP ]` to the beginning of the title (the `WIP` bot will keep its status check at `Pending` while the prefix is present) and remove the prefix when the PR is ready. +- [ ] This PR is ready to merge. If this PR is a work in progress, please open this as a [Draft Pull Request and mark it as Ready to Review when it is ready to merge](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests). - **[Breaking changes](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#making-breaking-changes)** - - [ ] None - - **OR** - - [ ] [Experimental feature(s) needed](https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/7.3/Microsoft.PowerShell.Core/About/about_Experimental_Features.md) - - [ ] Experimental feature name(s): + - [ ] None + - **OR** + - [ ] [Experimental feature(s) needed](https://github.com/MicrosoftDocs/PowerShell-Docs/blob/main/reference/7.5/Microsoft.PowerShell.Core/About/about_Experimental_Features.md) + - [ ] Experimental feature name(s): - **User-facing changes** - - [ ] Not Applicable - - **OR** - - [ ] [Documentation needed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) - - [ ] Issue filed: + - [ ] Not Applicable + - **OR** + - [ ] [Documentation needed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---submission) + - [ ] Issue filed: - **Testing - New and feature** - - [ ] N/A or can only be tested interactively - - **OR** - - [ ] [Make sure you've added a new test if existing tests do not effectively test the code changed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#before-submitting) -- **Tooling** - - [ ] I have considered the user experience from a tooling perspective and don't believe tooling will be impacted. - - **OR** - - [ ] I have considered the user experience from a tooling perspective and opened an issue in the relevant tool repository. This may include: - - [ ] Impact on [PowerShell Editor Services](https://github.com/PowerShell/PowerShellEditorServices) which is used in the [PowerShell extension](https://github.com/PowerShell/vscode-powershell) for VSCode - (which runs in a different PS Host). - - [ ] Issue filed: - - [ ] Impact on Completions (both in the console and in editors) - one of PowerShell's most powerful features. - - [ ] Issue filed: - - [ ] Impact on [PSScriptAnalyzer](https://github.com/PowerShell/PSScriptAnalyzer) (which provides linting & formatting in the editor extensions). - - [ ] Issue filed: - - [ ] Impact on [EditorSyntax](https://github.com/PowerShell/EditorSyntax) (which provides syntax highlighting with in VSCode, GitHub, and many other editors). - - [ ] Issue filed: + - [ ] N/A or can only be tested interactively + - **OR** + - [ ] [Make sure you've added a new test if existing tests do not effectively test the code changed](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#before-submitting) diff --git a/.github/action-filters.yml b/.github/action-filters.yml new file mode 100644 index 00000000000..9a61bc1947b --- /dev/null +++ b/.github/action-filters.yml @@ -0,0 +1,23 @@ +github: &github + - .github/actions/** + - .github/workflows/**-ci.yml +tools: &tools + - tools/buildCommon/** + - tools/ci.psm1 +props: &props + - '**.props' +tests: &tests + - test/powershell/** + - test/tools/** + - test/xUnit/** +mainSource: &mainSource + - src/** +buildModule: &buildModule + - build.psm1 +source: + - *github + - *tools + - *props + - *buildModule + - *mainSource + - *tests diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml new file mode 100644 index 00000000000..79defa2205f --- /dev/null +++ b/.github/actions/build/ci/action.yml @@ -0,0 +1,54 @@ +name: CI Build +description: 'Builds PowerShell' +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: |- + Import-Module .\tools\ci.psm1 + Show-Environment + shell: pwsh + - name: Set Build Name for Non-PR + 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 + with: + global-json-file: ./global.json + - 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 + - name: Build + if: success() + run: |- + Write-Verbose -Verbose "Running Build..." + 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/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/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..de2952252d4 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -0,0 +1,110 @@ +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: "./.github/actions/infrastructure/get-changed-files" + with: + 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 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 + "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/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md new file mode 100644 index 00000000000..b53d6f99964 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -0,0 +1,86 @@ +# 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 + - **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 + +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..41c7d2ad941 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -0,0 +1,37 @@ +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 + # 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 + Test-MergeConflictMarker -File $changedFiles -WorkspacePath $env:GITHUB_WORKSPACE + +branding: + icon: 'alert-triangle' + color: 'red' diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml new file mode 100644 index 00000000000..656719262b2 --- /dev/null +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -0,0 +1,137 @@ +name: Path Filters +description: 'Path Filters' +inputs: + GITHUB_TOKEN: + description: 'GitHub token' + required: true +outputs: + source: + description: 'Source code changes (composite of all changes)' + value: ${{ steps.filter.outputs.source }} + githubChanged: + description: 'GitHub workflow changes' + value: ${{ steps.filter.outputs.githubChanged }} + toolsChanged: + description: 'Tools changes' + value: ${{ steps.filter.outputs.toolsChanged }} + propsChanged: + description: 'Props changes' + value: ${{ steps.filter.outputs.propsChanged }} + testsChanged: + description: 'Tests changes' + value: ${{ steps.filter.outputs.testsChanged }} + mainSourceChanged: + description: 'Main source code changes (any changes in src/)' + value: ${{ steps.filter.outputs.mainSourceChanged }} + buildModuleChanged: + description: 'Build module changes' + value: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: + description: 'Packaging related changes' + value: ${{ steps.filter.outputs.packagingChanged }} +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: | + console.log(`Event Name: ${context.eventName}`); + + // Just say everything changed if this is not a PR + if (context.eventName !== 'pull_request') { + console.log('Not a pull request, setting all outputs to true'); + core.setOutput('toolsChanged', true); + core.setOutput('githubChanged', true); + core.setOutput('propsChanged', true); + core.setOutput('testsChanged', true); + core.setOutput('mainSourceChanged', true); + core.setOutput('buildModuleChanged', true); + core.setOutput('source', true); + return; + } + + // 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 toolsChanged = toolsCiPsm1Changed || toolsBuildCommonChanged; + console.log(`→ Tools changed: ${toolsChanged}`); + + const propsChanged = files.some(file => file.endsWith('.props')); + console.log(`✓ Props files changed: ${propsChanged}`); + + 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.startsWith('src/')); + console.log(`✓ Main source (src/) changed: ${mainSourceChanged}`); + + const buildModuleChanged = files.some(file => file === 'build.psm1'); + console.log(`✓ build.psm1 changed: ${buildModuleChanged}`); + + 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 === '.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); + core.setOutput('propsChanged', propsChanged); + core.setOutput('testsChanged', testsChanged); + core.setOutput('mainSourceChanged', mainSourceChanged); + core.setOutput('buildModuleChanged', buildModuleChanged); + core.setOutput('globalConfigChanged', globalConfigChanged); + core.setOutput('packagingChanged', packagingChanged); + core.setOutput('source', source); diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml new file mode 100644 index 00000000000..acfce145420 --- /dev/null +++ b/.github/actions/test/linux-packaging/action.yml @@ -0,0 +1,118 @@ +name: linux_packaging +description: 'Linux packaging for PowerShell' + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment + shell: pwsh + + - uses: actions/setup-dotnet@v5 + 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 + shell: pwsh + + - 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 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 + 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 + 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: + 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/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml new file mode 100644 index 00000000000..ef943bfce78 --- /dev/null +++ b/.github/actions/test/nix/action.yml @@ -0,0 +1,110 @@ +name: nix_test +description: 'Test PowerShell on non-Windows platforms' + +inputs: + purpose: + required: false + default: '' + type: string + tagSet: + required: false + default: CI + type: string + ctrfFolder: + required: false + default: ctrf + type: string + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment + shell: pwsh + + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + + - name: Capture Artifacts Directory + continue-on-error: true + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Artifacts Directory' + Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + Write-LogGroupEnd -Title 'Artifacts Directory' + shell: pwsh + + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Bootstrap' + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Write-LogGroupEnd -Title 'Bootstrap' + + - 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 {} \; + shell: bash + + - name: Capture Extracted Build ZIP + continue-on-error: true + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Extracted Build ZIP' + Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + Write-LogGroupEnd -Title 'Extracted Build ZIP' + shell: pwsh + + - name: Test + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + $options = (Get-PSOptions) + $rootPath = '${{ github.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 + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -TitlePrefix '${{ inputs.buildName }}' -OutputFormat NUnitXml + shell: pwsh + + - 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" + ctrfFolder: "${{ inputs.ctrfFolder }}" diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml new file mode 100644 index 00000000000..27b94f6ebcb --- /dev/null +++ b/.github/actions/test/process-pester-results/action.yml @@ -0,0 +1,27 @@ +name: process-pester-test-results +description: 'Process Pester test results' + +inputs: + name: + required: true + default: '' + type: string + testResultsFolder: + required: false + default: "${{ runner.workspace }}/testResults" + type: string + +runs: + using: composite + steps: + - name: Log Summary + run: |- + & "$env:GITHUB_ACTION_PATH/process-pester-results.ps1" -Name '${{ inputs.name }}' -TestResultsFolder '${{ inputs.testResultsFolder }}' + shell: pwsh + + - name: Upload testResults artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: junit-pester-${{ inputs.name }} + path: ${{ runner.workspace }}/testResults diff --git a/.github/actions/test/process-pester-results/process-pester-results.ps1 b/.github/actions/test/process-pester-results/process-pester-results.ps1 new file mode 100644 index 00000000000..523de3bebaa --- /dev/null +++ b/.github/actions/test/process-pester-results/process-pester-results.ps1 @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +param( + [parameter(Mandatory)] + [string]$Name, + [parameter(Mandatory)] + [string]$TestResultsFolder +) + +Import-Module "$PSScriptRoot/../../../../build.psm1" + +if (-not $env:GITHUB_STEP_SUMMARY) { + Write-Error "GITHUB_STEP_SUMMARY is not set. Ensure this workflow is running in a GitHub Actions environment." + exit 1 +} + +$testCaseCount = 0 +$testErrorCount = 0 +$testFailureCount = 0 +$testNotRunCount = 0 +$testInconclusiveCount = 0 +$testIgnoredCount = 0 +$testSkippedCount = 0 +$testInvalidCount = 0 + +Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { + $results = [xml] (get-content $_.FullName) + + $testCaseCount += [int]$results.'test-results'.total + $testErrorCount += [int]$results.'test-results'.errors + $testFailureCount += [int]$results.'test-results'.failures + $testNotRunCount += [int]$results.'test-results'.'not-run' + $testInconclusiveCount += [int]$results.'test-results'.inconclusive + $testIgnoredCount += [int]$results.'test-results'.ignored + $testSkippedCount += [int]$results.'test-results'.skipped + $testInvalidCount += [int]$results.'test-results'.invalid +} + +@" + +# Summary of $Name + +- Total Tests: $testCaseCount +- Total Errors: $testErrorCount +- Total Failures: $testFailureCount +- Total Not Run: $testNotRunCount +- Total Inconclusive: $testInconclusiveCount +- Total Ignored: $testIgnoredCount +- Total Skipped: $testSkippedCount +- Total Invalid: $testInvalidCount + +"@ | Out-File -FilePath $ENV:GITHUB_STEP_SUMMARY -Append + +Write-Log "Summary written to $ENV:GITHUB_STEP_SUMMARY" + +Write-LogGroupStart -Title 'Test Results' +Get-Content $ENV:GITHUB_STEP_SUMMARY +Write-LogGroupEnd -Title 'Test Results' + +if ($testErrorCount -gt 0 -or $testFailureCount -gt 0) { + Write-Error "There were $testErrorCount/$testFailureCount errors/failures in the test results." + exit 1 +} +if ($testCaseCount -eq 0) { + Write-Error "No test cases were run." + exit 1 +} diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml new file mode 100644 index 00000000000..fccca27182f --- /dev/null +++ b/.github/actions/test/verify_xunit/action.yml @@ -0,0 +1,21 @@ +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/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml new file mode 100644 index 00000000000..3b3ce0cafe8 --- /dev/null +++ b/.github/actions/test/windows/action.yml @@ -0,0 +1,81 @@ +name: windows_test +description: 'Test PowerShell on Windows' + +inputs: + purpose: + required: false + default: '' + type: string + tagSet: + required: false + default: CI + type: string + ctrfFolder: + required: false + default: ctrf + type: string + +runs: + using: composite + steps: + - name: Capture Environment + if: success() || failure() + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment + shell: pwsh + + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: "${{ github.workspace }}" + + - name: Capture Artifacts Directory + continue-on-error: true + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Artifacts Directory' + Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + Write-LogGroupEnd -Title 'Artifacts Directory' + shell: pwsh + + - uses: actions/setup-dotnet@v4 + with: + global-json-file: .\global.json + + - name: Bootstrap + shell: powershell + run: |- + Import-Module ./build.psm1 + Write-LogGroupStart -Title 'Bootstrap' + 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 + Write-LogGroupEnd -Title 'Bootstrap' + + - name: Test + if: success() + run: |- + Import-Module .\build.psm1 -force + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '${{ github.workspace }}\build\psoptions.json' + $options = (Get-PSOptions) + $path = split-path -path $options.Output + $rootPath = split-Path -path $path + Expand-Archive -Path '${{ github.workspace }}\build\build.zip' -DestinationPath $rootPath -Force + Invoke-CITest -Purpose '${{ inputs.purpose }}' -TagSet '${{ inputs.tagSet }}' -OutputFormat NUnitXml + shell: pwsh + + - 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 + ctrfFolder: "${{ inputs.ctrfFolder }}" 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/dependabot.yml b/.github/dependabot.yml index 37c0fc6ca7c..7996891b5f7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -58,3 +58,10 @@ updates: interval: "daily" labels: - "CL-BuildPackaging" + + - package-ecosystem: docker + directory: / + schedule: + interval: daily + labels: + - "CL-BuildPackaging" diff --git a/.github/instructions/build-configuration-guide.instructions.md b/.github/instructions/build-configuration-guide.instructions.md new file mode 100644 index 00000000000..d0384f4f307 --- /dev/null +++ b/.github/instructions/build-configuration-guide.instructions.md @@ -0,0 +1,150 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" + - ".pipelines/**/*.yml" +--- + +# 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 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 +``` + +**Why Release:** +- Optimized binaries +- 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** + +```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 +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/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/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/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/.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/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/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/AssignPrs.yml b/.github/workflows/AssignPrs.yml deleted file mode 100644 index b2a7610d60c..00000000000 --- a/.github/workflows/AssignPrs.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Auto Assign PR Maintainer -on: - pull_request: - types: [opened, edited] -jobs: - run: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: wow-actions/auto-assign@v3 - 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/codeql-analysis.yml b/.github/workflows/analyze-reusable.yml similarity index 53% rename from .github/workflows/codeql-analysis.yml rename to .github/workflows/analyze-reusable.yml index a18163af84d..10b2f0893a3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/analyze-reusable.yml @@ -1,30 +1,30 @@ -name: "CodeQL" +name: CodeQL Analysis (Reusable) on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] + workflow_call: + inputs: + runner_os: + description: 'Runner OS for CodeQL analysis' + type: string + required: false + default: ubuntu-latest -defaults: - run: - shell: pwsh +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_SKIP_FIRST_TIME_EXPERIENCE: 1 - -permissions: - contents: read + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none jobs: 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 + runs-on: ${{ inputs.runner_os }} strategy: fail-fast: false @@ -37,13 +37,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + 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@v2 + 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. @@ -52,18 +56,22 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main - run: | - Get-ChildItem -Path env: + Import-Module .\tools\ci.psm1 + Show-Environment 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 + Invoke-CIBuild -Configuration 'StaticAnalysis' name: Build + shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 diff --git a/.github/workflows/createReminders.yml b/.github/workflows/createReminders.yml index 290141703d7..6acbda7661a 100644 --- a/.github/workflows/createReminders.yml +++ b/.github/workflows/createReminders.yml @@ -9,6 +9,8 @@ permissions: 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 @@ -16,4 +18,4 @@ jobs: steps: - name: check for reminder - uses: agrc/create-reminder-action@v1 + uses: agrc/create-reminder-action@922893a5705067719c4c4751843962f56aabf5eb # v1.1.13 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000000..a52521621b3 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,22 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - name: 'Dependency Review' + uses: actions/dependency-review-action@0efb1d1d84fc9633afcdaad14c485cbbc90ef46c # v2.5.1 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml new file mode 100644 index 00000000000..794ef64b213 --- /dev/null +++ b/.github/workflows/labels.yml @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +name: Verify PR Labels + +on: + pull_request: + types: [opened, reopened, edited, labeled, unlabeled, synchronize] + +permissions: + contents: read + pull-requests: read + +jobs: + verify-labels: + if: github.repository_owner == 'PowerShell' + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v2 + + - name: Verify PR has label starting with 'cl-' + id: verify-labels + uses: actions/github-script@v6 + with: + script: | + const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); + if (!labels.some(label => label.startsWith('cl-'))) { + core.setFailed("Every PR must have at least one label starting with 'cl-'."); + } diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml new file mode 100644 index 00000000000..4dd186316df --- /dev/null +++ b/.github/workflows/linux-ci.yml @@ -0,0 +1,274 @@ +name: Linux-CI + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +on: + workflow_dispatch: + + push: + branches: + - master + - release/** + - github-mirror + paths: + - "**" + - "!.github/ISSUE_TEMPLATE/**" + - "!.dependabot/config.yml" + - "!.pipelines/**" + - "!test/perf/**" + pull_request: + branches: + - master + - release/** + - github-mirror + - "*-feature" +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + FORCE_FEATURE: 'False' + FORCE_PACKAGE: 'False' + NUGET_KEY: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + system_debug: 'false' +jobs: + changes: + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' + name: Change Detection + runs-on: ubuntu-latest + # Required permissions + permissions: + pull-requests: read + contents: read + + # 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 + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Change Detection + id: filter + uses: "./.github/actions/infrastructure/path-filters" + 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 + needs: changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + + - name: Build + uses: "./.github/actions/build/ci" + linux_test_unelevated_ci: + name: Linux Unelevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Unelevated CI + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: CI + linux_test_elevated_ci: + name: Linux Elevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Elevated CI + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: CI + linux_test_unelevated_others: + name: Linux Unelevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Unelevated Others + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: Others + linux_test_elevated_others: + name: Linux Elevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Linux Elevated Others + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_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 + + 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 + # 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 + needs: + - verify_xunit + - linux_test_elevated_ci + - linux_test_elevated_others + - linux_test_unelevated_ci + - linux_test_unelevated_others + - analyze + - linux_packaging + - merge_conflict_check + - infrastructure_tests + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + with: + needs_context: ${{ toJson(needs) }} + linux_packaging: + name: Linux Packaging + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.packagingChanged == '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/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml new file mode 100644 index 00000000000..b4fc56cc32f --- /dev/null +++ b/.github/workflows/macos-ci.yml @@ -0,0 +1,247 @@ +name: macOS-CI + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +on: + push: + branches: + - master + - release/** + - github-mirror + paths: + - "**" + - "!.github/ISSUE_TEMPLATE/**" + - "!.dependabot/config.yml" + - "!.pipelines/**" + - "!test/perf/**" + pull_request: + branches: + - master + - release/** + - github-mirror + - "*-feature" +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + FORCE_FEATURE: 'False' + FORCE_PACKAGE: 'False' + HOMEBREW_NO_ANALYTICS: 1 + NUGET_KEY: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + system_debug: 'false' + +jobs: + changes: + name: Change Detection + runs-on: ubuntu-latest + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' + # Required permissions + permissions: + pull-requests: read + contents: read + + # 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@v4.1.0 + + - name: Change Detection + id: filter + uses: "./.github/actions/infrastructure/path-filters" + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ci_build: + name: Build PowerShell + runs-on: macos-latest + needs: changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Build + uses: "./.github/actions/build/ci" + macos_test_unelevated_ci: + name: macos Unelevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Unelevated CI + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: CI + macos_test_elevated_ci: + name: macOS Elevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Elevated CI + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: CI + macos_test_unelevated_others: + name: macOS Unelevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Unelevated Others + uses: "./.github/actions/test/nix" + with: + purpose: UnelevatedPesterTests + tagSet: Others + macos_test_elevated_others: + name: macOS Elevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: macOS Elevated Others + uses: "./.github/actions/test/nix" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_xunit" + PackageMac-macos_packaging: + name: macOS packaging and testing + needs: + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: + - macos-latest + 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() + 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: Install Pester + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + 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 = './test/packaging/macos/package-validation.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: + - verify_xunit + - PackageMac-macos_packaging + - macos_test_elevated_ci + - macos_test_elevated_others + - macos_test_unelevated_ci + - macos_test_unelevated_others + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + with: + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml index 9f66988fe95..4bf75e72095 100644 --- a/.github/workflows/markdownLink.yml +++ b/.github/workflows/markdownLink.yml @@ -2,7 +2,6 @@ on: pull_request: branches: - master - - 'release/**' name: Check modified markdown files permissions: @@ -11,9 +10,11 @@ permissions: jobs: markdown-link-check: runs-on: ubuntu-latest + if: github.repository_owner == 'PowerShell' + steps: - - uses: actions/checkout@v4 - - uses: gaurav-nelson/github-action-markdown-link-check@v1 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 with: use-quiet-mode: 'yes' use-verbose-mode: 'yes' @@ -26,16 +27,25 @@ jobs: statuses: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 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@v5 + uses: super-linter/super-linter@a8150b40c89574adb5f68bf9502b890a236a06b3 # v5.7.2 env: - VALIDATE_ALL_CODEBASE: false - DEFAULT_BRANCH: master - FILTER_REGEX_INCLUDE: .*\.md GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VALIDATE_EDITORCONFIG: false + - name: Super-Linter correction instructions + if: failure() + uses: actions/github-script@v7.0.1 + 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 index 557b801273d..48643e8a6ba 100644 --- a/.github/workflows/markdownLinkDaily.yml +++ b/.github/workflows/markdownLinkDaily.yml @@ -18,15 +18,15 @@ jobs: if: github.repository == 'PowerShell/PowerShell' steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check Links - uses: gaurav-nelson/github-action-markdown-link-check@v1 + 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@master + uses: skitionek/notify-microsoft-teams@77cc88b484449e2318245a54c115c5dca0eae4ef # master if: failure() with: webhook_url: ${{ secrets.PS_BUILD_TEAMS_CHANNEL }} diff --git a/.github/workflows/processReminders.yml b/.github/workflows/processReminders.yml index c660788a620..c47d830fd76 100644 --- a/.github/workflows/processReminders.yml +++ b/.github/workflows/processReminders.yml @@ -10,6 +10,7 @@ permissions: 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 @@ -17,4 +18,4 @@ jobs: steps: - name: check reminders and notify - uses: agrc/reminder-action@v1 + uses: agrc/reminder-action@e59091b4e9705a6108120cb50823108df35b5392 # v1.0.12 diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index faf5ddda535..00000000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This cannot rebase workflow changes into a PR -# It also only works if the GITHUB_TOKEN has permission to push to the branch -# see: https://github.com/cirrus-actions/rebase/issues/12#issuecomment-632594995 -on: - issue_comment: - types: [created] -name: Automatic Rebase -permissions: - contents: read - -jobs: - rebase: - permissions: - contents: write # for cirrus-actions/rebase to push code to rebase - pull-requests: write # for actions/github-script to create PR comment - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Post rebase started comment to pull request - uses: actions/github-script@v6 - continue-on-error: true - with: - script: | - const backport_start_body = `Started rebase: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${process.env.GITHUB_RUN_ID}`; - await github.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: backport_start_body - }); - - name: Automatic Rebase - uses: cirrus-actions/rebase@1.8 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 00000000000..1f5e9547a72 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,72 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["master"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + if: github.repository_owner == 'PowerShell' + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@99c53751e09b9529366343771cc321ec74e9bd3d # v2.0.6 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # 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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@f72882a05ba58122a44b17f2fce8fb50e5c79a59 # v2.25.0 + with: + sarif_file: results.sarif 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 diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml new file mode 100644 index 00000000000..0fe4af46051 --- /dev/null +++ b/.github/workflows/windows-ci.yml @@ -0,0 +1,193 @@ +name: Windows-CI +on: + workflow_dispatch: + push: + branches: + - master + - release/** + - github-mirror + paths: + - "**" + - "!.vsts-ci/misc-analysis.yml" + - "!.github/ISSUE_TEMPLATE/**" + - "!.dependabot/config.yml" + - "!test/perf/**" + - "!.pipelines/**" + pull_request: + branches: + - master + - release/** + - github-mirror + - "*-feature" + +# Path filters for PRs need to go into the changes job + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ contains(github.ref, 'merge')}} + +permissions: + contents: read + +run-name: "${{ github.ref_name }} - ${{ github.run_number }}" + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + NugetSecurityAnalysisWarningLevel: none + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts +jobs: + changes: + name: Change Detection + runs-on: ubuntu-latest + if: startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell' + # Required permissions + permissions: + pull-requests: read + contents: read + + # 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 + uses: actions/checkout@v4.1.0 + + - name: Change Detection + id: filter + uses: "./.github/actions/infrastructure/path-filters" + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ci_build: + name: Build PowerShell + needs: changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Build + uses: "./.github/actions/build/ci" + windows_test_unelevated_ci: + name: Windows Unelevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Unelevated CI + uses: "./.github/actions/test/windows" + with: + purpose: UnelevatedPesterTests + tagSet: CI + windows_test_elevated_ci: + name: Windows Elevated CI + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Elevated CI + uses: "./.github/actions/test/windows" + with: + purpose: ElevatedPesterTests + tagSet: CI + windows_test_unelevated_others: + name: Windows Unelevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Unelevated Others + uses: "./.github/actions/test/windows" + with: + purpose: UnelevatedPesterTests + tagSet: Others + windows_test_elevated_others: + name: Windows Elevated Others + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Windows Elevated Others + uses: "./.github/actions/test/windows" + with: + purpose: ElevatedPesterTests + tagSet: Others + verify_xunit: + name: Verify xUnit test results + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + runs-on: windows-latest + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + with: + fetch-depth: 1000 + - name: Verify xUnit test results + uses: "./.github/actions/test/verify_xunit" + analyze: + name: CodeQL Analysis + needs: changes + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == '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: + - changes + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} + uses: ./.github/workflows/windows-packaging-reusable.yml + ready_to_merge: + name: windows ready to merge + needs: + - verify_xunit + - windows_test_elevated_ci + - 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 + with: + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml new file mode 100644 index 00000000000..6b42a8899ec --- /dev/null +++ b/.github/workflows/windows-packaging-reusable.yml @@ -0,0 +1,89 @@ +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: | + Import-Module .\tools\ci.psm1 + Show-Environment + 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 diff --git a/.gitignore b/.gitignore index f8fac8a21bb..3bf9526015a 100644 --- a/.gitignore +++ b/.gitignore @@ -101,3 +101,19 @@ StartupProfileData-NonInteractive # Ignore logfiles logfile/* + +# Ignore nuget.config because it is dynamically generated +nuget.config + +# Ignore MSBuild Binary Logs +msbuild.binlog + +# Ignore gzip files in the manpage folder +assets/manpage/*.gz + +# Ignore files and folders generated by some gh cli extensions +tmp/* +.env.local + +# Ignore CTRF report files +crtf/* diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json b/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json new file mode 100644 index 00000000000..9ed971068cc --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/RolloutSpec.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutSpecification.json", + "contentVersion": "1.0.0.0", + "rolloutMetadata": { + "serviceModelPath": "ServiceModel.json", + "ScopeBindingsPath": "ScopeBindings.json", + "name": "OneBranch-Demo-Container-Deployment", + "rolloutType": "Major", + "buildSource": { + "parameters": { + "versionFile": "buildver.txt" + } + }, + "Notification": { + "Email": { + "To": "default" + } + } + }, + "orchestratedSteps": [ + { + "name": "UploadLinuxContainer", + "targetType": "ServiceResource", + "targetName": "LinuxContainerUpload", + "actions": ["Shell/Run"] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json b/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json new file mode 100644 index 00000000000..c3a98555867 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ScopeBindings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/scopeBindings.json", + "contentVersion": "0.0.0.1", + "scopeBindings": [ + { + "scopeTagName": "Global", + "bindings": [ + { + "find": "__SUBSCRIPTION_ID__", + "replaceWith": "$azureSubscriptionId()" + }, + { + "find": "__RESOURCE_GROUP__", + "replaceWith": "$azureResourceGroup()" + }, + { + "find": "__BUILD_VERSION__", + "replaceWith": "$buildVersion()" + } + ] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json new file mode 100644 index 00000000000..ce974fe69e5 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/ServiceModel.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/serviceModel.json", + "contentVersion": "1.0.0.0", + "serviceMetadata": { + "serviceGroup": "OneBranch-PowerShellDocker", + "environment": "Test" + }, + "serviceResourceGroupDefinitions": [ + { + "name": "OneBranch-PowerShellDocker-RGDef", + "serviceResourceDefinitions": [ + { + "name": "OneBranch-PowerShellDocker.Shell-SRDef", + "composedOf": { + "extension": { + "shell": [ + { + "type": "Run", + "properties": { + "imageName": "adm-azurelinux-30-l", + "imageVersion": "v2" + } + } + ] + } + } + } + ] + } + ], + "serviceResourceGroups": [ + { + "azureResourceGroupName": "default", + "location": "West US 3", + "instanceOf": "OneBranch-PowerShellDocker-RGDef", + "azureSubscriptionId": "default", + "scopeTags": [ + { + "name": "Global" + } + ], + "serviceResources": [ + { + "Name": "LinuxContainerUpload", + "InstanceOf": "OneBranch-PowerShellDocker.Shell-SRDef", + "RolloutParametersPath": "UploadLinux.Rollout.json" + } + ] + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 new file mode 100644 index 00000000000..23f91c1bff2 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -0,0 +1,397 @@ +<# +This function gets info from pmc's derived list of all repositories and from mapping.json (which contains info on just the repositories powershell publishes packages to, their package formats, etc) +to create a list of repositories PowerShell cares about along with repository Ids, repository full Urls and associated package that will be published to it. +#> +function Get-MappedRepositoryIds { + param( + [Parameter(Mandatory)] + [hashtable] + $Mapping, + + [Parameter(Mandatory)] + $RepoList, + + # LTS is not consider a package in this context. + # LTS is just another package name. + [Parameter(Mandatory)] + [ValidateSet('stable', 'preview')] + $Channel + ) + + $mappedReposUsedByPwsh = @() + foreach ($package in $Mapping.Packages) + { + Write-Verbose "package: $package" + $packageChannel = $package.channel + if (!$packageChannel) { + $packageChannel = 'all' + } + + Write-Verbose "package channel: $packageChannel" + if ($packageChannel -eq 'all' -or $packageChannel -eq $Channel) + { + $repoIds = [System.Collections.Generic.List[string]]::new() + $packageFormat = $package.PackageFormat + Write-Verbose "package format: $packageFormat" -Verbose + $extension = [System.io.path]::GetExtension($packageFormat) + $packageType = $extension -replace '^\.' + + if ($package.distribution.count -gt 1) { + throw "Package $($package | out-string) has more than one Distribution." + } + + foreach ($distribution in $package.distribution) + { + $urlGlob = $package.url + switch ($packageType) + { + 'deb' { + $urlGlob = $urlGlob + '-apt' + } + 'rpm' { + $urlGlob = $urlGlob + '-yum' + } + default { + throw "Unknown package type: $packageType" + } + } + + Write-Verbose "---Finding repo id for: $urlGlob---" -Verbose + $repos = $RepoList | Where-Object { $_.name -eq $urlGlob } + + if ($repos.id) { + Write-Verbose "Found repo id: $($repos.id)" -Verbose + $repoIds.AddRange(([string[]]$repos.id)) + } + else { + Write-Failure "Could not find repo for $urlGlob" + } + + if ($repoIds.Count -gt 0) { + $mappedReposUsedByPwsh += ($package + @{ "RepoId" = $repoIds.ToArray() }) + } + } + } + } + + Write-Verbose -Verbose "mapped repos length: $($mappedReposUsedByPwsh.Length)" + return $mappedReposUsedByPwsh +} + +<# +This function creates package objects for the packages to be published, +with the package name (ie package name format resolve with channel based PackageName and pwsh version), repoId, distribution and package path. +#> +function Get-PackageObjects() { + param( + [Parameter(Mandatory)] + [psobject[]] + $RepoObjects, + + [Parameter(Mandatory)] + [string] + $ReleaseVersion, + + [Parameter(Mandatory)] + [string[]] + $PackageName + ) + + $packages = @() + + foreach ($pkg in $RepoObjects) + { + if ($pkg.RepoId.count -gt 1) { + throw "Package $($pkg.name) has more than one repo id." + } + + if ($pkg.Distribution.count -gt 1) { + throw "Package $($pkg.name) has more than one Distribution." + } + + $pkgRepo = $pkg.RepoId | Select-Object -First 1 + $pkgDistribution = $pkg.Distribution | Select-Object -First 1 + + foreach ($name in $PackageName) { + $pkgName = $pkg.PackageFormat.Replace('PACKAGE_NAME', $name).Replace('POWERSHELL_RELEASE', $ReleaseVersion) + + if ($pkgName.EndsWith('.rpm')) { + $pkgName = $pkgName.Replace($ReleaseVersion, $ReleaseVersion.Replace('-', '_')) + } + + $packagePath = "$pwshPackagesFolder/$pkgName" + $packagePathExists = Test-Path -Path $packagePath + if (!$packagePathExists) + { + throw "package path $packagePath does not exist" + } + + Write-Verbose "Creating package info object for package '$pkgName' for repo '$pkgRepo'" + $packages += @{ + PackagePath = $packagePath + PackageName = $pkgName + RepoId = $pkgRepo + Distribution = $pkgDistribution + } + + Write-Verbose -Verbose "package info obj: Name: $pkgName RepoId: $pkgRepo Distribution: $pkgDistribution PackagePath: $packagePath" + } + } + + Write-Verbose -Verbose "count of packages objects: $($packages.Length)" + return $packages +} + +<# +This function stages, uploads and publishes the powershell packages to their associated repositories in PMC. +#> +function Publish-PackageToPMC() { + param( + [Parameter(Mandatory)] + [pscustomobject[]] + $PackageObject, + + [Parameter(Mandatory)] + [string] + $ConfigPath, + + [Parameter(Mandatory)] + [bool] + $SkipPublish + ) + + # Don't fail outright when an error occurs, but instead pool them until + # after attempting to publish every package. That way we can choose to + # proceed for a partial failure. + $errorMessage = [System.Collections.Generic.List[string]]::new() + foreach ($finalPackage in $PackageObject) + { + Write-Verbose "---Staging package: $($finalPackage.PackageName)---" -Verbose + $packagePath = $finalPackage.PackagePath + $pkgRepo = $finalPackage.RepoId + + $extension = [System.io.path]::GetExtension($packagePath) + $packageType = $extension -replace '^\.' + Write-Verbose "packageType: $packageType" -Verbose + + $packageListJson = pmc --config $ConfigPath package $packageType list --file $packagePath + $list = $packageListJson | ConvertFrom-Json + + $packageId = @() + if ($list.count -ne 0) + { + Write-Verbose "Package '$packagePath' already exists, skipping upload" -Verbose + $packageId = $list.results.id | Select-Object -First 1 + } + else { + # PMC UPLOAD COMMAND + Write-Verbose -Verbose "Uploading package, config: '$ConfigPath' package: '$packagePath'" + $uploadResult = $null + try { + $uploadResult = pmc --config $ConfigPath package upload $packagePath --type $packageType + } + catch { + $errorMessage.Add("Uploading package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $packageId = ($uploadResult | ConvertFrom-Json).id + } + + Write-Verbose "Got package ID: '$packageId'" -Verbose + $distribution = $finalPackage.Distribution | select-object -First 1 + Write-Verbose "distribution: $distribution" -Verbose + + if (!$SkipPublish) + { + Write-Verbose "---Publishing package: $($finalPackage.PackageName) to $pkgRepo---" -Verbose + + if (($packageType -ne 'rpm') -and ($packageType -ne 'deb')) + { + throw "Unsupported package type: $packageType" + return 1 + } + else { + # PMC UPDATE COMMAND + $rawUpdateResponse = $null + try { + if ($packageType -eq 'rpm') { + $rawUpdateResponse = pmc --config $ConfigPath repo package update $pkgRepo --add-packages $packageId + } elseif ($packageType -eq 'deb') { + $rawUpdateResponse = pmc --config $ConfigPath repo package update $pkgRepo $distribution --add-packages $packageId + } + } + catch { + $errorMessage.Add("Invoking update for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $state = ($rawUpdateResponse | ConvertFrom-Json).state + Write-Verbose -Verbose "update response state: $state" + if ($state -ne 'completed') { + $errorMessage.Add("Publishing package $($finalPackage.PackageName) to $pkgRepo failed: $rawUpdateResponse") + continue + } + } + + # PMC PUBLISH COMMAND + # The CLI outputs messages and JSON in the same stream, so we must sift through it for now + # This is planned to be fixed with a switch in a later release + Write-Verbose -Verbose ([pscustomobject]($package + @{ + PackageId = $packageId + })) + + # At this point, the changes are staged and will eventually be publish. + # Running publish, causes them to go live "immediately" + $rawPublishResponse = $null + try { + $rawPublishResponse = pmc --config $ConfigPath repo publish $pkgRepo + } + catch { + $errorMessage.Add("Invoking final publish for package $($finalPackage.PackageName) to $pkgRepo failed. See errors above for details.") + continue + } + + $publishState = ($rawPublishResponse | ConvertFrom-Json).state + Write-Verbose -Verbose "publish response state: $publishState" + if ($publishState -ne 'completed') { + $errorMessage.Add("Final publishing of package $($finalPackage.PackageName) to $pkgRepo failed: $rawPublishResponse") + continue + } + } else { + Write-Verbose -Verbose "Skipping Uploading package --config-file '$ConfigPath' package add '$packagePath' --repoID '$pkgRepo'" + } + } + + if ($errorMessage) { + throw $errorMessage -join [Environment]::NewLine + } +} + +if ($null -eq $env:MAPPING_FILE) +{ + Write-Verbose -Verbose "MAPPING_FILE variable didn't get passed correctly" + return 1 +} + +if ($null -eq $env:PWSH_PACKAGES_TARGZIP) +{ + Write-Verbose -Verbose "PWSH_PACKAGES_TARGZIP variable didn't get passed correctly" + return 1 +} + +if ($null -eq $env:PMC_METADATA) +{ + Write-Verbose -Verbose "PMC_METADATA variable didn't get passed correctly" + return 1 +} + +try { + Write-Verbose -Verbose "Downloading files" + Invoke-WebRequest -Uri $env:MAPPING_FILE -OutFile mapping.json + Invoke-WebRequest -Uri $env:PWSH_PACKAGES_TARGZIP -OutFile packages.tar.gz + Invoke-WebRequest -Uri $env:PMC_METADATA -OutFile pmcMetadata.json + + # create variables to those paths and test them + $mappingFilePath = Join-Path "/package/unarchive/" -ChildPath "mapping.json" + $mappingFilePathExists = Test-Path $mappingFilePath + if (!$mappingFilePathExists) + { + Write-Verbose -Verbose "mapping.json expected at $mappingFilePath does not exist" + return 1 + } + + $packagesTarPath = Join-Path -Path "/package/unarchive/" -ChildPath "packages.tar.gz" + $packagesTarPathExists = Test-Path $packagesTarPath + if (!$packagesTarPathExists) + { + Write-Verbose -Verbose "packages.tar.gz expected at $packagesTarPath does not exist" + return 1 + } + + # Extract files from 'packages.tar.gz' + Write-Verbose -Verbose "---Extracting files from packages.tar.gz---" + $pwshPackagesFolder = Join-Path -Path "/package/unarchive/" -ChildPath "packages" + New-Item -Path $pwshPackagesFolder -ItemType Directory + tar -xzvf $packagesTarPath -C $pwshPackagesFolder --force-local + Get-ChildItem $pwshPackagesFolder -Recurse + + $metadataFilePath = Join-Path -Path "/package/unarchive/" -ChildPath "pmcMetadata.json" + $metadataFilePathExists = Test-Path $metadataFilePath + if (!$metadataFilePathExists) + { + Write-Verbose -Verbose "pmcMetadata.json expected at $metadataFilePath does not exist" + return 1 + } + + # files in the extracted Run dir + $configPath = Join-Path '/package/unarchive/Run' -ChildPath 'settings.toml' + $configPathExists = Test-Path -Path $configPath + if (!$configPathExists) + { + Write-Verbose -Verbose "settings.toml expected at $configPath does not exist" + return 1 + } + + $pythonDlFolder = Join-Path '/package/unarchive/Run' -ChildPath 'python_dl' + $pyPathExists = Test-Path -Path $pythonDlFolder + if (!$pyPathExists) + { + Write-Verbose -Verbose "python_dl expected at $pythonDlFolder does not exist" + return 1 + } + + Write-Verbose -Verbose "Installing pmc-cli" + pip install --upgrade pip + pip --version --verbose + pip install /package/unarchive/Run/python_dl/*.whl + + # Get metadata + $channel = "" + $packageNames = @() + $metadataContent = Get-Content -Path $metadataFilePath | ConvertFrom-Json + $releaseVersion = $metadataContent.ReleaseTag.TrimStart('v') + $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') + } + else { + $channel = 'stable' + $packageNames = @('powershell') + } + + # Only add LTS package if not a rebuild branch + if ($lts -and -not $isRebuild) { + $packageNames += @('powershell-lts') + } + + Write-Verbose -Verbose "---Getting repository list---" + $rawResponse = pmc --config $configPath repo list --limit 800 + $response = $rawResponse | ConvertFrom-Json + $limit = $($response.limit) + $count = $($response.count) + Write-Verbose -Verbose "'pmc repo list' limit is: $limit and count is: $count" + $repoList = $response.results + + Write-Verbose -Verbose "---Getting package info---" + + + Write-Verbose "Reading mapping file from '$mappingFilePath'" -Verbose + $mapping = Get-Content -Raw -LiteralPath $mappingFilePath | ConvertFrom-Json -AsHashtable + $mappedReposUsedByPwsh = Get-MappedRepositoryIds -Mapping $mapping -RepoList $repoList -Channel $channel + $packageObjects = Get-PackageObjects -RepoObjects $mappedReposUsedByPwsh -PackageName $packageNames -ReleaseVersion $releaseVersion + Write-Verbose -Verbose "skip publish $skipPublish" + Publish-PackageToPMC -PackageObject $packageObjects -ConfigPath $configPath -SkipPublish $skipPublish +} +catch { + Write-Error -ErrorAction Stop $_.Exception.Message + return 1 +} + +return 0 diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json b/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json new file mode 100644 index 00000000000..d7c75c2e216 --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/UploadLinux.Rollout.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutParameters.json", + "contentVersion": "1.0.0.0", + "shellExtensions": [ + { + "name": "Run", + "type": "Run", + "properties": { + "maxExecutionTime": "PT2H" + }, + "package": { + "reference": { + "path": "Shell/Run.tar" + } + }, + "launch": { + "command": [ + "/bin/bash", + "-c", + "pwsh ./Run/Run.ps1" + ], + "environmentVariables": [ + { + "name": "MAPPING_FILE", + "reference": + { + "path": "Parameters\\mapping.json" + } + }, + { + "name": "PWSH_PACKAGES_TARGZIP", + "reference": + { + "path": "Parameters\\packages.tar.gz" + } + }, + { + "name": "PMC_METADATA", + "reference": + { + "path": "Parameters\\pmcMetadata.json" + } + } + ], + "identity": { + "type": "userAssigned", + "userAssignedIdentities": [ + "default" + ] + } + } + } + ] +} diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt b/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt new file mode 100644 index 00000000000..7dea76edb3d --- /dev/null +++ b/.pipelines/EV2Specs/ServiceGroupRoot/buildVer.txt @@ -0,0 +1 @@ +1.0.1 diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml new file mode 100644 index 00000000000..e0b5beaa255 --- /dev/null +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -0,0 +1,308 @@ +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: Skip Signing + type: string + default: 'NO' + - name: RUN_TEST_AND_RELEASE + displayName: Run Test and Release Artifacts Stage + type: boolean + default: true + - name: RUN_WINDOWS + displayName: Enable Windows Stage + type: boolean + default: true + - name: ENABLE_MSBUILD_BINLOGS + displayName: Enable MSBuild Binary Logs + type: boolean + default: false + - name: OfficialBuild + type: boolean + default: false + +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(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: + - 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 }} + - 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 + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + +extends: + template: ${{ variables.templateFile }} + parameters: + 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 + compiled: + ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: + enabled: true + ${{ else }}: + 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: + - 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'] + 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'] + 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/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml new file mode 100644 index 00000000000..18ef7b2d14c --- /dev/null +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -0,0 +1,309 @@ +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: OfficialBuild + type: boolean + default: false + - name: disableNetworkIsolation + type: boolean + default: false + +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(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: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} + +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-Official' + trigger: + branches: + include: + - master + - releases/* + + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: ${{ variables.templateFile }} + 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: + - 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/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml new file mode 100644 index 00000000000..f4c41143b5f --- /dev/null +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -0,0 +1,107 @@ +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: OfficialBuild + type: boolean + default: false + +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(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 + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-Official' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-Official' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: ${{ variables.templateFile }} + 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/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml new file mode 100644 index 00000000000..59d5dcf7547 --- /dev/null +++ b/.pipelines/PowerShell-Release-Official.yml @@ -0,0 +1,442 @@ +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: OfficialBuild + type: boolean + default: false + +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(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: 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: + - 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 Binaries-Official' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-Official' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: ${{ variables.templateFile }} + 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: + - 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: PSMMSUbuntu20.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 vPack Release pipeline + jobName: PublishVPack + instructions: | + Kick off vPack release 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 + 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 diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml new file mode 100644 index 00000000000..096dfb574a4 --- /dev/null +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -0,0 +1,341 @@ +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: 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)_Prod.${{ parameters.OfficialBuild }}_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/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 + - 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 + value: ${{ parameters.netiso }} +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: ${{ variables.templateFile }} + 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: + - 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/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml new file mode 100644 index 00000000000..af122fb2365 --- /dev/null +++ b/.pipelines/apiscan-gen-notice.yml @@ -0,0 +1,112 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +name: apiscan-genNotice-$(BUILD.SOURCEBRANCHNAME)-$(Build.BuildId) +trigger: none + +parameters: + - name: FORCE_CODEQL + 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. + # A PAT in the wrong org will give a single Error 203. No PAT will give a single Error 401, and individual pdbs may be missing even if permissions are correct. + - group: symbols + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + # Defines the variables AzureFileCopySubscription, StorageAccount, StorageAccountKey, StorageResourceGroup, StorageSubscriptionName + - group: 'Azure Blob variable group' + # Defines the variables CgPat, CgOrganization, and CgProject + - group: 'ComponentGovernance' + - group: 'PoolNames' + - name: LinuxContainerImage + 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') }}: + # Cadence is hours before CodeQL will allow a re-upload of the database + - name: CodeQL.Cadence + value: 0 + - name: CODEQL_ENABLED + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: true + ${{ else }}: + value: false + - name: Codeql.TSAEnabled + value: $(CODEQL_ENABLED) + # AnalyzeInPipeline: false = upload results + # AnalyzeInPipeline: true = do not upload results + - name: Codeql.AnalyzeInPipeline + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: false + ${{ else }}: + value: true + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@templates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + globalSdl: + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: $(CODEQL_ENABLED) # This enables TSA bug filing only for CodeQL 3000 + armory: + enabled: false + sbom: + enabled: false + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + tsa: + enabled: true # onebranch publish all SDL results to TSA. If TSA is disabled all SDL tools will forced into 'break' build mode. + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + 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: + enabled: true + softwareName: "PowerShell" # Default is repo name + versionNumber: "7.5" # 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. + + tsaOptionsFile: .config\tsaoptions.json + + stages: + - stage: APIScan + displayName: 'ApiScan' + dependsOn: [] + jobs: + - template: /.pipelines/templates/compliance/apiscan.yml@self + parameters: + parentJobs: [] + - stage: notice + displayName: Generate Notice File + dependsOn: [] + jobs: + - template: /.pipelines/templates/compliance/generateNotice.yml@self + parameters: + parentJobs: [] + SkipVerifyPackages: ${{ parameters.SkipVerifyPackages }} 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 00000000000..48e96378055 Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Error.png differ 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 00000000000..90420254a8e Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png differ 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 00000000000..f4084360d5c Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png differ 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 00000000000..3b8d6228485 Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png differ diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png new file mode 100644 index 00000000000..1fb9a6247c5 Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png differ 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 00000000000..a40d6fddfdc Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png differ diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png b/.pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png new file mode 100644 index 00000000000..2761a46a64f Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png differ 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 00000000000..c531f719c85 Binary files /dev/null and b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png differ diff --git a/.pipelines/store/PDP/PDP/en-US/PDP.xml b/.pipelines/store/PDP/PDP/en-US/PDP.xml new file mode 100644 index 00000000000..15d0bdf5270 --- /dev/null +++ b/.pipelines/store/PDP/PDP/en-US/PDP.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + 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..a52d60b045f --- /dev/null +++ b/.pipelines/store/SBConfig.json @@ -0,0 +1,69 @@ +{ + "helpUri": "https:\\\\aka.ms\\StoreBroker_Config", + "schemaVersion": 2, + "packageParameters": { + "PDPRootPath": "", + "Release": "", + "PDPInclude": [ + "PDP.xml" + ], + "PDPExclude": [], + "LanguageExclude": [ + "default", + "qps-ploc", + "qps-ploca", + "qps-plocm" + ], + "MediaRootPath": "", + "MediaFallbackLanguage": "en-US", + "PackagePath": [], + "OutPath": "", + "OutName": "", + "DisableAutoPackageNameFormatting": false + }, + "appSubmission": { + "productId": "", + "targetPublishMode": "Immediate", + "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/SetVersionVariables.yml b/.pipelines/templates/SetVersionVariables.yml new file mode 100644 index 00000000000..30ed1704022 --- /dev/null +++ b/.pipelines/templates/SetVersionVariables.yml @@ -0,0 +1,48 @@ +parameters: +- name: ReleaseTagVar + default: v6.2.0 +- name: ReleaseTagVarName + default: ReleaseTagVar +- name: CreateJson + default: 'no' +- name: ob_restore_phase + type: boolean + default: true + +steps: +- template: set-reporoot.yml@self + parameters: + ob_restore_phase: ${{ parameters.ob_restore_phase }} + +- powershell: | + $createJson = ("${{ parameters.CreateJson }}" -ne "no") + + $REPOROOT = $env:REPOROOT + + if (-not (Test-Path $REPOROOT/tools/releaseBuild/setReleaseTag.ps1)) { + if (Test-Path "$REPOROOT/PowerShell/tools/releaseBuild/setReleaseTag.ps1") { + $REPOROOT = "$REPOROOT/PowerShell" + } else { + throw "Could not find setReleaseTag.ps1 in $REPOROOT/tools/releaseBuild or $REPOROOT/PowerShell/tools/releaseBuild" + } + } + + $releaseTag = & "$REPOROOT/tools/releaseBuild/setReleaseTag.ps1" -ReleaseTag ${{ parameters.ReleaseTagVar }} -Variable "${{ parameters.ReleaseTagVarName }}" -CreateJson:$createJson + $version = $releaseTag.Substring(1) + $vstsCommandString = "vso[task.setvariable variable=Version]$version" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + $azureVersion = $releaseTag.ToLowerInvariant() -replace '\.', '-' + $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' + env: + 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: ${{ parameters.ob_restore_phase }} diff --git a/tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml b/.pipelines/templates/approvalJob.yml similarity index 96% rename from tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml rename to .pipelines/templates/approvalJob.yml index b34cc4c75b6..ac3b8bc2ab2 100644 --- a/tools/releaseBuild/azureDevOps/templates/release/approvalJob.yml +++ b/.pipelines/templates/approvalJob.yml @@ -24,7 +24,8 @@ jobs: - job: ${{ parameters.jobName }} dependsOn: ${{ parameters.dependsOnJob }} displayName: ${{ parameters.displayName }} - pool: server + pool: + type: agentless timeoutInMinutes: 4320 # job times out in 3 days steps: - task: ManualValidation@0 diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml new file mode 100644 index 00000000000..9dd0f3fb216 --- /dev/null +++ b/.pipelines/templates/channelSelection.yml @@ -0,0 +1,49 @@ +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 = $releaseTag -match '-' + + # 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 + 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/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml new file mode 100644 index 00000000000..3e383d2c572 --- /dev/null +++ b/.pipelines/templates/checkAzureContainer.yml @@ -0,0 +1,86 @@ +jobs: +- job: DeleteBlob + 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 + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + - 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: ob_sdl_codeql_compiled_enabled + value: false + + displayName: Delete blob is exists + pool: + type: windows + steps: + - checkout: self + clean: true + 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 + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + - pwsh: | + if (-not (Test-Path -Path $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json)) { + Get-ChildItem -Path $(Build.SourcesDirectory) -Recurse + throw 'tsaoptions.json not found' + } + displayName: 'Check tsaoptions.json' + + - pwsh: | + if (-not (Test-Path -Path $(Build.SourcesDirectory)\PowerShell\.config\suppress.json)) { + Get-ChildItem -Path $(Build.SourcesDirectory) -Recurse + throw 'suppress.json not found' + } + displayName: 'Check suppress.json' + + - task: AzurePowerShell@5 + displayName: Check if blob exists and delete if specified + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $containersToDelete = @('$(AzureVersion)', '$(AzureVersion)-private', '$(AzureVersion)-nuget', '$(AzureVersion)-gc') + + $containersToDelete | ForEach-Object { + $containerName = $_ + try { + $container = Get-AzStorageContainer -Container $containerName -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -ErrorAction Stop + if ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'false') { + throw "Azure blob container $containerName already exists. To overwrite, use ForceAzureBlobDelete parameter" + } + elseif ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'true') { + Write-Verbose -Verbose "Removing container $containerName due to ForceAzureBlobDelete parameter" + Remove-AzStorageContainer -Name $containerName -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -Force + } + } + catch { + if ($_.FullyQualifiedErrorId -eq 'ResourceNotFoundException,Microsoft.WindowsAzure.Commands.Storage.Blob.Cmdlet.GetAzureStorageContainerCommand') { + Write-Verbose -Verbose "Container $containerName does not exists." + } + else { + throw $_ + } + } + } + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/cloneToOfficialPath.yml b/.pipelines/templates/cloneToOfficialPath.yml new file mode 100644 index 00000000000..b060c713683 --- /dev/null +++ b/.pipelines/templates/cloneToOfficialPath.yml @@ -0,0 +1,31 @@ +parameters: +- name: nativePathRoot + default: '' +- name: ob_restore_phase + type: boolean + default: true + +steps: +- powershell: | + $dirSeparatorChar = [system.io.path]::DirectorySeparatorChar + $nativePath = "${{parameters.nativePathRoot }}${dirSeparatorChar}PowerShell" + Write-Host "##vso[task.setvariable variable=PowerShellRoot]$nativePath" + if ((Test-Path "$nativePath")) { + Remove-Item -Path "$nativePath" -Force -Recurse -Verbose -ErrorAction ignore + } + else { + Write-Verbose -Verbose -Message "No cleanup required." + } + # 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: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml new file mode 100644 index 00000000000..a07000c7067 --- /dev/null +++ b/.pipelines/templates/compliance/apiscan.yml @@ -0,0 +1,189 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +jobs: + - job: APIScan + variables: + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ReleaseTagVar + value: fromBranch + # Defines the variables APIScanClient, APIScanTenant and APIScanSecret + - group: PS-PS-APIScan + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - 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 + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: repoRoot + value: '$(Build.SourcesDirectory)\PowerShell' + - 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: Codeql.SourceRoot + value: $(repoRoot) + + pool: + type: windows + + # APIScan can take a long time + timeoutInMinutes: 180 + + steps: + - checkout: self + clean: true + fetchTags: true + fetchDepth: 1000 + displayName: Checkout PowerShell + retryCountOnTaskFailure: 1 + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: ../SetVersionVariables.yml + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: ../insert-nuget-config-azfeed.yml + parameters: + repoRoot: '$(repoRoot)' + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(Build.SourcesDirectory)" + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + dotnet tool install dotnet-symbol --tool-path $(Agent.ToolsDirectory)\tools\dotnet-symbol + $symbolToolPath = Get-ChildItem -Path $(Agent.ToolsDirectory)\tools\dotnet-symbol\dotnet-symbol.exe | Select-Object -First 1 -ExpandProperty FullName + Write-Host "##vso[task.setvariable variable=symbolToolPath]$symbolToolPath" + displayName: Install dotnet-symbol + 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') + inputs: + Language: csharp + + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + Start-PSBuild -Configuration StaticAnalysis -PSModuleRestore -Clean -Runtime fxdependent-win-desktop + + $OutputFolder = Split-Path (Get-PSOutput) + + Write-Verbose -Verbose -Message "Deleting ref folder from output folder" + if (Test-Path $OutputFolder/ref) { + Remove-Item -Recurse -Force $OutputFolder/ref + } + + Copy-Item -Path "$OutputFolder\*" -Destination '$(ob_outputDirectory)' -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 { + Write-Verbose -Verbose -Message "Deleting $($_.FullName)" + Remove-Item -Force -Verbose -Path $_.FullName + } + + # 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 { + Write-Verbose -Verbose -Message "Deleting $($_.FullName)" + Remove-Item -Force -Verbose -Path $_.FullName + } + + workingDirectory: '$(repoRoot)' + displayName: 'Remove unused runtimes' + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + displayName: 🔏 CodeQL 3000 Finalize + condition: eq(variables['CODEQL_ENABLED'], 'true') + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + workingDirectory: '$(repoRoot)' + displayName: Capture Environment + condition: succeededOrFailed() + + # Explicitly download symbols for the drop since the SDL image doesn't have http://SymWeb access and APIScan cannot handle https yet. + - pwsh: | + Import-Module .\build.psm1 -force + Find-DotNet + $pat = '$(SymbolServerPAT)' + if ($pat -like '*PAT*' -or $pat -eq '') + { + throw 'No PAT defined' + } + $url = 'https://microsoft.artifacts.visualstudio.com/defaultcollection/_apis/symbol/symsrv' + $(symbolToolPath) --authenticated-server-path $(SymbolServerPAT) $url --symbols -d "$env:ob_outputDirectory\*" --recurse-subdirectories + displayName: 'Download Symbols for binaries' + retryCountOnTaskFailure: 2 + workingDirectory: '$(repoRoot)' + + - pwsh: | + Get-ChildItem '$(ob_outputDirectory)' -File -Recurse | + Foreach-Object { + [pscustomobject]@{ + Path = $_.FullName + Version = $_.VersionInfo.FileVersion + Md5Hash = (Get-FileHash -Algorithm MD5 -Path $_.FullName).Hash + Sha512Hash = (Get-FileHash -Algorithm SHA512 -Path $_.FullName).Hash + } + } | Export-Csv -Path '$(Build.SourcesDirectory)/ReleaseFileHash.csv' + workingDirectory: '$(repoRoot)' + displayName: 'Create release file hash artifact' + + - pwsh: | + Copy-Item -Path '$(Build.SourcesDirectory)/ReleaseFileHash.csv' -Destination '$(ob_outputDirectory)' -Verbose + displayName: 'Publish Build File Hash artifact' + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture Environment + condition: succeededOrFailed() + workingDirectory: '$(repoRoot)' diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml new file mode 100644 index 00000000000..7de316e8b49 --- /dev/null +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -0,0 +1,121 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +parameters: + - name: parentJobs + type: jobList + - name: SkipVerifyPackages + type: boolean + +jobs: +- job: generateNotice + variables: + - name: runCodesignValidationInjection + value : false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/notice' + - name: ob_sdl_apiscan_enabled + value: false + - name: repoRoot + value: '$(Build.SourcesDirectory)\PowerShell' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + + displayName: Generate Notice + dependsOn: + ${{ parameters.parentJobs }} + pool: + type: windows + + timeoutInMinutes: 15 + + steps: + - checkout: self + clean: true + + - pwsh: | + [string]$Branch=$env:BUILD_SOURCEBRANCH + $branchOnly = $Branch -replace '^refs/heads/'; + $branchOnly = $branchOnly -replace '[_\-]' + + if ($branchOnly -eq 'master') { + $container = 'tpn' + } else { + $branchOnly = $branchOnly -replace '[\./]', '-' + $container = "tpn-$branchOnly" + } + + $vstsCommandString = "vso[task.setvariable variable=tpnContainer]$container" + Write-Verbose -Message $vstsCommandString -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Set ContainerName + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\tools' + + - 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: + outputfile: '$(ob_outputDirectory)\ThirdPartyNotices.txt' + # output format can be html or text + outputformat: text + # this isn't working + # additionaldata: $(Build.SourcesDirectory)\assets\additionalAttributions.txt + + - pwsh: | + Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt | Out-File '$(ob_outputDirectory)\ThirdPartyNotices.txt' -Encoding utf8NoBOM -Force -Append + Get-Content -Raw -Path $(repoRoot)\assets\additionalAttributions.txt + displayName: Append Additional Attributions + continueOnError: true + + - pwsh: | + Get-Content -Raw -Path '$(ob_outputDirectory)\ThirdPartyNotices.txt' + displayName: Capture Notice + continueOnError: true + + - task: AzurePowerShell@5 + displayName: Upload Notice + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + workingDirectory: '$(repoRoot)' + pwsh: true + inline: | + try { + $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' + $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' + $storageAccountName = "pscoretestdata" + $containerName = '$(tpnContainer)' + $blobName = 'ThirdPartyNotices.txt' + $noticePath = "$(ob_outputDirectory)\$blobName" + + Write-Verbose -Verbose "creating context ($storageAccountName) ..." + $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount + + Write-Verbose -Verbose "checking if container ($containerName) exists ..." + $containerExists = Get-AzStorageContainer -Name $containerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + Write-Verbose -Verbose "Creating container ..." + $null = New-AzStorageContainer -Name $containerName -Context $context + Write-Verbose -Verbose "Blob container $containerName created successfully." + } + + Write-Verbose -Verbose "Setting blob ($blobName) content ($noticePath) ..." + $null = Set-AzStorageBlobContent -File $noticePath -Container $containerName -Blob $blobName -Context $context -confirm:$false -force + Write-Verbose -Verbose "Done" + } catch { + Get-Error + throw + } diff --git a/.pipelines/templates/insert-nuget-config-azfeed.yml b/.pipelines/templates/insert-nuget-config-azfeed.yml new file mode 100644 index 00000000000..20057440c00 --- /dev/null +++ b/.pipelines/templates/insert-nuget-config-azfeed.yml @@ -0,0 +1,53 @@ +parameters: +- name: "repoRoot" + default: $(REPOROOT) +- name: "ob_restore_phase" + type: boolean + default: true + +steps: +- task: NuGetAuthenticate@1 + displayName: Install Azure Artifacts Credential Provider + inputs: + forceReinstallCredentialProvider: true + +- pwsh: | + try { + $configPath = "${env:NugetConfigDir}/nuget.config" + Import-Module ${{ parameters.repoRoot }}/build.psm1 -Force + + Write-Verbose -Verbose "Running: Switch-PSNugetConfig -Source Private -UserName '$(AzDevopsFeedUserNameKVPAT)' -ClearTextPAT '$(powershellPackageReadPat)'" + Switch-PSNugetConfig -Source Private -UserName '$(AzDevopsFeedUserNameKVPAT)' -ClearTextPAT '$(powershellPackageReadPat)' + + if(-not (Test-Path $configPath)) + { + throw "nuget.config is not created" + } + } + catch { + Get-Error + throw + } + displayName: 'Switch to production Azure DevOps feed for all nuget.configs' + condition: and(succeededOrFailed(), ne(variables['UseAzDevOpsFeed'], '')) + env: + NugetConfigDir: ${{ parameters.repoRoot }}/src/Modules + ob_restore_phase: ${{ parameters.ob_restore_phase }} + +- pwsh: | + Get-ChildItem ${{ parameters.repoRoot }}/nuget.config -Recurse | Foreach-Object { + Write-Verbose -Verbose "--- START $($_.fullname) ---" + get-content $_.fullname | Out-String -width 9999 -Stream | write-Verbose -Verbose + Write-Verbose -Verbose "--- END $($_.fullname) ---" + } + displayName: 'Capture all nuget.config files' + condition: and(succeededOrFailed(), ne(variables['UseAzDevOpsFeed'], '')) + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} + +- pwsh: | + Get-ChildItem -Path env:VSS* | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture VSS* Environment + condition: and(succeededOrFailed(), ne(variables['UseAzDevOpsFeed'], '')) + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml new file mode 100644 index 00000000000..464e13d1047 --- /dev/null +++ b/.pipelines/templates/install-dotnet.yml @@ -0,0 +1,24 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + +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: ${{ parameters.ob_restore_phase }} + diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml new file mode 100644 index 00000000000..3c94b476f90 --- /dev/null +++ b/.pipelines/templates/linux-package-build.yml @@ -0,0 +1,207 @@ +parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedeDrop: 'drop_linux_sign_linux_x64' + packageType: deb + jobName: 'deb' + signingProfile: 'CP-450779-pgpdetached' + +jobs: +- job: ${{ parameters.jobName }} + displayName: Package linux ${{ parameters.packageType }} + condition: succeeded() + pool: + type: linux + + variables: + - name: runCodesignValidationInjection + value: false + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: PackageType + value: ${{ parameters.packageType }} + - name: signedDrop + value: ${{ parameters.signedDrop }} + - name: unsignedDrop + value: ${{ parameters.unsignedDrop }} + - 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: SigningProfile + value: ${{ parameters.signingProfile }} + + 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 + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: shouldSign.yml + + - template: cloneToOfficialPath.yml + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + - template: rebuild-branch-check.yml@self + + - download: CoOrdinatedBuildPipeline + artifact: ${{ parameters.unsignedDrop }} + displayName: 'Download unsigned artifacts' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - download: CoOrdinatedBuildPipeline + artifact: ${{ parameters.signedDrop }} + displayName: 'Download signed artifacts' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - pwsh: | + Write-Verbose -Verbose "Unsigned artifacts" + Get-ChildItem "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${{ parameters.unsignedDrop }}" -Recurse + + Write-Verbose -Verbose "Signed artifacts" + Get-ChildItem "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${{ parameters.signedDrop }}" -Recurse + 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: | + $packageType = '$(PackageType)' + Write-Verbose -Verbose "packageType = $packageType" + + $signedDrop = '$(signedDrop)' + Write-Verbose -Verbose "signedDrop = $signedDrop" + + $unsignedDrop = '$(unsignedDrop)' + Write-Verbose -Verbose "unsignedDrop = $unsignedDrop" + + Write-Verbose -Message "Init..." -Verbose + + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot/build.psm1" + Import-Module "$repoRoot/tools/packaging" + + Start-PSBootstrap -Scenario Both + + $psOptionsPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${unsignedDrop}/psoptions/psoptions.json" + + if (-not (Test-Path $psOptionsPath)) { + throw "psOptionsPath file not found at $psOptionsPath" + } + + Restore-PSOptions $psOptionsPath + Write-Verbose -Message "Restoring PSOptions from $psOptionsPath" -Verbose + Get-PSOptions | Write-Verbose -Verbose + + $signedFolder, $pkgFilter = switch ($packageType) { + 'tar-arm' { 'Signed-linux-arm', 'powershell*.tar.gz' } + 'tar-arm64' { 'Signed-linux-arm64', 'powershell*.tar.gz' } + 'tar-alpine' { 'Signed-linux-musl-x64', 'powershell*.tar.gz' } + 'fxdependent' { 'Signed-fxdependent', 'powershell*.tar.gz' } + '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' } + 'rpm-fxdependent' { 'Signed-fxdependent-linux-x64', 'powershell*.rpm' } + 'rpm-fxdependent-arm64' { 'Signed-fxdependent-linux-arm64', 'powershell*.rpm' } + 'rpm' { 'Signed-linux-x64', 'powershell*.rpm' } + 'min-size' { 'Signed-linux-x64', 'powershell*.tar.gz' } + } + + $signedFilesPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/${signedDrop}/${signedFolder}" + Write-Verbose -Verbose "signedFilesPath: $signedFilesPath" + + Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose + if (-not (Test-Path "$signedFilesPath/pwsh")) { + throw "pwsh not found in $signedFilesPath" + } + + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json + + 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" + } + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + $packageType = '$(PackageType)' + Write-Verbose -Verbose "packageType = $packageType" + + 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" + displayName: 'Package ${{ parameters.packageType}}' + 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 deb and rpm packages + inputs: + command: 'sign' + signing_profile: '$(SigningProfile)' + files_to_sign: '**/*.rpm;**/*.deb' + search_root: '$(Pipeline.Workspace)' + + - pwsh: | + $pkgFilter = '$(PackageFilter)' + Write-Verbose -Verbose "pkgFilter: $pkgFilter" + + $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 + displayName: 'Copy artifacts to output directory' + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - pwsh: | + Get-ChildItem -Path $(ob_outputDirectory) -Recurse + displayName: 'List artifacts' diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml new file mode 100644 index 00000000000..cbf63c84b48 --- /dev/null +++ b/.pipelines/templates/linux.yml @@ -0,0 +1,199 @@ +parameters: + Runtime: 'linux-x64' + BuildConfiguration: 'release' + JobName: 'build_linux' + +jobs: +- job: build_${{ parameters.JobName }} + displayName: Build_Linux_${{ parameters.Runtime }}_${{ parameters.BuildConfiguration }} + condition: succeeded() + pool: + type: linux + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - 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: BUILDCONFIGURATION + value: ${{ parameters.BuildConfiguration }} + - name: Runtime + value: ${{ parameters.Runtime }} + - name: ob_sdl_sbom_packageName + value: 'Microsoft.Powershell.Linux.${{ parameters.Runtime }}' + - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: + - name: ob_sdl_codeql_compiled_enabled + value: true + + steps: + - checkout: self + clean: true + 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) + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: true + Language: csharp + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $runtime = $env:RUNTIME + + $params = @{} + if ($env:BUILDCONFIGURATION -eq 'minSize') { + Write-Verbose -Message "Building for minimal size" + $params['ForMinimalSize'] = $true + } + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime" + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Runtime) -Force + + $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 @params -Clean -PSModuleRestore @ReleaseTagParam + + $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) { + Write-Error -Message "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)" + } + } + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BUILDCONFIGURATION' configuration" + displayName: 'Build Linux - $(Runtime)' + 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. + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - pwsh: | + $platform = 'linux' + $vstsCommandString = "vso[task.setvariable variable=ArtifactPlatform]$platform" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Set artifact platform + + - pwsh: | + $pathForUpload = New-Item -ItemType Directory -Path '$(ob_outputDirectory)/Unsigned-$(Runtime)' -Force + Write-Verbose -Verbose -Message "pathForUpload: $pathForUpload" + Copy-Item -Path '$(Pipeline.Workspace)/Symbols_$(Runtime)/*' -Destination $pathForUpload -Recurse -Force -Verbose + displayName: Copy unsigned files for upload + + - template: /.pipelines/templates/step/finalize.yml@self + +- job: sign_${{ parameters.JobName }} + displayName: Sign_Linux_${{ parameters.Runtime }}_${{ parameters.BuildConfiguration }} + condition: succeeded() + dependsOn: build_${{ parameters.JobName }} + pool: + type: windows + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - 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: BuildConfiguration + value: ${{ parameters.BuildConfiguration }} + - name: Runtime + value: ${{ parameters.Runtime }} + - name: ob_sdl_codeql_compiled_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 + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: drop_linux_build_${{ parameters.JobName }} + path: $(Pipeline.Workspace)/drop_linux_build + displayName: Download build + + - pwsh: | + Get-ChildItem -Path $(Pipeline.Workspace)/drop_linux_build -Recurse + displayName: Capture downloaded files + + - pwsh: | + $pwshPath = Get-ChildItem -Path $(Pipeline.Workspace)/drop_linux_build -File -Recurse | Where-Object { $_.Name -eq 'pwsh' } + $rootPath = Split-Path -Path $pwshPath.FullName -Parent + Write-Verbose -Verbose "Setting vso[task.setvariable variable=DropRootPath]$rootPath" + Write-Host "##vso[task.setvariable variable=DropRootPath]$rootPath" + displayName: Set drop root path + + - 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-package-build.yml b/.pipelines/templates/mac-package-build.yml new file mode 100644 index 00000000000..2348063336c --- /dev/null +++ b/.pipelines/templates/mac-package-build.yml @@ -0,0 +1,251 @@ +parameters: + parentJob: '' + buildArchitecture: x64 + +jobs: +- job: package_macOS_${{ parameters.buildArchitecture }} + displayName: Package macOS ${{ parameters.buildArchitecture }} + condition: succeeded() + pool: + type: linux + isCustom: true + name: Azure Pipelines + vmImage: 'macOS-latest' + + variables: + - name: HOMEBREW_NO_ANALYTICS + value: 1 + - name: runCodesignValidationInjection + value: false + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: ob_sdl_credscan_suppressionsfileforartifacts + value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json + - name: BuildArch + value: ${{ parameters.buildArchitecture }} + + steps: + - checkout: self + clean: true + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - pwsh: | + # create folder + sudo mkdir "$(Agent.TempDirectory)/PowerShell" + + # make the current user the owner + sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" + displayName: 'Create $(Agent.TempDirectory)/PowerShell' + + - template: SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: shouldSign.yml + + - template: cloneToOfficialPath.yml + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + - template: rebuild-branch-check.yml@self + + - download: CoOrdinatedBuildPipeline + artifact: macosBinResults-${{ parameters.buildArchitecture }} + + - download: CoOrdinatedBuildPipeline + artifact: drop_macos_sign_${{ parameters.buildArchitecture }} + + - pwsh: | + Write-Verbose -Verbose "unsigned artifacts" + Get-ChildItem "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/macosBinResults-${{ parameters.buildArchitecture }}" -Recurse + + Write-Verbose -Verbose "unsigned artifacts" + Get-ChildItem "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/drop_macos_sign_${{ parameters.buildArchitecture }}" -Recurse + displayName: 'Capture Downloaded Artifacts' + # Diagnostics is not critical it passes every time it runs + continueOnError: true + + - pwsh: | + # Add -SkipReleaseChecks as a mitigation to unblock release. + # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. + + $buildArch = '${{ parameters.buildArchitecture }}' + + Write-Verbose -Message "Init..." -Verbose + $repoRoot = $env:REPOROOT + Set-Location $repoRoot + Import-Module "$repoRoot/build.psm1" + Import-Module "$repoRoot/tools/packaging" + + $unsignedFilesPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/macosBinResults-$buildArch" + $signedFilesPath = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/drop_macos_sign_$buildArch/Signed-$buildArch" + + Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose + if (-not (Test-Path $signedFilesPath/pwsh)) { + throw "pwsh not found in $signedFilesPath" + } + + $psoptionsPath = Get-ChildItem -Path $unsignedFilesPath -Filter 'psoptions.json' -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Message "Restoring PSOptions from $psoptionsPath" -Verbose + + 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:" + $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" -Verbose + } + + Start-PSBootstrap -Scenario Package + + $macosRuntime = "osx-$buildArch" + + 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 + + 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" + 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: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + +- job: sign_package_macOS_${{ parameters.buildArchitecture }} + displayName: Sign Package macOS ${{ parameters.buildArchitecture }} + dependsOn: package_macOS_${{ parameters.buildArchitecture }} + condition: succeeded() + pool: + type: windows + + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: ob_sdl_credscan_suppressionsfileforartifacts + value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json + - name: BuildArch + value: ${{ parameters.buildArchitecture }} + - group: mscodehub-macos-package-signing + + steps: + - download: current + artifact: macos-pkgs + + - pwsh: | + $buildArch = '${{ parameters.buildArchitecture }}' + $macosRuntime = "osx-$buildArch" + $pkgNameFilter = "powershell-*$macosRuntime.pkg" + $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File + + if ($pkgPath.Count -eq 0) { + throw "No package found for $macosRuntime" + } + + foreach($p in $pkgPath) { + $file = $p.FullName + $fileName = $p.BaseName + Write-Verbose -verbose "Compressing $file" + $zipFile = "$(Pipeline.Workspace)\${fileName}.zip" + Write-Verbose -Verbose "Zip file: $zipFile" + Compress-Archive -Path $file -Destination $zipFile + } + + Write-Verbose -Verbose "Compressed files:" + Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*.zip" -File | Write-Verbose -Verbose + displayName: Compress package files for signing + + - task: onebranch.pipeline.signing@1 + displayName: 'OneBranch CodeSigning Package' + inputs: + command: 'sign' + files_to_sign: '**/*-osx-*.zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "$(KeyCode)", + "OperationCode": "MacAppDeveloperSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "Hardening": "Enable", + "OpusInfo": "http://microsoft.com" + } + } + ] + + - 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 + } + + Expand-Archive -Path $_ -DestinationPath $(ob_outputDirectory) -Verbose + } + + Write-Verbose -Verbose "Expanded pkg file:" + Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose + displayName: Expand signed file diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml new file mode 100644 index 00000000000..ff4787b9bcf --- /dev/null +++ b/.pipelines/templates/mac.yml @@ -0,0 +1,149 @@ +parameters: + buildArchitecture: 'x64' +jobs: +- job: build_macOS_${{ parameters.buildArchitecture }} + displayName: Build macOS ${{ parameters.buildArchitecture }} + condition: succeeded() + pool: + type: linux + isCustom: true + name: Azure Pipelines + vmImage: 'macOS-latest' + + variables: + - name: HOMEBREW_NO_ANALYTICS + value: 1 + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: PowerShellRoot + value: $(Build.SourcesDirectory) + + steps: + - checkout: self + clean: true + 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) + - pwsh: | + # create folder + sudo mkdir "$(Agent.TempDirectory)/PowerShell" + # make the current user the owner + sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" + displayName: 'Create $(Agent.TempDirectory)/PowerShell' + + ## 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 + Start-PSBootstrap -Scenario Package + displayName: 'Bootstrap VM' + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + - pwsh: | + $env:AzDevOpsFeedPAT2 = '$(powershellPackageReadPat)' + # Add -SkipReleaseChecks as a mitigation to unblock release. + # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. + + Import-Module ./build.psm1 -Force + + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR + } + + Start-PSBuild -Runtime 'osx-${{ parameters.buildArchitecture }}' -Configuration Release -PSModuleRestore -Clean -Output $(OB_OUTPUTDIRECTORY) @ReleaseTagParam + $artifactName = "macosBinResults-${{ parameters.buildArchitecture }}" + + $psOptPath = "$(OB_OUTPUTDIRECTORY)/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + # 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)" + + $env:AzDevOpsFeedPAT2 = $null + displayName: 'Build' + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - template: /.pipelines/templates/step/finalize.yml@self + +- job: sign_${{ parameters.buildArchitecture }} + displayName: Sign_macOS_${{ parameters.buildArchitecture }} + condition: succeeded() + dependsOn: build_macOS_${{ parameters.buildArchitecture }} + pool: + type: windows + variables: + - name: NugetSecurityAnalysisWarningLevel + value: none + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_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: BuildArchitecture + value: ${{ parameters.buildArchitecture }} + - name: ob_sdl_codeql_compiled_enabled + value: false + - name: ob_sdl_sbom_packageName + value: 'Microsoft.Powershell.MacOS.${{parameters.buildArchitecture}}' + + steps: + - checkout: self + clean: true + 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) + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: 'macosBinResults-$(BuildArchitecture)' + path: '$(Pipeline.Workspace)\Symbols' + displayName: Download build + + - pwsh: | + Get-ChildItem "$(Pipeline.Workspace)\*" -Recurse + displayName: 'Capture Downloaded Artifacts' + # Diagnostics is not critical it passes every time it runs + continueOnError: true + + - pwsh: | + $runtime = '$(BuildArchitecture)' + Write-Host "sending.. vso[task.setvariable variable=Runtime]$runtime" + Write-Host "##vso[task.setvariable variable=Runtime]$runtime" + + $rootPath = "$(Pipeline.Workspace)\Symbols" + Write-Verbose -Verbose "Setting vso[task.setvariable variable=DropRootPath]$rootPath" + Write-Host "##vso[task.setvariable variable=DropRootPath]$rootPath" + displayName: Expand symbols zip + + - 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/nupkg.yml b/.pipelines/templates/nupkg.yml new file mode 100644 index 00000000000..873d7b6560b --- /dev/null +++ b/.pipelines/templates/nupkg.yml @@ -0,0 +1,300 @@ +jobs: +- job: build_nupkg + displayName: Package NuPkgs + condition: succeeded() + pool: + type: windows + + variables: + - name: runCodesignValidationInjection + value: false + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - 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 + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - group: DotNetPrivateBuildAccess + + 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 + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: shouldSign.yml + + - template: cloneToOfficialPath.yml + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_fxdependent_release + displayName: 'Download drop_windows_build_windows_fxdependent_release' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_fxdependentWinDesktop_release + displayName: 'Download drop_windows_build_windows_fxdependentWinDesktop_release' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - download: CoOrdinatedBuildPipeline + artifact: drop_linux_sign_linux_fxd + displayName: 'Download drop_linux_sign_linux_fxd' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - download: CoOrdinatedBuildPipeline + artifact: drop_linux_sign_linux_fxd_x64_alpine + displayName: 'Download drop_linux_sign_linux_fxd_x64_alpine' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - pwsh: | + Write-Verbose -Verbose "drop_windows_build_windows_fxdependent_release" + Get-ChildItem -Path $(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependent_release -Recurse | Out-String | Write-Verbose -Verbose + + Write-Verbose -Verbose "drop_windows_build_windows_fxdependentWinDesktop_release" + Get-ChildItem -Path $(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependentWinDesktop_release -Recurse | Out-String | Write-Verbose -Verbose + + Write-Verbose -Verbose "drop_linux_sign_linux_fxd" + Get-ChildItem -Path $(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd -Recurse | Out-String | Write-Verbose -Verbose + + Write-Verbose -Verbose "drop_linux_sign_linux_fxd_x64_alpine" + Get-ChildItem -Path $(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd_x64_alpine -Recurse | Out-String | Write-Verbose -Verbose + displayName: 'Capture download artifacts' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + Set-Location -Path '$(PowerShellRoot)' + Import-Module "$(PowerShellRoot)/build.psm1" -Force + + $sharedModules = @('Microsoft.PowerShell.Commands.Management', + 'Microsoft.PowerShell.Commands.Utility', + 'Microsoft.PowerShell.ConsoleHost', + 'Microsoft.PowerShell.Security', + 'System.Management.Automation' + ) + + $winOnlyModules = @('Microsoft.Management.Infrastructure.CimCmdlets', + 'Microsoft.PowerShell.Commands.Diagnostics', + 'Microsoft.PowerShell.CoreCLR.Eventing', + 'Microsoft.WSMan.Management', + 'Microsoft.WSMan.Runtime' + ) + + $refAssemblyFolder = Join-Path '$(System.ArtifactsDirectory)' 'RefAssembly' + $null = New-Item -Path $refAssemblyFolder -Force -Verbose -Type Directory + + Start-PSBuild -Clean -Runtime linux-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) + + $sharedModules | Foreach-Object { + $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net8.0\refint\$_.dll" + Write-Verbose -Verbose "RefAssembly: $refFile" + Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose + $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net8.0\$_.xml" + if (-not (Test-Path $refDoc)) { + Write-Warning "$refDoc not found" + Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net8.0\" | Out-String | Write-Verbose -Verbose + } + else { + Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose + } + } + + Start-PSBuild -Clean -Runtime win7-x64 -Configuration Release -ReleaseTag $(ReleaseTagVar) + + $winOnlyModules | Foreach-Object { + $refFile = Get-ChildItem -Path "$(PowerShellRoot)\src\$_\obj\Release\net8.0\refint\*.dll" + Write-Verbose -Verbose 'RefAssembly: $refFile' + Copy-Item -Path $refFile -Destination "$refAssemblyFolder\$_.dll" -Verbose + $refDoc = "$(PowerShellRoot)\src\$_\bin\Release\net8.0\$_.xml" + if (-not (Test-Path $refDoc)) { + Write-Warning "$refDoc not found" + Get-ChildItem -Path "$(PowerShellRoot)\src\$_\bin\Release\net8.0" | Out-String | Write-Verbose -Verbose + } + else { + Copy-Item -Path $refDoc -Destination "$refAssemblyFolder\$_.xml" -Verbose + } + } + + Get-ChildItem $refAssemblyFolder -Recurse | Out-String | Write-Verbose -Verbose + + # Set RefAssemblyPath path variable + $vstsCommandString = "vso[task.setvariable variable=RefAssemblyPath]${refAssemblyFolder}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Build reference assemblies + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - task: onebranch.pipeline.signing@1 + displayName: Sign ref assemblies + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.dll' + search_root: '$(System.ArtifactsDirectory)\RefAssembly' + + - pwsh: | + $files = @( + "Microsoft.Management.Infrastructure.CimCmdlets.dll" + "Microsoft.PowerShell.Commands.Diagnostics.dll" + "Microsoft.PowerShell.Commands.Management.dll" + "Microsoft.PowerShell.Commands.Utility.dll" + "Microsoft.PowerShell.ConsoleHost.dll" + "Microsoft.PowerShell.CoreCLR.Eventing.dll" + "Microsoft.PowerShell.Security.dll" + "Microsoft.PowerShell.SDK.dll" + "Microsoft.WSMan.Management.dll" + "Microsoft.WSMan.Runtime.dll" + "System.Management.Automation.dll" + ) + + Import-Module -Name '$(PowerShellRoot)\build.psm1' + Import-Module -Name '$(PowerShellRoot)\tools\packaging' + Find-DotNet + + Write-Verbose -Verbose "Version == $(Version)" + + $winFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependent_release\Signed-fxdependent" + Write-Verbose -Verbose "winFxdPath == $winFxdPath" + + $linuxFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd\Signed-fxdependent" + Write-Verbose -Verbose "linuxFxdPath == $linuxFxdPath" + + $nupkgOutputPath = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'nupkg' + New-Item -Path $nupkgOutputPath -ItemType Directory -Force + + $files | Foreach-Object { + $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($_) + $FilePackagePath = Join-Path -Path $nupkgOutputPath -ChildPath $FileBaseName + Write-Verbose -Verbose "FileName to package: $_" + Write-Verbose -Verbose "FilePackage path: $FilePackagePath" + New-ILNugetPackageSource -File $_ -PackagePath $FilePackagePath -PackageVersion '$(Version)' -WinFxdBinPath $winFxdPath -LinuxFxdBinPath $linuxFxdPath -RefAssemblyPath $(RefAssemblyPath) + New-ILNugetPackageFromSource -FileName $_ -PackageVersion '$(Version)' -PackagePath $FilePackagePath + } + displayName: 'Create NuGet Package for single file' + + - task: onebranch.pipeline.signing@1 + displayName: Sign nupkg files + inputs: + command: 'sign' + cp_code: 'CP-401405' + files_to_sign: '**\*.nupkg' + search_root: '$(Pipeline.Workspace)\nupkg' + + ### Create global tools + + - pwsh: | + $winFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependent_release\Signed-fxdependent" + $winDesktopFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependentWinDesktop_release\Signed-fxdependent-win-desktop" + $linuxFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd\Signed-fxdependent" + $alpineFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd_x64_alpine\Signed-fxdependent-noopt-linux-musl-x64" + + Import-Module -Name '$(PowerShellRoot)\build.psm1' + Import-Module -Name '$(PowerShellRoot)\tools\packaging' + + Start-PrepForGlobalToolNupkg -LinuxBinPath $linuxFxdPath -WindowsBinPath $winFxdPath -WindowsDesktopBinPath $winDesktopFxdPath -AlpineBinPath $alpineFxdPath + displayName: 'Prepare for global tool packages' + + - pwsh: | + Import-Module -Name '$(PowerShellRoot)\build.psm1' + Import-Module -Name '$(PowerShellRoot)\tools\packaging' + Find-DotNet + + $gblToolOutputPath = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'globaltools' + New-Item -Path $gblToolOutputPath -ItemType Directory -Force + + $winFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependent_release\Signed-fxdependent" + $winDesktopFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependentWinDesktop_release\Signed-fxdependent-win-desktop" + $linuxFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd\Signed-fxdependent" + $alpineFxdPath = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_linux_sign_linux_fxd_x64_alpine\Signed-fxdependent-noopt-linux-musl-x64" + + # Build global tools which do not have the shims exe generated in build. + $packageTypes = @('Unified', 'PowerShell.Linux.Alpine', 'PowerShell.Linux.x64', 'PowerShell.Linux.arm32', 'PowerShell.Linux.arm64') + + $packageTypes | Foreach-Object { + $PackageType = $_ + Write-Verbose -Verbose "PackageType: $PackageType" + + New-GlobalToolNupkgSource -PackageType $PackageType -PackageVersion '$(Version)' -LinuxBinPath $linuxFxdPath -WindowsBinPath $winFxdPath -WindowsDesktopBinPath $winDesktopFxdPath -AlpineBinPath $alpineFxdPath -SkipCGManifest + + Write-Verbose -Verbose "GlobalToolNuspecSourcePath = $global:GlobalToolNuSpecSourcePath" + Write-Verbose -Verbose "GlobalToolPkgName = $global:GlobalToolPkgName" + + Write-Verbose -Verbose "Starting global tool package creation for $PackageType" + New-GlobalToolNupkgFromSource -PackageNuSpecPath "$global:GlobalToolNuSpecSourcePath" -PackageName "$global:GlobalToolPkgName" -DestinationPath $gblToolOutputPath + Write-Verbose -Verbose "Global tool package created for $PackageType" + $global:GlobalToolNuSpecSourcePath = $null + $global:GlobalToolPkgName = $null + } + displayName: 'Create global tools' + + - pwsh: | + $gblToolOutputPath = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'globaltools' + Get-ChildItem -Path $gblToolOutputPath + displayName: Capture global tools + + - task: onebranch.pipeline.signing@1 + displayName: Sign nupkg files + inputs: + command: 'sign' + cp_code: 'CP-401405' + files_to_sign: '**\*.nupkg' + search_root: '$(Pipeline.Workspace)\globaltools' + + - pwsh: | + if (-not (Test-Path '$(ob_outputDirectory)')) { + New-Item -ItemType Directory -Path '$(ob_outputDirectory)' -Force + } + + Write-Verbose -Verbose "Copying nupkgs to output directory" + $nupkgOutputPath = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'nupkg' + Get-ChildItem -Path $nupkgOutputPath -Filter *.nupkg -Recurse | Copy-Item -Destination '$(ob_outputDirectory)' -Force -Verbose + + # Copy Windows.x86 global tool from build to output directory + $winX64GlobalTool = "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_fxdependent_release\globaltool\powershell*.nupkg" + Write-Verbose -Verbose "Finding Windows.x64 global tool at $winX64GlobalTool" + $globalToolPath = Get-Item $winX64GlobalTool + Copy-Item -Path $globalToolPath -Destination '$(ob_outputDirectory)' -Force -Verbose + + Write-Verbose -Verbose "Copying global tools to output directory" + $gblToolOutputPath = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'globaltools' + Get-ChildItem -Path $gblToolOutputPath -Filter *.nupkg -Recurse | Copy-Item -Destination '$(ob_outputDirectory)' -Force -Verbose + displayName: Copy artifacts to output directory + + - pwsh: | + $nupkgOutputPath = '$(ob_outputDirectory)' + Get-ChildItem -Path $nupkgOutputPath | Out-String | Write-Verbose -Verbose + displayName: List artifacts diff --git a/.pipelines/templates/obp-file-signing.yml b/.pipelines/templates/obp-file-signing.yml new file mode 100644 index 00000000000..3793078503e --- /dev/null +++ b/.pipelines/templates/obp-file-signing.yml @@ -0,0 +1,181 @@ +parameters: + binPath: '$(ob_outputDirectory)' + globalTool: 'false' + SigningProfile: 'external_distribution' + OfficialBuild: true + vPackScenario: false + +steps: +- pwsh: | + $fullSymbolsFolder = '${{ parameters.binPath }}' + Write-Verbose -Verbose "fullSymbolsFolder == $fullSymbolsFolder" + Get-ChildItem -Recurse $fullSymbolsFolder | Select-Object -ExpandProperty FullName | Write-Verbose -Verbose + $filesToSignDirectory = "$(Pipeline.Workspace)/toBeSigned" + if ((Test-Path -Path $filesToSignDirectory)) { + Remove-Item -Path $filesToSignDirectory -Recurse -Force + } + $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force + + $itemsToCopyWithRecurse = @( + "$($fullSymbolsFolder)/*.ps1" + "$($fullSymbolsFolder)/Microsoft.PowerShell*.dll" + ) + $itemsToCopy = @{ + "$($fullSymbolsFolder)/*.ps1" = "" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1" = "Modules/Microsoft.PowerShell.Host" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1" = "Modules/Microsoft.PowerShell.Management" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1" = "Modules/Microsoft.PowerShell.Security" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1" = "Modules/Microsoft.PowerShell.Utility" + "$($fullSymbolsFolder)/pwsh.dll" = "" + "$($fullSymbolsFolder)/System.Management.Automation.dll" = "" + } + ## Windows only modules + if('$(ArtifactPlatform)' -eq 'windows') { + $itemsToCopy += @{ + "$($fullSymbolsFolder)/pwsh.exe" = "" + "$($fullSymbolsFolder)/Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" + "$($fullSymbolsFolder)/Microsoft.WSMan.*.dll" = "" + "$($fullSymbolsFolder)/Modules/CimCmdlets/CimCmdlets.psd1" = "Modules/CimCmdlets" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml" = "Modules/Microsoft.PowerShell.Diagnostics" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml" = "Modules/Microsoft.PowerShell.Diagnostics" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml" = "Modules/Microsoft.PowerShell.Diagnostics" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Security/Security.types.ps1xml" = "Modules/Microsoft.PowerShell.Security" + "$($fullSymbolsFolder)/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1" = "Modules/Microsoft.PowerShell.Diagnostics" + "$($fullSymbolsFolder)/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1" = "Modules/Microsoft.WSMan.Management" + "$($fullSymbolsFolder)/Modules/Microsoft.WSMan.Management/WSMan.format.ps1xml" = "Modules/Microsoft.WSMan.Management" + "$($fullSymbolsFolder)/Modules/PSDiagnostics/PSDiagnostics.ps?1" = "Modules/PSDiagnostics" + } + } + + $itemsToExclude = @( + # This package is retrieved from https://www.github.com/powershell/MarkdownRender + "$($fullSymbolsFolder)/Microsoft.PowerShell.MarkdownRender.dll" + ) + + if('$(ArtifactPlatform)' -eq 'linux' -or '$(ArtifactPlatform)' -eq 'macos') { + $itemsToExclude += "$($fullSymbolsFolder)/pwsh" + } + + Write-Verbose -verbose "recursively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" + Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude + Write-Verbose -verbose "recursive copy done." + + foreach($pattern in $itemsToCopy.Keys) { + $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern + $null = New-Item -ItemType Directory -Path $destinationFolder -Force + Write-Verbose -verbose "copying $pattern to $destinationFolder" + + if (-not (Test-Path -Path $pattern)) { + Write-Verbose -verbose "No files found for pattern $pattern" + continue + } + + Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose + } + + Write-Verbose -verbose "copying done." + Write-Verbose -verbose "Files to be signed at: $filesToSignDirectory" + + Get-ChildItem -Recurse -File $filesToSignDirectory | Select-Object -Property FullName + displayName: 'Prepare files to be signed' + +- task: onebranch.pipeline.signing@1 + displayName: Sign 1st party files + inputs: + command: 'sign' + signing_profile: ${{ parameters.SigningProfile }} + files_to_sign: '**\*.psd1;**\*.psm1;**\*.ps1xml;**\*.ps1;**\*.dll;**\*.exe;**\pwsh' + search_root: $(Pipeline.Workspace)/toBeSigned + +- pwsh : | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + +- pwsh: | + Get-ChildItem -Path '$(Pipeline.Workspace)/toBeSigned/*' + displayName: Capture signed files + +- pwsh: | + Import-Module $(PowerShellRoot)/build.psm1 -Force + Import-Module $(PowerShellRoot)/tools/packaging -Force + + $BuildPath = (Get-Item '${{ parameters.binPath }}').FullName + Write-Verbose -Verbose -Message "BuildPath: $BuildPath" + + Write-Verbose -Verbose "Signed Path: $(Pipeline.Workspace)/toBeSigned" + + $officialBuild = [System.Convert]::ToBoolean('${{ parameters.OfficialBuild }}') + ## copy all files to be signed to build folder + Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath '$(Pipeline.Workspace)/toBeSigned' -OfficialBuild $officialBuild + + $dlls = Get-ChildItem $BuildPath/*.dll, $BuildPath/*.exe -Recurse + $signatures = $dlls | Get-AuthenticodeSignature + $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)" + + $filesToSignDirectory = "$(Pipeline.Workspace)/thirdPartyToBeSigned" + if (Test-Path $filesToSignDirectory) { + Remove-Item -Path $filesToSignDirectory -Recurse -Force + } + $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force -Verbose + + $missingSignatures | ForEach-Object { + $pathWithoutLeaf = Split-Path $_ + $relativePath = $pathWithoutLeaf.replace($BuildPath,'') + Write-Verbose -Verbose -Message "relativePath: $relativePath" + $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath + Write-Verbose -Verbose -Message "targetDirectory: $targetDirectory" + if(!(Test-Path $targetDirectory)) + { + $null = New-Item -ItemType Directory -Path $targetDirectory -Force -Verbose + } + Copy-Item -Path $_ -Destination $targetDirectory + } + displayName: Create ThirdParty Signing Folder + +- task: onebranch.pipeline.signing@1 + displayName: Sign 3rd Party files + inputs: + command: 'sign' + signing_profile: $(msft_3rd_party_cert_id) + files_to_sign: '**\*.dll;**\*.exe' + search_root: $(Pipeline.Workspace)/thirdPartyToBeSigned + +- pwsh: | + Get-ChildItem '$(Pipeline.Workspace)/thirdPartyToBeSigned/*' + 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 ($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 + Write-Verbose -Verbose -Message "Files copied to $pathForUpload" + } + else { + $pathForUpload = '${{ parameters.binPath }}' + } + + Write-Verbose "Copying third party signed files to the build folder" + $thirdPartySignedFilesPath = (Get-Item '$(Pipeline.Workspace)/thirdPartyToBeSigned').FullName + Update-PSSignedBuildFolder -BuildPath $pathForUpload -SignedFilesPath $thirdPartySignedFilesPath -OfficialBuild $officialBuild + + displayName: 'Copy signed files for upload' + +- template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml new file mode 100644 index 00000000000..bb9a75d2235 --- /dev/null +++ b/.pipelines/templates/package-create-msix.yml @@ -0,0 +1,299 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + +jobs: +- job: CreateMSIXBundle + displayName: Create .msixbundle file + pool: + type: windows + + 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 + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - 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 + inputs: + buildType: 'current' + artifact: drop_windows_package_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows arm64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows x64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_x86 + itemPattern: | + **/*.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 + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $toolsDir = '$(Pipeline.Workspace)\releasePipeline\tools' + New-Item $toolsDir -Type Directory -Force > $null + $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:' + } + $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" + + Get-ChildItem -Path $sourceDir -Recurse + $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 + 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" + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + + 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)' + 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)" + + # 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('$(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-Stable' + 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: | + 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/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml new file mode 100644 index 00000000000..ad9d81645a0 --- /dev/null +++ b/.pipelines/templates/packaging/windows/package.yml @@ -0,0 +1,230 @@ +parameters: + runtime: x64 + +jobs: +- job: build_win_${{ parameters.runtime }} + displayName: Build Windows Packages ${{ parameters.runtime }} + condition: succeeded() + pool: + 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 + 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 + 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: 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 + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: Runtime + value: ${{ parameters.runtime }} + - group: msixTools + + steps: + - checkout: self + clean: true + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + ob_restore_phase: false + + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + parameters: + 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 + condition: ${{ ne(parameters.runtime, 'minSize') }} + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_x64_${{ parameters.runtime }} + displayName: Download minsize signed artifacts + condition: ${{ eq(parameters.runtime, 'minSize') }} + + - pwsh: | + Write-Verbose -Verbose "signed artifacts" + Get-ChildItem "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_${{ parameters.runtime }}_release" -Recurse + displayName: 'Capture Downloaded Artifacts' + # Diagnostics is not critical it passes every time it runs + continueOnError: true + + - template: /.pipelines/templates/install-dotnet.yml@self + parameters: + ob_restore_phase: false + + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $signedFolder = switch ($runtime) { + 'x64' { 'Signed-win7-x64' } + 'x86' { 'Signed-win7-x86' } + 'arm64' { 'Signed-win-arm64' } + 'fxdependent' { 'Signed-fxdependent' } + 'fxdependentWinDesktop' { 'Signed-fxdependent-win-desktop' } + 'minsize' { 'Signed-win7-x64' } + } + + Write-Verbose -Message "Init..." -Verbose + + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + Start-PSBootstrap -Scenario Both + + Find-Dotnet + + $signedFilesPath, $psoptionsFilePath = if ($env:RUNTIME -eq 'minsize') { + "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_x64_${runtime}\$signedFolder" + "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_x64_${runtime}\psoptions\psoptions.json" + } + else { + "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_${runtime}_release\$signedFolder" + "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline\drop_windows_build_windows_${runtime}_release\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 + + 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:" + $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" + } + + Start-PSBootstrap -Scenario Package + + $WindowsRuntime = switch ($runtime) { + 'x64' { 'win7-x64' } + 'x86' { 'win7-x86' } + 'arm64' { 'win-arm64' } + 'fxdependent' { 'win7-x64' } + 'fxdependentWinDesktop' { 'win7-x64' } + 'minsize' { 'win7-x64' } + } + + $packageTypes = switch ($runtime) { + 'x64' { @('msi', 'zip', 'msix') } + 'x86' { @('msi', 'zip', 'msix') } + 'arm64' { @('msi', 'zip', 'msix') } + 'fxdependent' { 'fxdependent' } + 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } + 'minsize' { 'min-size' } + } + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + Set-Location $repoRoot + + Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + + displayName: 'Build Packages (Unsigned)' + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + # Copy unsigned packages to output directory + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $packageTypes = switch ($runtime) { + 'x64' { @('msi', 'zip', 'msix') } + 'x86' { @('msi', 'zip', 'msix') } + 'arm64' { @('msi', 'zip', 'msix') } + '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 "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 "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 "unsigned msixPkgPath: $msixPkgPath" + Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + displayName: Copy unsigned packages to output directory + + - pwsh: | + Get-ChildItem -Path $(ob_outputDirectory) -Recurse + 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/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 diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml new file mode 100644 index 00000000000..47be4e0db26 --- /dev/null +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -0,0 +1,124 @@ +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' + - 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'] ] + 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 '-preview') { + $middleURL = "preview" + } + elseif ($tagString -match '(\d+\.\d+)') { + $middleURL = $matches[1] + } + + $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" + $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: | + $IsLTS = '$(LTS)' -eq 'true' + $IsStable = '$(STABLE)' -eq 'true' + $IsPreview = '$(PREVIEW)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(Stable), Preview: $(Preview)" + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + 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 StoreBroker Package (Stable/LTS)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + 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 StoreBroker Package (Preview)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) + inputs: + 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' diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml new file mode 100644 index 00000000000..4f3df0d5892 --- /dev/null +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -0,0 +1,176 @@ +parameters: + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false + +jobs: +- template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Approve Copy release packages to PSInfra storage + jobName: CopyReleaseBlobApproval + instructions: | + Approval for Copy release packages to PSInfra storage + +- job: PSInfraReleaseBlobPublic + displayName: Copy release to PSInfra storage + dependsOn: CopyReleaseBlobApproval + condition: and(succeeded(), ne('${{ parameters.SkipPSInfraInstallers }}', true)) + pool: + name: PowerShell1ES + type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure + + variables: + - group: 'PSInfraStorage' + - group: 'Azure Blob variable group' + - 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 + - name: ob_sdl_codeql_compiled_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 + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - task: AzurePowerShell@5 + displayName: Copy blobs to PSInfra storage + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $sourceStorageAccountName = '$(StorageAccount)' + $destinationStorageAccountName = '$(PSInfraStorageAccount)' + $destinationContainerName = '$web' + $destinationPrefix = 'install/$(ReleaseTagVar)' + + $sourceContext = New-AzStorageContext -StorageAccountName $sourceStorageAccountName + Write-Verbose -Verbose "Source context: $($sourceContext.BlobEndPoint)" + + $destinationContext = New-AzStorageContext -StorageAccountName $destinationStorageAccountName + Write-Verbose -Verbose "Destination context: $($destinationContext.BlobEndPoint)" + + foreach ($sourceContainerName in '$(AzureVersion)', '$(AzureVersion)-gc') { + $blobs = Get-AzStorageBlob -Context $sourceContext -Container $sourceContainerName + + Write-Verbose -Verbose "Blobs found in $sourceContainerName" + $blobs.Name | Write-Verbose -Verbose + + Write-Verbose -Verbose "Copying blobs from $sourceContainerName to $destinationContainerName/$destinationPrefix" + + foreach ($blob in $blobs) { + $sourceBlobName = $blob.Name + Write-Verbose -Verbose "sourceBlobName = $sourceBlobName" + + $destinationBlobName = "$destinationPrefix/$sourceBlobName" + Write-Verbose -Verbose "destinationBlobName = $destinationBlobName" + $existingBlob = Get-AzStorageBlob -Blob $destinationBlobName -Container $destinationContainerName -Context $destinationContext -ErrorAction Ignore + if ($existingBlob) { + Write-Verbose -Verbose "Blob $destinationBlobName already exists in '$destinationStorageAccountName/$destinationContainerName', removing before copy." + $existingBlob | Remove-AzStorageBlob -ErrorAction Stop -Verbose + } + + Copy-AzStorageBlob -SourceContext $sourceContext -DestinationContext $destinationContext -SrcContainer $sourceContainerName -SrcBlob $sourceBlobName -DestContainer $destinationContainerName -DestBlob $destinationBlobName -Force -Verbose -Confirm:$false + } + } + + +- template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Approve Copy Global tool packages to PSInfra storage + jobName: CopyBlobApproval + instructions: | + Approval for Copy global tool packages to PSInfra storage + +- job: PSInfraBlobPublic + displayName: Copy global tools to PSInfra storage + dependsOn: CopyBlobApproval + pool: + name: PowerShell1ES + type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure + + variables: + - group: 'PSInfraStorage' + - group: 'Azure Blob variable group' + - 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 + 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: no + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - task: AzurePowerShell@5 + displayName: Copy blobs to PSInfra storage + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $sourceStorageAccountName = '$(StorageAccount)' + $sourceContainerName = '$(AzureVersion)-nuget' + $prefix = 'globaltool' + + $destinationStorageAccountName = '$(PSInfraStorageAccount)' + $destinationContainerName = '$web' + $destinationPrefix = 'tool/$(Version)' + + $sourceContext = New-AzStorageContext -StorageAccountName $sourceStorageAccountName + Write-Verbose -Verbose "Source context: $($sourceContext.BlobEndPoint)" + + $destinationContext = New-AzStorageContext -StorageAccountName $destinationStorageAccountName + Write-Verbose -Verbose "Destination context: $($destinationContext.BlobEndPoint)" + + $blobs = Get-AzStorageBlob -Context $sourceContext -Container $sourceContainerName -Prefix $prefix + + Write-Verbose -Verbose "Blobs found in $sourceContainerName" + $blobs.Name | Write-Verbose -Verbose + + Write-Verbose -Verbose "Copying blobs from $sourceContainerName to $destinationContainerName/$destinationPrefix" + + foreach ($blob in $blobs) { + $sourceBlobName = $blob.Name + Write-Verbose -Verbose "sourceBlobName = $sourceBlobName" + + $destinationBlobName = $sourceBlobName -replace "$prefix", $destinationPrefix + Write-Verbose -Verbose "destinationBlobName = $destinationBlobName" + + Copy-AzStorageBlob -SourceContext $sourceContext -DestinationContext $destinationContext -SrcContainer $sourceContainerName -SrcBlob $sourceBlobName -DestContainer $destinationContainerName -DestBlob $destinationBlobName -Force -Verbose -Confirm:$false + } diff --git a/tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml b/.pipelines/templates/release-SetReleaseTagandContainerName.yml similarity index 52% rename from tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml rename to .pipelines/templates/release-SetReleaseTagandContainerName.yml index 26229325b82..d40551353d2 100644 --- a/tools/releaseBuild/azureDevOps/templates/release-SetReleaseTagAndContainerName.yml +++ b/.pipelines/templates/release-SetReleaseTagandContainerName.yml @@ -1,3 +1,7 @@ +parameters: +- name: restorePhase + default: false + steps: - pwsh: | $variable = 'releaseTag' @@ -8,14 +12,25 @@ steps: } $releaseTag = $Branch -replace '^.*((release|rebuild)/)' - $vstsCommandString = "vso[task.setvariable variable=$Variable]$releaseTag" + $vstsCommandString = "vso[task.setvariable variable=$Variable;isOutput=true]$releaseTag" Write-Verbose -Message "setting $Variable to $releaseTag" -Verbose Write-Host -Object "##$vstsCommandString" + name: OutputReleaseTag displayName: Set Release Tag + env: + ob_restore_phase: ${{ parameters.restorePhase }} - pwsh: | - $azureVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' - $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" + $azureVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '\.', '-' + $vstsCommandString = "vso[task.setvariable variable=AzureVersion;isOutput=true]$azureVersion" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" + + $version = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant().Substring(1) + $vstsCommandString = "vso[task.setvariable variable=Version;isOutput=true]$version" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + name: OutputVersion displayName: Set container name + env: + ob_restore_phase: ${{ parameters.restorePhase }} diff --git a/.pipelines/templates/release-SetTagAndChangelog.yml b/.pipelines/templates/release-SetTagAndChangelog.yml new file mode 100644 index 00000000000..b33e652b3c7 --- /dev/null +++ b/.pipelines/templates/release-SetTagAndChangelog.yml @@ -0,0 +1,51 @@ +jobs: +- job: setTagAndChangelog + displayName: Set Tag and Upload Changelog + condition: succeeded() + pool: + type: windows + variables: + - group: 'mscodehub-code-read-akv' + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - 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: + - template: release-SetReleaseTagandContainerName.yml@self + + - checkout: self + clean: true + env: + ob_restore_phase: true + + - pwsh: | + Write-Verbose -Verbose "Release Tag: $(OutputReleaseTag.releaseTag)" + $releaseVersion = '$(OutputReleaseTag.releaseTag)' -replace '^v','' + Write-Verbose -Verbose "Release Version: $releaseVersion" + $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion + + $isPreview = $semanticVersion.PreReleaseLabel -ne $null + + $fileName = if ($isPreview) { + "preview.md" + } + else { + $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" + } + + $filePath = "$(Build.SourcesDirectory)/PowerShell/CHANGELOG/$fileName" + Write-Verbose -Verbose "Selected Log file: $filePath" + + if (-not (Test-Path -Path $filePath)) { + Write-Error "Changelog file not found: $filePath" + exit 1 + } + + Write-Verbose -Verbose "Creating output directory for CHANGELOG: $(ob_outputDirectory)/CHANGELOG" + 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/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml new file mode 100644 index 00000000000..a8a874619a4 --- /dev/null +++ b/.pipelines/templates/release-githubNuget.yml @@ -0,0 +1,203 @@ +parameters: + - name: skipPublish + type: boolean + +jobs: +- job: GithubReleaseDraft + displayName: Create GitHub Release Draft + condition: succeeded() + pool: + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: drop_setReleaseTagAndChangelog_SetTagAndChangelog + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages + variables: + - template: ./variable/release-shared.yml@self + parameters: + RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] + + steps: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Release Tag: $(ReleaseTag)" + Get-ChildItem Env: | Out-String -Stream | Write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + $Path = "$(Pipeline.Workspace)/GitHubPackages" + $OutputPath = Join-Path $Path 'hashes.sha256' + $packages = Get-ChildItem -Path $Path -Include * -Recurse -File + $checksums = $packages | + ForEach-Object { + Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" + $packageName = $_.Name + $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() + # the '*' before the packagename signifies it is a binary + "$hash *$packageName" + } + $checksums | Out-File -FilePath $OutputPath -Force + $fileContent = Get-Content -Path $OutputPath -Raw | Out-String + Write-Verbose -Verbose -Message $fileContent + displayName: Add sha256 hashes + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Get-ChildItem $(Pipeline.Workspace) -recurse | Select-Object -ExpandProperty FullName + displayName: List all files in the workspace + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + $releaseVersion = '$(ReleaseTag)' -replace '^v','' + Write-Verbose -Verbose "Available modules: " + Get-Module | Write-Verbose -Verbose + + $filePath = Get-ChildItem -Path "$(Pipeline.Workspace)/CHANGELOG" -Filter '*.md' | Select-Object -First 1 -ExpandProperty FullName + + if (-not (Test-Path $filePath)) { + throw "$filePath not found" + } + + $changelog = Get-Content -Path $filePath + + $headingPattern = "^## \[\d+\.\d+\.\d+" + $headingStartLines = $changelog | Select-String -Pattern $headingPattern | Select-Object -ExpandProperty LineNumber + $startLine = $headingStartLines[0] + $endLine = $headingStartLines[1] - 1 + + $clContent = $changelog | Select-Object -Skip ($startLine-1) -First ($endLine - $startLine) | Out-String + + $StringBuilder = [System.Text.StringBuilder]::new($clContent, $clContent.Length + 2kb) + $StringBuilder.AppendLine().AppendLine() > $null + $StringBuilder.AppendLine("### SHA256 Hashes of the release artifacts").AppendLine() > $null + Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages/" -File | ForEach-Object { + $PackageName = $_.Name + $SHA256 = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash + $StringBuilder.AppendLine("- $PackageName").AppendLine(" - $SHA256") > $null + } + + $clContent = $StringBuilder.ToString() + + Write-Verbose -Verbose "Selected content: `n$clContent" + + $releaseNotesFilePath = "$(Pipeline.Workspace)/release-notes.md" + $clContent | Out-File -FilePath $releaseNotesFilePath -Encoding utf8 + + Write-Host "##vso[task.setvariable variable=ReleaseNotesFilePath;]$releaseNotesFilePath" + + #if name has prelease then make prerelease true as a variable + if ($releaseVersion -like '*-*') { + Write-Host "##vso[task.setvariable variable=IsPreRelease;]true" + } else { + Write-Host "##vso[task.setvariable variable=IsPreRelease;]false" + } + displayName: Set variables for GitHub release task + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Host "ReleaseNotes content:" + Get-Content "$(Pipeline.Workspace)/release-notes.md" -Raw | Out-String -width 9999 | Write-Host + displayName: Verify Release Notes + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + $middleURL = '' + $tagString = "$(ReleaseTag)" + Write-Verbose -Verbose "Use the following command to push the tag:" + if ($tagString -match '-') { + $middleURL = "preview" + } + elseif ($tagString -match '(\d+\.\d+)') { + $middleURL = $matches[1] + } + $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 + + - task: GitHubRelease@1 + inputs: + gitHubConnection: GitHubReleasePAT + repositoryName: PowerShell/PowerShell + target: master + assets: '$(Pipeline.Workspace)/GitHubPackages/*' + tagSource: 'userSpecifiedTag' + tag: '$(ReleaseTag)' + title: "$(ReleaseTag) Release of PowerShell" + isDraft: true + addChangeLog: false + action: 'create' + releaseNotesFilePath: '$(ReleaseNotesFilePath)' + isPrerelease: '$(IsPreRelease)' + +- job: NuGetPublish + displayName: Publish to NuGet + condition: succeeded() + pool: + type: release + os: windows + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_upload_upload_packages + variables: + - template: ./variable/release-shared.yml@self + parameters: + VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] + + steps: + - task: PowerShell@2 + inputs: + targetType: inline + script: | + Write-Verbose -Verbose "Version: $(Version)" + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - task: PowerShell@2 + inputs: + targetType: inline + script: | + #Exclude all global tool packages. Their names start with 'PowerShell.' + $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" + Copy-Item "$(Pipeline.Workspace)/NuGetPackages/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose + + $releaseVersion = '$(Version)' + $globalToolPath = "$(Pipeline.Workspace)/NuGetPackages/PowerShell.$releaseVersion.nupkg" + + if ($releaseVersion -notlike '*-*') { + # Copy the global tool package for stable releases + Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" + } + + Write-Verbose -Verbose "The .nupkgs below will be pushed:" + Get-ChildItem "$(Pipeline.Workspace)/release" -recurse + displayName: Download and capture nupkgs + condition: and(ne('${{ parameters.skipPublish }}', 'true'), succeeded()) + + - task: NuGetCommand@2 + displayName: 'NuGet push' + condition: and(ne('${{ parameters.skipPublish }}', 'true'), succeeded()) + inputs: + command: push + packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' + nuGetFeedType: external + publishFeedCredentials: PowerShellNuGetOrgPush diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml new file mode 100644 index 00000000000..cf7982cd5e1 --- /dev/null +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -0,0 +1,237 @@ +parameters: +- name: skipPublish + type: boolean + default: false + +stages: +- stage: PrepForEV2 + displayName: 'Copy and prep all files needed for EV2 stage' + jobs: + - job: CopyEV2FilesToArtifact + displayName: 'Copy EV2 Files to Artifact' + pool: + type: linux + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: repoRoot + value: '$(Build.SourcesDirectory)/PowerShell' + - name: ev2ServiceGroupRootFolder + value: '$(Build.SourcesDirectory)/PowerShell/.pipelines/EV2Specs/ServiceGroupRoot' + - name: ev2ParametersFolder + value: '$(Build.SourcesDirectory)/PowerShell/.pipelines/EV2Specs/ServiceGroupRoot/Parameters' + - group: 'mscodehub-code-read-akv' + - group: 'packages.microsoft.com' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + steps: + - checkout: self ## the global setting on lfs didn't work + lfs: false + env: + ob_restore_phase: true + + - template: release-SetReleaseTagandContainerName.yml + parameters: + restorePhase: true + + - pwsh: | + $packageVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '^v','' + $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: Set Package version + env: + ob_restore_phase: true + + - pwsh: | + $branch = 'mirror-target' + $gitArgs = "clone", + "--verbose", + "--branch", + "$branch", + "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", + '$(Pipeline.Workspace)/tools' + $gitArgs | Write-Verbose -Verbose + git $gitArgs + displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem '$(Build.SourcesDirectory)' + displayName: 'Capture BuildDirectory' + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem '$(Pipeline.Workspace)' -Recurse | Out-String -Stream | write-Verbose -Verbose + displayName: 'Capture Workspace' + env: + ob_restore_phase: true + + - pwsh: | + New-Item -Path '$(ev2ParametersFolder)' -ItemType Directory + displayName: 'Create Parameters folder under EV2Specs folder' + env: + ob_restore_phase: true + + - task: PipAuthenticate@1 + inputs: + artifactFeeds: 'PowerShellCore/PowerShellCore_PublicPackages' + displayName: 'Pip Authenticate' + env: + ob_restore_phase: true + + - pwsh: | + python3 -m pip install --upgrade pip + pip --version --verbose + + Write-Verbose -Verbose "Download pmc-cli to folder without installing it" + $pythonDlFolderPath = Join-Path '$(ev2ServiceGroupRootFolder)/Shell/Run' -ChildPath "python_dl" + pip download -d $pythonDlFolderPath pmc-cli --platform=manylinux_2_17_x86_64 --only-binary=:all: --verbose + displayName: 'Download pmc-cli package' + 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' + $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 + foreach ($file in $packageFiles) + { + Write-Verbose -Verbose "copying file: $($file.FullName)" + Copy-Item -Path $($file.FullName) -Destination $packagesFolder -Verbose + } + + $packagesTarGzDestination = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath 'packages.tar.gz' + tar -czvf $packagesTarGzDestination -C $packagesFolder . + displayName: 'Copy signed .deb and .rpm packages to .tar.gz to pass as a file var to shell extension' + env: + ob_restore_phase: true + + - pwsh: | + $pathToPMCMetadataFile = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath 'pmcMetadata.json' + + $metadata = Get-Content -Path "$(repoRoot)/tools/metadata.json" -Raw | ConvertFrom-Json + $metadataHash = @{} + $skipPublishValue = '${{ parameters.skipPublish }}' + $metadataHash["ReleaseTag"] = '$(OutputReleaseTag.ReleaseTag)' + $metadataHash["LTS"] = $metadata.LTSRelease.Latest + $metadataHash["ForProduction"] = $true + $metadataHash["SkipPublish"] = [System.Convert]::ToBoolean($skipPublishValue) + + $metadataHash | ConvertTo-Json | Out-File $pathToPMCMetadataFile + + $mappingFilePath = Join-Path -Path '$(repoRoot)/tools/packages.microsoft.com' -ChildPath 'mapping.json' + $mappingFilePathExists = Test-Path $mappingFilePath + $mappingFileEV2Path = Join-Path -Path '$(ev2ParametersFolder)' -ChildPath "mapping.json" + Write-Verbose -Verbose "Copy mapping.json file at: $mappingFilePath which exists: $mappingFilePathExists to: $mappingFileEV2Path" + Copy-Item -Path $mappingFilePath -Destination $mappingFileEV2Path + displayName: 'Create pmcScriptMetadata.json and mapping.json file' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'RolloutSpec.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.RolloutMetadata.Notification.Email.To = '$(PmcEV2SupportEmail)' + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 4 | Out-File $pathToJsonFile + displayName: 'Replace values in RolloutSpecPath.json' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'UploadLinux.Rollout.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + + $identityString = "/subscriptions/$(PmcSubscription)/resourcegroups/$(PmcResourceGroup)/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$(PmcMIName)" + $content.shellExtensions.launch.identity.userAssignedIdentities[0] = $identityString + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 6 | Out-File $pathToJsonFile + displayName: 'Replace values in UploadLinux.Rollout.json file' + env: + ob_restore_phase: true + + - pwsh: | + $pathToJsonFile = Join-Path -Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'ServiceModel.json' + $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json + $content.ServiceResourceGroups[0].AzureResourceGroupName = '$(PmcResourceGroup)' + $content.ServiceResourceGroups[0].AzureSubscriptionId = '$(PmcSubscription)' + + Remove-Item -Path $pathToJsonFile + $content | ConvertTo-Json -Depth 9 | Out-File $pathToJsonFile + displayName: 'Replace values in ServiceModel.json' + env: + ob_restore_phase: true + + - pwsh: | + $settingFilePath = Join-Path '$(ev2ServiceGroupRootFolder)/Shell/Run' -ChildPath 'settings.toml' + New-Item -Path $settingFilePath -ItemType File + $pmcMIClientID = '$(PmcMIClientID)' + $pmcEndpoint = '$(PmcEndpointUrl)' + + Add-Content -Path $settingFilePath -Value "[default]" + Add-Content -Path $settingFilePath -Value "base_url = `"$pmcEndpoint`"" + Add-Content -Path $settingFilePath -Value "auth_type = `"msi`"" + Add-Content -Path $settingFilePath -Value "client_id = `"$pmcMIClientID`"" + displayName: 'Create settings.toml file with MI clientId populated' + env: + ob_restore_phase: true + + - task: onebranch.pipeline.signing@1 + inputs: + command: 'sign' + signing_profile: external_distribution + 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' + $pathToRunTarFile = Join-Path $srcPath -ChildPath "Run.tar" + tar -cvf $pathToRunTarFile -C $srcPath ./Run + displayName: 'Create archive for the shell extension' + + - task: CopyFiles@2 + inputs: + SourceFolder: '$(repoRoot)/.pipelines' + Contents: 'EV2Specs/**' + TargetFolder: $(ob_outputDirectory) diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml new file mode 100644 index 00000000000..d5454845211 --- /dev/null +++ b/.pipelines/templates/release-publish-pmc.yml @@ -0,0 +1,37 @@ +stages: +- stage: 'Prod_Release' + displayName: 'Deploy packages to PMC with EV2' + dependsOn: + - PrepForEV2 + variables: + - name: ob_release_environment + value: "Production" + - name: repoRoot + value: $(Build.SourcesDirectory) + jobs: + - job: Prod_ReleaseJob + displayName: Publish to PMC + pool: + type: release + + steps: + - task: DownloadPipelineArtifact@2 + inputs: + targetPath: '$(Pipeline.Workspace)' + artifact: drop_PrepForEV2_CopyEv2FilesToArtifact + displayName: 'Download drop_PrepForEV2_CopyEv2FilesToArtifact artifact that has all files needed' + + - 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' diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml new file mode 100644 index 00000000000..9bfa7b870d4 --- /dev/null +++ b/.pipelines/templates/release-symbols.yml @@ -0,0 +1,91 @@ +parameters: + - name: skipPublish + default: false + type: boolean + +jobs: +- job: PublishSymbols + displayName: Publish Symbols + condition: succeeded() + pool: + type: windows + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - 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 + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: release-SetReleaseTagandContainerName.yml + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_x64_release + patterns: 'symbols.zip' + displayName: Download winx64 + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_x86_release + patterns: 'symbols.zip' + displayName: Download winx86 + + - download: CoOrdinatedBuildPipeline + artifact: drop_windows_build_windows_arm64_release + patterns: 'symbols.zip' + displayName: Download winx64 + + - pwsh: | + Write-Verbose -Verbose "Enumerating $(Pipeline.Workspace)\CoOrdinatedBuildPipeline" + $downloadedArtifacts = Get-ChildItem -Path "$(Pipeline.Workspace)\CoOrdinatedBuildPipeline" -Recurse -Filter 'symbols.zip' + $downloadedArtifacts + $expandedRoot = New-Item -Path "$(Pipeline.Workspace)/expanded" -ItemType Directory -Verbose + $symbolsRoot = New-Item -Path "$(Pipeline.Workspace)/symbols" -ItemType Directory -Verbose + + $downloadedArtifacts | ForEach-Object { + $folderName = (Get-Item (Split-Path $_.FullName)).Name + Write-Verbose -Verbose "Expanding $($_.FullName) to $expandedRoot/$folderName/$($_.BaseName)" + $destFolder = New-Item -Path "$expandedRoot/$folderName/$($_.BaseName)/" -ItemType Directory -Verbose + Expand-Archive -Path $_.FullName -DestinationPath $destFolder -Force + + $symbolsToPublish = New-Item -Path "$symbolsRoot/$folderName/$($_.BaseName)" -ItemType Directory -Verbose + + Get-ChildItem -Path $destFolder -Recurse -Filter '*.pdb' | ForEach-Object { + Copy-Item -Path $_.FullName -Destination $symbolsToPublish -Verbose + } + } + + Write-Verbose -Verbose "Enumerating $symbolsRoot" + Get-ChildItem -Path $symbolsRoot -Recurse + $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$symbolsRoot" + Write-Verbose -Message "$vstsCommandString" -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Expand and capture symbols folders + + - task: PublishSymbols@2 + inputs: + symbolsFolder: '$(SymbolsPath)' + searchPattern: '**/*.pdb' + indexSources: false + publishSymbols: true + symbolServerType: teamServices + detailedLog: true diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml new file mode 100644 index 00000000000..c8693228847 --- /dev/null +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -0,0 +1,141 @@ +parameters: + - name: skipPublish + default: false + type: boolean + +jobs: +- job: BuildInfoPublish + displayName: Publish BuildInfo + condition: succeeded() + pool: + name: PowerShell1ES + type: windows + isCustom: true + demands: + - ImageOverride -equals PSMMS2019-Secure + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - group: 'Azure Blob variable group' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - 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 + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: release-SetReleaseTagandContainerName.yml + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - download: PSPackagesOfficial + artifact: BuildInfoJson + displayName: Download build info artifact + + - pwsh: | + $toolsDirectory = '$(Build.SourcesDirectory)/tools' + Import-Module "$toolsDirectory/ci.psm1" + $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" + $fileName = Split-Path $jsonFile -Leaf + + $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 + $stableRelease = $metadata.StableRelease.Latest + $ltsRelease = $metadata.LTSRelease.Latest + + Write-Verbose -Verbose "Writing $jsonFile contents:" + $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw + Write-Verbose -Verbose $buildInfoJsonContent + + $buildInfo = $buildInfoJsonContent | ConvertFrom-Json + $buildInfo.ReleaseDate = $dateTime + + $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 + } else { + Set-BuildVariable -Name CopyMainBuildInfo -Value NO + } + + Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile + + ## Create 'lts.json' if it's the latest stable and also a LTS release. + + if ($fileName -eq "stable.json") { + 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 + } else { + Set-BuildVariable -Name CopyLTSBuildInfo -Value NO + } + + $releaseTag = $buildInfo.ReleaseTag + $version = $releaseTag -replace '^v' + $semVersion = [System.Management.Automation.SemanticVersion] $version + + $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 + } + displayName: Create json files + + - task: AzurePowerShell@5 + displayName: Upload buildjson to blob + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $containerName = '$web' + $storageAccount = '$(PSInfraStorageAccount)' + $prefix = "buildinfo" + + $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount + + if ($env:CopyMainBuildInfo -eq 'YES') { + $jsonFile = "$env:BuildInfoJsonFile" + $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" + $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" + $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')) diff --git a/.pipelines/templates/release-validate-fxdpackages.yml b/.pipelines/templates/release-validate-fxdpackages.yml new file mode 100644 index 00000000000..af20d93e75c --- /dev/null +++ b/.pipelines/templates/release-validate-fxdpackages.yml @@ -0,0 +1,118 @@ +parameters: + - name: jobName + type: string + default: "" + - name: displayName + type: string + default: "" + - name: jobtype + type: string + default: "" + - name: artifactName + type: string + default: "" + - name: packageNamePattern + type: string + default: "" + - name: arm64 + type: string + default: "no" + - name: enableCredScan + type: boolean + default: true + +jobs: +- job: ${{ parameters.jobName }} + displayName: ${{ parameters.displayName }} + variables: + - group: DotNetPrivateBuildAccess + - name: artifactName + value: ${{ parameters.artifactName }} + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - 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_sdl_credscan_enabled + value: ${{ parameters.enableCredScan }} + + pool: + type: ${{ parameters.jobtype }} + ${{ if eq(parameters.arm64, 'yes') }}: + hostArchitecture: arm64 + + steps: + - checkout: self + clean: true + + - template: release-SetReleaseTagandContainerName.yml@self + + - download: PSPackagesOfficial + artifact: "${{ parameters.artifactName }}" + displayName: Download fxd artifact + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - pwsh: | + $artifactName = '$(artifactName)' + Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" -Recurse + displayName: 'Capture Downloaded Artifacts' + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $artifactName = '$(artifactName)' + $rootPath = "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" + + $destPath = New-Item "$rootPath/fxd" -ItemType Directory + $packageNameFilter = '${{ parameters.packageNamePattern }}' + + if ($packageNameFilter.EndsWith('tar.gz')) { + $package = @(Get-ChildItem -Path "$rootPath/*.tar.gz") + Write-Verbose -Verbose "Package: $package" + if ($package.Count -ne 1) { + throw 'Only 1 package was expected.' + } + tar -xvf $package.FullName -C $destPath + } + else { + $package = @(Get-ChildItem -Path "$rootPath/*.zip") + Write-Verbose -Verbose "Package: $package" + if ($package.Count -ne 1) { + throw 'Only 1 package was expected.' + } + Expand-Archive -Path $package.FullName -Destination "$destPath" -Verbose + } + displayName: Expand fxd package + + - pwsh: | + $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + $artifactName = '$(artifactName)' + $rootPath = "$(Pipeline.Workspace)/PSPackagesOfficial/$artifactName" + + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + Import-Module "$repoRoot/build.psm1" -Force + Find-Dotnet -SetDotnetRoot + Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" + Write-Verbose -Verbose "Check dotnet install" + dotnet --info + Write-Verbose -Verbose "Start test" + $packageNameFilter = '${{ parameters.packageNamePattern }}' + $pwshExeName = if ($packageNameFilter.EndsWith('tar.gz')) { 'pwsh' } else { 'pwsh.exe' } + $pwshPath = Join-Path "$rootPath/fxd" $pwshExeName + + if ($IsLinux) { + chmod u+x $pwshPath + } + + $pwshDllPath = Join-Path "$rootPath/fxd" 'pwsh.dll' + + $actualOutput = & dotnet $pwshDllPath -c 'Start-ThreadJob -ScriptBlock { "1" } | Wait-Job | Receive-Job' + Write-Verbose -Verbose "Actual output: $actualOutput" + if ($actualOutput -ne 1) { + throw "Actual output is not as expected" + } + displayName: Test package diff --git a/.pipelines/templates/release-validate-globaltools.yml b/.pipelines/templates/release-validate-globaltools.yml new file mode 100644 index 00000000000..abe46378758 --- /dev/null +++ b/.pipelines/templates/release-validate-globaltools.yml @@ -0,0 +1,121 @@ +parameters: + jobName: "" + displayName: "" + jobtype: "windows" + globalToolExeName: 'pwsh.exe' + globalToolPackageName: 'PowerShell.Windows.x64' + + +jobs: +- job: ${{ parameters.jobName }} + displayName: ${{ parameters.displayName }} + pool: + type: ${{ parameters.jobtype }} + variables: + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - 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 + clean: true + + - template: release-SetReleaseTagandContainerName.yml@self + + - download: PSPackagesOfficial + artifact: drop_nupkg_build_nupkg + displayName: Download nupkgs + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - pwsh: | + Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse + displayName: 'Capture Downloaded Artifacts' + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + + $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName + + Write-Verbose -Verbose "dotnet tool list -g" + dotnet tool list -g + + $packageName = '${{ parameters.globalToolPackageName }}' + Write-Verbose -Verbose "Installing $packageName" + + dotnet tool install --add-source "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/drop_nupkg_build_nupkg" --tool-path $toolPath --version '$(OutputVersion.Version)' $packageName + + Get-ChildItem -Path $toolPath + + displayName: Install global tool + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - pwsh: | + $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" + + if (-not (Test-Path $toolPath)) + { + throw "Tool is not installed at $toolPath" + } + else + { + Write-Verbose -Verbose "Tool found at: $toolPath" + } + displayName: Validate tool is installed + + - pwsh: | + $repoRoot = "$(Build.SourcesDirectory)/PowerShell" + Import-Module "$repoRoot/build.psm1" -Force + + $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } + + $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" + + $source = (get-command -Type Application -Name dotnet | Select-Object -First 1 -ExpandProperty source) + $target = (Get-ChildItem $source).target + + # If we find a symbolic link for dotnet, then we need to split the filename off the target. + if ($target) { + Write-Verbose -Verbose "Splitting target: $target" + $target = Split-Path $target + } + + Write-Verbose -Verbose "target is set as $target" + + $env:DOTNET_ROOT = (resolve-path -Path (Join-Path (split-path $source) $target)).ProviderPath + Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" + Get-ChildItem $env:DOTNET_ROOT + + $versionFound = & $toolPath -c '$PSVersionTable.PSVersion.ToString()' + + if ( '$(OutputVersion.Version)' -ne $versionFound) + { + throw "Expected version of global tool not found. Installed version is $versionFound" + } + else + { + write-verbose -verbose "Found expected version: $versionFound" + } + + $dateYear = & $toolPath -c '(Get-Date).Year' + + if ( $dateYear -ne [DateTime]::Now.Year) + { + throw "Get-Date returned incorrect year: $dateYear" + } + else + { + write-verbose -verbose "Got expected year: $dateYear" + } + displayName: Basic validation + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml new file mode 100644 index 00000000000..c717b50f289 --- /dev/null +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -0,0 +1,184 @@ +jobs: +- job: validatePackageNames + displayName: Validate Package Names + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - group: 'Azure Blob variable group' + + steps: + - checkout: self + clean: true + + - template: release-SetReleaseTagandContainerName.yml + + - pwsh: | + Get-ChildItem ENV: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - pwsh: | + $name = "{0}_{1:x}" -f '$(OutputReleaseTag.releaseTag)', (Get-Date).Ticks + Write-Host $name + Write-Host "##vso[build.updatebuildnumber]$name" + displayName: Set Release Name + + - task: AzurePowerShell@5 + displayName: Upload packages to blob + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $storageAccount = Get-AzStorageAccount -ResourceGroupName '$(StorageResourceGroup)' -Name '$(StorageAccount)' + $ctx = $storageAccount.Context + $container = '$(OutputVersion.AzureVersion)' + + $destinationPath = '$(System.ArtifactsDirectory)' + $blobList = Get-AzStorageBlob -Container $container -Context $ctx + foreach ($blob in $blobList) { + $blobName = $blob.Name + $destinationFile = Join-Path -Path $destinationPath -ChildPath $blobName + Get-AzStorageBlobContent -Container $container -Blob $blobName -Destination $destinationFile -Context $ctx -Force + Write-Output "Downloaded $blobName to $destinationFile" + } + + - pwsh: | + Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name + displayName: Capture Artifact Listing + + - pwsh: | + $message = @() + Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.rpm | ForEach-Object { + if($_.Name -notmatch 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1.(rh|cm).(x86_64|aarch64)\.rpm') + { + $messageInstance = "$($_.Name) is not a valid package name" + $message += $messageInstance + Write-Warning $messageInstance + } + } + if($message.count -gt 0){throw ($message | out-string)} + displayName: Validate RPM package names + + - pwsh: | + $message = @() + Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.tar.gz | ForEach-Object { + if($_.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)') + { + $messageInstance = "$($_.Name) is not a valid package name" + $message += $messageInstance + Write-Warning $messageInstance + } + } + if($message.count -gt 0){throw ($message | out-string)} + displayName: Validate Tar.Gz Package Names + + - 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') + { + $messageInstance = "$($_.Name) is not a valid package name" + $message += $messageInstance + Write-Warning $messageInstance + } + } + if($message.count -gt 0){throw ($message | out-string)} + displayName: Validate PKG Package Names + + - 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}') + { + $messageInstance = "$($_.Name) is not a valid package name" + $message += $messageInstance + Write-Warning $messageInstance + } + } + + if($message.count -gt 0){throw ($message | out-string)} + displayName: Validate Zip and MSI Package Names + + - 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') + { + $messageInstance = "$($_.Name) is not a valid package name" + $message += $messageInstance + Write-Warning $messageInstance + } + } + if($message.count -gt 0){throw ($message | out-string)} + displayName: Validate Deb Package Names + +# Move to 1ES SBOM validation tool +# - job: validateBOM +# displayName: Validate Package Names +# pool: +# type: windows +# variables: +# - name: ob_outputDirectory +# value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' +# - name: ob_sdl_credscan_suppressionsFile +# value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json +# - name: ob_sdl_tsa_configFile +# value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json +# - group: 'Azure Blob variable group' + +# steps: +# - checkout: self +# clean: true + +# - pwsh: | +# Get-ChildItem ENV: | Out-String -width 9999 -Stream | write-Verbose -Verbose +# displayName: Capture environment + +# - template: release-SetReleaseTagAndContainerName.yml + +# - pwsh: | +# $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks +# Write-Host $name +# Write-Host "##vso[build.updatebuildnumber]$name" +# displayName: Set Release Name + +# - task: DownloadPipelineArtifact@2 +# inputs: +# source: specific +# project: PowerShellCore +# pipeline: '696' +# preferTriggeringPipeline: true +# runVersion: latestFromBranch +# runBranch: '$(Build.SourceBranch)' +# artifact: finalResults +# path: $(System.ArtifactsDirectory) + + +# - pwsh: | +# Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name +# displayName: Capture Artifact Listing + +# - pwsh: | +# Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 +# displayName: Install Pester +# condition: succeededOrFailed() + +# - pwsh: | +# Import-module './build.psm1' +# Import-module './tools/packaging' +# $env:PACKAGE_FOLDER = '$(System.ArtifactsDirectory)' +# $path = Join-Path -Path $pwd -ChildPath './packageReleaseTests.xml' +# $results = invoke-pester -Script './tools/packaging/releaseTests' -OutputFile $path -OutputFormat NUnitXml -PassThru +# Write-Host "##vso[results.publish type=NUnit;mergeResults=true;runTitle=Package Release Tests;publishRunAttachments=true;resultFiles=$path;]" +# if($results.TotalCount -eq 0 -or $results.FailedCount -gt 0) +# { +# throw "Package Release Tests failed" +# } +# displayName: Run packaging release tests diff --git a/.pipelines/templates/release-validate-sdk.yml b/.pipelines/templates/release-validate-sdk.yml new file mode 100644 index 00000000000..fec086aa318 --- /dev/null +++ b/.pipelines/templates/release-validate-sdk.yml @@ -0,0 +1,95 @@ +parameters: + jobName: "" + displayName: "" + poolName: "windows" + imageName: 'none' + +jobs: +- job: ${{ parameters.jobName }} + displayName: ${{ parameters.displayName }} + pool: + type: linux + isCustom: true + ${{ if eq( parameters.poolName, 'Azure Pipelines') }}: + name: ${{ parameters.poolName }} + vmImage: ${{ parameters.imageName }} + ${{ else }}: + name: ${{ parameters.poolName }} + demands: + - ImageOverride -equals ${{ parameters.imageName }} + + variables: + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - group: DotNetPrivateBuildAccess + + steps: + - checkout: self + clean: true + lfs: false + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: "$(Build.SourcesDirectory)" + + - template: release-SetReleaseTagandContainerName.yml@self + + - download: PSPackagesOfficial + artifact: drop_nupkg_build_nupkg + displayName: Download nupkgs + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment + + - pwsh: | + Get-ChildItem "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" -Recurse + displayName: 'Capture Downloaded Artifacts' + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $repoRoot = "$(Build.SourcesDirectory)" + + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + + $localLocation = "$(Pipeline.Workspace)/PSPackagesOfficial/drop_nupkg_build_nupkg" + $xmlElement = @" + + + + "@ + + $releaseVersion = '$(OutputVersion.Version)' + + Write-Verbose -Message "Release Version: $releaseVersion" -Verbose + + Set-Location -Path $repoRoot/test/hosting + + Get-ChildItem + + ## register the packages download directory in the nuget file + $nugetPath = './NuGet.Config' + if(!(test-path $nugetPath)) { + $nugetPath = "$repoRoot/nuget.config" + } + Write-Verbose -Verbose "nugetPath: $nugetPath" + $nugetConfigContent = Get-Content $nugetPath -Raw + $updateNugetContent = $nugetConfigContent.Replace("", $xmlElement) + + $updateNugetContent | Out-File $nugetPath -Encoding ascii + + Get-Content $nugetPath + + dotnet --info + dotnet restore + dotnet test /property:RELEASE_VERSION=$releaseVersion --test-adapter-path:. "--logger:xunit;LogFilePath=$(System.DefaultWorkingDirectory)/test-hosting.xml" + displayName: Restore and execute tests + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + + - task: PublishTestResults@2 + displayName: 'Publish Test Results **\test-hosting.xml' + inputs: + testResultsFormat: XUnit + testResultsFiles: '**\test-hosting.xml' 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/tools/releaseBuild/azureDevOps/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml similarity index 86% rename from tools/releaseBuild/azureDevOps/templates/shouldSign.yml rename to .pipelines/templates/shouldSign.yml index e3c38cb29d5..551297f3aaa 100644 --- a/tools/releaseBuild/azureDevOps/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -1,29 +1,30 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - powershell: | $shouldSign = $true $authenticodeCert = 'CP-230012' $msixCert = 'CP-230012' - if($env:IS_DAILY -eq 'true') { $authenticodeCert = 'CP-460906' } - if($env:SKIP_SIGNING -eq 'Yes') { $shouldSign = $false } - $vstsCommandString = "vso[task.setvariable variable=SHOULD_SIGN]$($shouldSign.ToString().ToLowerInvariant())" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - $vstsCommandString = "vso[task.setvariable variable=MSIX_CERT]$($msixCert)" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - $vstsCommandString = "vso[task.setvariable variable=AUTHENTICODE_CERT]$($authenticodeCert)" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" - displayName: 'Set SHOULD_SIGN Variable' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/step/finalize.yml b/.pipelines/templates/step/finalize.yml new file mode 100644 index 00000000000..78e0341c829 --- /dev/null +++ b/.pipelines/templates/step/finalize.yml @@ -0,0 +1,6 @@ +# This was used before migrating to OneBranch to deal with one of the SDL taks from failing with a warning instead of an error. +steps: +- pwsh: | + throw "Jobs with an Issue will not work for release. Please fix the issue and try again." + displayName: Check for SucceededWithIssues + condition: eq(variables['Agent.JobStatus'],'SucceededWithIssues') diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml new file mode 100644 index 00000000000..751c9d5a53b --- /dev/null +++ b/.pipelines/templates/testartifacts.yml @@ -0,0 +1,138 @@ +jobs: +- job: build_testartifacts_win + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - group: DotNetPrivateBuildAccess + - 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 + - name: ob_sdl_codeSignValidation_excludes + value: '-|**\*.ps1;-|**\*.psm1;-|**\*.ps1xml;-|**\*.psd1;-|**\*.exe;-|**\*.dll;-|**\*.cdxml' + + displayName: Build windows test artifacts + condition: succeeded() + pool: + type: windows + steps: + - checkout: self + clean: true + 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: $(RepoRoot) + ob_restore_phase: true + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force + Import-Module $(Build.SourcesDirectory)/PowerShell/build.psm1 + function BuildTestPackage([string] $runtime) + { + Write-Verbose -Verbose "Starting to build package for $runtime" + New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime + if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) + { + throw "Test Package was not found at: $(System.ArtifactsDirectory)" + } + switch ($runtime) + { + win7-x64 { $packageName = "TestPackage-win-x64.zip" } + win7-x86 { $packageName = "TestPackage-win-x86.zip" } + win-arm64 { $packageName = "TestPackage-win-arm64.zip" } + } + Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName + ## Write-Host "##vso[artifact.upload containerfolder=testArtifacts;artifactname=testArtifacts]$(System.ArtifactsDirectory)/$packageName" + + Copy-Item -Path $(System.ArtifactsDirectory)/$packageName -Destination $(ob_outputDirectory) -Force -Verbose + } + BuildTestPackage -runtime win7-x64 + BuildTestPackage -runtime win7-x86 + BuildTestPackage -runtime win-arm64 + displayName: Build test package and upload + retryCountOnTaskFailure: 1 + env: + ob_restore_phase: true + + - pwsh: | + Write-Host "This doesn't do anything but make the build phase run." + displayName: Dummy build task + + +- job: build_testartifacts_nonwin + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - group: DotNetPrivateBuildAccess + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + displayName: Build non-windows test artifacts + condition: succeeded() + pool: + type: linux + steps: + - checkout: self + clean: true + 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 + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + New-Item -Path '$(ob_outputDirectory)' -ItemType Directory -Force + Import-Module $(Build.SourcesDirectory)/PowerShell/build.psm1 + function BuildTestPackage([string] $runtime) + { + Write-Verbose -Verbose "Starting to build package for $runtime" + New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime + if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) + { + throw "Test Package was not found at: $(System.ArtifactsDirectory)" + } + switch ($runtime) + { + linux-x64 { $packageName = "TestPackage-linux-x64.zip" } + linux-arm { $packageName = "TestPackage-linux-arm.zip" } + linux-arm64 { $packageName = "TestPackage-linux-arm64.zip" } + osx-x64 { $packageName = "TestPackage-macOS.zip" } + linux-musl-x64 { $packageName = "TestPackage-alpine-x64.zip"} + } + Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName + Copy-Item -Path $(System.ArtifactsDirectory)/$packageName -Destination $(ob_outputDirectory) -Force -Verbose + } + BuildTestPackage -runtime linux-x64 + BuildTestPackage -runtime linux-arm + BuildTestPackage -runtime linux-arm64 + BuildTestPackage -runtime osx-x64 + BuildTestPackage -runtime linux-musl-x64 + displayName: Build test package and upload + retryCountOnTaskFailure: 1 + env: + ob_restore_phase: true + + - pwsh: | + Write-Host "This doesn't do anything but make the build phase run." + displayName: Dummy build task diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml new file mode 100644 index 00000000000..9ee5cb81655 --- /dev/null +++ b/.pipelines/templates/uploadToAzure.yml @@ -0,0 +1,433 @@ +jobs: +- job: upload_packages + displayName: Upload packages + condition: succeeded() + pool: + type: windows + variables: + - name: ob_sdl_sbom_enabled + value: true + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - 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: ob_sdl_codeql_compiled_enabled + value: false + - group: 'Azure Blob variable group' + + steps: + - checkout: self + clean: true + 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: no + + - template: /.pipelines/templates/release-SetReleaseTagandContainerName.yml@self + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: 'Capture Environment Variables' + + - pwsh: | + New-Item -Path '$(Build.ArtifactStagingDirectory)/downloads' -ItemType Directory -Force + displayName: Create downloads directory + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_deb + itemPattern: '**/*.deb' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download deb package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_fxdependent + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux fxd package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_mariner_arm64 + itemPattern: '**/*.rpm' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux mariner arm64 package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_mariner_x64 + itemPattern: '**/*.rpm' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux mariner x64 package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_minSize + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux minSize package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_rpm + itemPattern: '**/*.rpm' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux rpm package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_tar + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux tar package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_tar_alpine + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux alpine tar package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_tar_alpine_fxd + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux alpine fxd tar package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_tar_arm + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux arm32 tar package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_linux_package_tar_arm64 + itemPattern: '**/*.tar.gz' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download linux arm64 tar package + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_nupkg_build_nupkg + itemPattern: '**/*.nupkg' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download nupkgs + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_arm64 + itemPattern: | + **/*.msi + **/*.msix + **/*.zip + **/*.exe + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows arm64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_fxdependent + itemPattern: '**/*.zip' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows fxdependent packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_fxdependentWinDesktop + itemPattern: '**/*.zip' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows fxdependentWinDesktop packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_minsize + itemPattern: '**/*.zip' + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows minsize packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_x64 + itemPattern: | + **/*.msi + **/*.msix + **/*.zip + **/*.exe + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows x64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_windows_package_package_win_x86 + itemPattern: | + **/*.msi + **/*.msix + **/*.zip + **/*.exe + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download windows x86 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: macos-pkgs + itemPattern: | + **/*.tar.gz + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download macos tar packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_mac_package_sign_package_macos_arm64 + itemPattern: | + **/*.pkg + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download macos arm packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_mac_package_sign_package_macos_x64 + itemPattern: | + **/*.pkg + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download macos x64 packages + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_msixbundle_CreateMSIXBundle + itemPattern: | + **/*.msixbundle + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download MSIXBundle + + - pwsh: | + Get-ChildItem '$(Build.ArtifactStagingDirectory)/downloads' | Select-Object -ExpandProperty FullName + displayName: 'Capture downloads' + + - 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'} | + 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' } | + Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose + displayName: Copy downloads to Artifacts + + - pwsh: | + # Create output directory for packages which have been uploaded to blob storage + New-Item -Path $(Build.ArtifactStagingDirectory)/uploaded -ItemType Directory -Force + displayName: Create output directory for packages + + - task: AzurePowerShell@5 + displayName: Upload packages to blob + inputs: + azureSubscription: az-blob-cicd-infra + scriptType: inlineScript + azurePowerShellVersion: LatestVersion + pwsh: true + inline: | + $downloadsDirectory = '$(Build.ArtifactStagingDirectory)/downloads' + $uploadedDirectory = '$(Build.ArtifactStagingDirectory)/uploaded' + $storageAccountName = "pscoretestdata" + $containerName = $env:AZUREVERSION + + Write-Verbose -Verbose "Uploading packages to blob storage account: $storageAccountName container: $containerName" + + $context = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount + + # Create the blob container if it doesn't exist + $containerExists = Get-AzStorageContainer -Name $containerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + $null = New-AzStorageContainer -Name $containerName -Context $context + Write-Host "Blob container $containerName created successfully." + } + + $gcPackages = Get-ChildItem -Path $downloadsDirectory -Filter "powershell*gc.*" + Write-Verbose -Verbose "gc files to upload." + $gcPackages | Write-Verbose -Verbose + $gcContainerName = "$containerName-gc" + # Create the blob container if it doesn't exist + $containerExists = Get-AzStorageContainer -Name $gcContainerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + $null = New-AzStorageContainer -Name $gcContainerName -Context $context + Write-Host "Blob container $gcContainerName created successfully." + } + + $gcPackages | ForEach-Object { + $blobName = "${_.Name}" + Write-Verbose -Verbose "Uploading $($_.FullName) to $gcContainerName/$blobName" + $null = Set-AzStorageBlobContent -File $_.FullName -Container $gcContainerName -Blob $blobName -Context $context + # Move to folder to we wont upload again + Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force -Verbose + } + + $nupkgFiles = Get-ChildItem -Path $downloadsDirectory -Filter "*.nupkg" | Where-Object { $_.Name -notlike "powershell*.nupkg" } + + # create a SHA512 checksum file for each nupkg files + + $checksums = $nupkgFiles | + ForEach-Object { + Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" + $packageName = $_.Name + $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() + # the '*' before the packagename signifies it is a binary + "$hash *$packageName" + } + + $checksums | Out-File -FilePath "$downloadsDirectory\SHA512SUMS" -Force + $fileContent = Get-Content -Path "$downloadsDirectory\SHA512SUMS" -Raw | Out-String + Write-Verbose -Verbose -Message $fileContent + + Write-Verbose -Verbose "nupkg files to upload." + $nupkgFiles += (Get-Item "$downloadsDirectory\SHA512SUMS") + $nupkgFiles | Write-Verbose -Verbose + $nugetContainerName = "$containerName-nuget" + # Create the blob container if it doesn't exist + $containerExists = Get-AzStorageContainer -Name $nugetContainerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + $null = New-AzStorageContainer -Name $nugetContainerName -Context $context + Write-Host "Blob container $nugetContainerName created successfully." + } + + $nupkgFiles | ForEach-Object { + $blobName = $_.Name + Write-Verbose -Verbose "Uploading $($_.FullName) to $nugetContainerName/$blobName" + $null = Set-AzStorageBlobContent -File $_.FullName -Container $nugetContainerName -Blob $blobName -Context $context + # Move to folder to we wont upload again + Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force -Verbose + } + + $globaltoolFiles = Get-ChildItem -Path $downloadsDirectory -Filter "powershell*.nupkg" + # create a SHA512 checksum file for each nupkg files + + $checksums = $globaltoolFiles | + ForEach-Object { + Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" + $packageName = $_.Name + $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() + # the '*' before the packagename signifies it is a binary + "$hash *$packageName" + } + + New-Item -Path "$downloadsDirectory\globaltool" -ItemType Directory -Force + $checksums | Out-File -FilePath "$downloadsDirectory\globaltool\SHA512SUMS" -Force + $fileContent = Get-Content -Path "$downloadsDirectory\globaltool\SHA512SUMS" -Raw | Out-String + Write-Verbose -Verbose -Message $fileContent + + Write-Verbose -Verbose "globaltool files to upload." + $globaltoolFiles += Get-Item ("$downloadsDirectory\globaltool\SHA512SUMS") + $globaltoolFiles | Write-Verbose -Verbose + $globaltoolContainerName = "$containerName-nuget" + $globaltoolFiles | ForEach-Object { + $blobName = "globaltool/" + $_.Name + $globaltoolContainerName = "$containerName-nuget" + Write-Verbose -Verbose "Uploading $($_.FullName) to $globaltoolContainerName/$blobName" + $null = Set-AzStorageBlobContent -File $_.FullName -Container $globaltoolContainerName -Blob $blobName -Context $context + # Move to folder to we wont upload again + Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force + } + + # To use -Include parameter, we need to use \* to get all files + $privateFiles = Get-ChildItem -Path $downloadsDirectory\* -Include @("*.msix", "*.exe") + Write-Verbose -Verbose "private files to upload." + $privateFiles | Write-Verbose -Verbose + $privateContainerName = "$containerName-private" + # Create the blob container if it doesn't exist + $containerExists = Get-AzStorageContainer -Name $privateContainerName -Context $context -ErrorAction SilentlyContinue + if (-not $containerExists) { + $null = New-AzStorageContainer -Name $privateContainerName -Context $context + Write-Host "Blob container $privateContainerName created successfully." + } + + $privateFiles | ForEach-Object { + $blobName = $_.Name + Write-Verbose -Verbose "Uploading $($_.FullName) to $privateContainerName/$blobName" + $null = Set-AzStorageBlobContent -File $_.FullName -Container $privateContainerName -Blob $blobName -Context $context + # Move to folder to we wont upload again + Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force -Verbose + } + + # 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") + Write-Verbose -Verbose "files to upload." + $files | Write-Verbose -Verbose + + $files | ForEach-Object { + $blobName = $_.Name + Write-Verbose -Verbose "Uploading $($_.FullName) to $containerName/$blobName" + $null = Set-AzStorageBlobContent -File $_.FullName -Container $containerName -Blob $blobName -Context $context + Write-Host "File $blobName uploaded to $containerName container." + Move-Item -Path $_.FullName -Destination $uploadedDirectory -Force -Verbose + } + + $msixbundleFiles = Get-ChildItem -Path $downloadsDirectory -Filter "*.msixbundle" + + $containerName = '$(OutputVersion.AzureVersion)-private' + $storageAccount = '$(StorageAccount)' + + $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount + + if ($msixbundleFiles) { + $bundleFile = $msixbundleFiles[0].FullName + $blobName = $msixbundleFiles[0].Name + + $existing = Get-AzStorageBlob -Container $containerName -Blob $blobName -Context $storageContext -ErrorAction Ignore + if ($existing) { + Write-Verbose -Verbose "MSIX bundle already exists at '$storageAccount/$containerName/$blobName', removing first." + $existing | Remove-AzStorageBlob -ErrorAction Stop -Verbose + } + + Write-Verbose -Verbose "Uploading $bundleFile to $containerName/$blobName" + Set-AzStorageBlobContent -File $bundleFile -Container $containerName -Blob $blobName -Context $storageContext -Force + } else { + throw "MSIXBundle not found in $downloadsDirectory" + } diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml new file mode 100644 index 00000000000..f944639a908 --- /dev/null +++ b/.pipelines/templates/variable/release-shared.yml @@ -0,0 +1,42 @@ +parameters: + - name: REPOROOT + type: string + default: $(Build.SourcesDirectory)\PowerShell + - name: SBOM + type: boolean + default: false + - name: RELEASETAG + type: string + default: 'Not Initialized' + - name: VERSION + type: string + default: 'Not Initialized' + +variables: + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_sbom_enabled + value: ${{ parameters.SBOM }} + - name: runCodesignValidationInjection + value: false + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - group: 'mscodehub-code-read-akv' + - group: 'Azure Blob variable group' + - group: 'GitHubTokens' + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_binskim_enabled + value: false + - name: ob_sdl_tsa_configFile + value: ${{ parameters.REPOROOT }}\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: ${{ parameters.REPOROOT }}\.config\suppress.json + - name: ob_sdl_codeql_compiled_enabled + value: false + - name: ReleaseTag + value: ${{ parameters.RELEASETAG }} + - name: Version + value: ${{ parameters.VERSION }} diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml new file mode 100644 index 00000000000..cab00eb68bc --- /dev/null +++ b/.pipelines/templates/windows-hosted-build.yml @@ -0,0 +1,323 @@ +parameters: + Architecture: 'x64' + BuildConfiguration: 'release' + JobName: 'build_windows' + +jobs: +- job: build_windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} + displayName: Build_Windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} + condition: succeeded() + pool: + type: windows + variables: + - name: runCodesignValidationInjection + value: false + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_codeSignValidation_enabled + value: false + - 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: Architecture + value: ${{ parameters.Architecture }} + - name: BuildConfiguration + value: ${{ parameters.BuildConfiguration }} + - name: ob_sdl_sbom_packageName + value: 'Microsoft.Powershell.Windows.${{ parameters.Architecture }}' + - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: + - name: ob_sdl_codeql_compiled_enabled + value: true + + steps: + - checkout: self + clean: true + 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) + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: true + Language: csharp + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $runtime = switch ($env:Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + "fxdependent" { "fxdependent" } + "fxdependentWinDesktop" { "fxdependent-win-desktop" } + } + + $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 $(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 + + $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 "Verifying pdbs exist in build folder" + $pdbs = Get-ChildItem -Path $buildWithSymbolsPath -Recurse -Filter *.pdb + if ($pdbs.Count -eq 0) { + Write-Error -Message "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.zip" -Update + } + + 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. + + - pwsh: | + $runtime = switch ($env:Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + "fxdependent" { "fxdependent" } + "fxdependentWinDesktop" { "fxdependent-win-desktop" } + } + + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + Find-Dotnet + + ## Build global tool + Write-Verbose -Message "Building PowerShell global tool for Windows.x64" -Verbose + $globalToolCsProjDir = Join-Path $(PowerShellRoot) 'src' 'GlobalTools' 'PowerShell.Windows.x64' + Push-Location -Path $globalToolCsProjDir -Verbose + + $globalToolArtifactPath = Join-Path $(Build.SourcesDirectory) 'GlobalTool' + $vstsCommandString = "vso[task.setvariable variable=GlobalToolArtifactPath]${globalToolArtifactPath}" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + + if ($env:RELEASETAGVAR) { + $ReleaseTagToUse = $env:RELEASETAGVAR -Replace '^v' + } + + Write-Verbose -Verbose "Building PowerShell global tool for Windows.x64 with cmdline: dotnet publish --no-self-contained --artifacts-path $globalToolArtifactPath /property:PackageVersion=$(Version) --configuration 'Release' /property:ReleaseTag=$ReleaseTagToUse" + dotnet publish --no-self-contained --artifacts-path $globalToolArtifactPath /property:PackageVersion=$(Version) --configuration 'Release' /property:ReleaseTag=$ReleaseTagToUse + $globalToolBuildModulePath = Join-Path $globalToolArtifactPath 'publish' 'PowerShell.Windows.x64' 'release' + Pop-Location + # do this to ensure everything gets signed. + Restore-PSModuleToBuild -PublishPath $globalToolBuildModulePath + + $buildWithSymbolsPath = Get-Item -Path "$(Pipeline.Workspace)/Symbols_$(Architecture)" + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + + # Copy reference assemblies + Copy-Item -Path $refFolderPath -Destination $globalToolBuildModulePath -Recurse -Force + + Write-Verbose -Verbose "clean unnecessary files in obj directory" + $objDir = Join-Path $globalToolArtifactPath 'obj' 'PowerShell.Windows.x64' 'release' + + $filesToKeep = @("apphost.exe", "PowerShell.Windows.x64.pdb", "PowerShell.Windows.x64.dll", "project.assets.json") + + # only four files are needed in obj folder for global tool packaging + Get-ChildItem -Path $objDir -File -Recurse | + Where-Object { -not $_.PSIsContainer } | + Where-Object { $_.name -notin $filesToKeep } | + Remove-Item -Verbose + + + displayName: 'Build Winx64 Global tool' + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) + 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. + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - pwsh: | + $platform = 'windows' + $vstsCommandString = "vso[task.setvariable variable=ArtifactPlatform]$platform" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Set artifact platform + + - 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') }}: + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(GlobalToolArtifactPath)/publish/PowerShell.Windows.x64/release' + globalTool: 'true' + OfficialBuild: $(ps_official_build) + + - pwsh: | + Get-ChildItem '$(GlobalToolArtifactPath)/obj/PowerShell.Windows.x64/release' + displayName: Capture obj files + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) + + ## Now we sign couple of file from the obj folder which are needed for the global tool packaging + - task: onebranch.pipeline.signing@1 + displayName: Sign obj files + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.dll;**\*.exe' + search_root: '$(GlobalToolArtifactPath)/obj/PowerShell.Windows.x64/release' + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) + + - pwsh: | + <# The way the packaging works is a bit tricky as when it is built, we cannot add the modules that come from gallery. + We have to use dotnet pack to build the nupkg and then expand it as a zip. + After expanding we restore the signed files for the modules from the gallery. + We also delete pdbs, content and contentFiles folder which are not necessary. + 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' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $globalToolCsProjDir = Join-Path $(PowerShellRoot) 'src' 'GlobalTools' 'PowerShell.Windows.x64' + Push-Location -Path $globalToolCsProjDir -Verbose + + if ($env:RELASETAGVAR) { + $ReleaseTagToUse = $env:RELASETAGVAR -Replace '^v' + } + + Write-Verbose -Verbose "Packing PowerShell global tool for Windows.x64 with cmdline: dotnet pack --output $outputPath --no-build --artifacts-path '$(GlobalToolArtifactPath)' /property:PackageVersion=$(Version) /property:PackageIcon=Powershell_64.png /property:Version=$(Version) /property:ReleaseTag=$ReleaseTagToUse" + + dotnet pack --output $outputPath --no-build --artifacts-path '$(GlobalToolArtifactPath)' /property:PackageVersion=$(Version) /property:PackageIcon=Powershell_64.png /property:Version=$(Version) /property:ReleaseTag=$ReleaseTagToUse + + Write-Verbose -Verbose "Deleting content and contentFiles folders from the nupkg" + + $nupkgs = Get-ChildItem -Path $outputPath -Filter powershell*.nupkg + + $nupkgName = $nupkgs.Name + $newName = $nupkgName -replace '(\.nupkg)$', '.zip' + Rename-Item -Path $nupkgs.FullName -NewName $newName + + $zipPath = Get-ChildItem -Path $outputPath -Filter powershell*.zip + + # Expand zip and remove content and contentFiles folders + Expand-Archive -Path $zipPath -DestinationPath "$outputPath\temp" -Force + + $modulesToCopy = @( + 'PowerShellGet' + 'PackageManagement' + 'Microsoft.PowerShell.PSResourceGet' + 'Microsoft.PowerShell.Archive' + 'PSReadLine' + 'ThreadJob' + ) + + $sourceModulePath = Join-Path '$(GlobalToolArtifactPath)' 'publish' 'PowerShell.Windows.x64' 'release' 'Modules' + $destModulesPath = Join-Path "$outputPath" 'temp' 'tools' 'net8.0' 'any' 'modules' + + $modulesToCopy | ForEach-Object { + $modulePath = Join-Path $sourceModulePath $_ + Copy-Item -Path $modulePath -Destination $destModulesPath -Recurse -Force + } + + # Copy ref assemblies + Copy-Item '$(Pipeline.Workspace)/Symbols_$(Architecture)/ref' "$outputPath\temp\tools\net8.0\any\ref" -Recurse -Force + + $contentPath = Join-Path "$outputPath\temp" 'content' + $contentFilesPath = Join-Path "$outputPath\temp" 'contentFiles' + + Remove-Item -Path $contentPath,$contentFilesPath -Recurse -Force + + # remove PDBs to reduce the size of the nupkg + Remove-Item -Path "$outputPath\temp\tools\net8.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' 'net8.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 + + Remove-Item -Path "$outputPath\temp" -Recurse -Force + Remove-Item -Path $zipPath -Force + + if (-not (Test-Path "$outputPath\powershell.windows.x64.*.nupkg")) { + throw "Global tool package not found at $outputPath" + } + displayName: 'Pack Windows.x64 global tool' + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) + + - task: onebranch.pipeline.signing@1 + displayName: Sign nupkg files + inputs: + command: 'sign' + cp_code: 'CP-401405' + files_to_sign: '**\*.nupkg' + search_root: '$(ob_outputDirectory)\globaltool' + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) + + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000000..222861c3415 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "useTabs": false +} diff --git a/.vsts-ci/linux-daily.yml b/.vsts-ci/linux-daily.yml index 82705e8b5ce..c1dd96fd0b4 100644 --- a/.vsts-ci/linux-daily.yml +++ b/.vsts-ci/linux-daily.yml @@ -54,7 +54,7 @@ stages: steps: - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml new file mode 100644 index 00000000000..6286a03fb52 --- /dev/null +++ b/.vsts-ci/linux-internal.yml @@ -0,0 +1,116 @@ +# Pipeline to run Linux CI internally +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/* + - .github/workflows/* + - .dependabot/config.yml + - .pipelines/* + - test/perf/* +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - .dependabot/config.yml + - .github/ISSUE_TEMPLATE/* + - .github/workflows/* + - .vsts-ci/misc-analysis.yml + - .vsts-ci/windows.yml + - .vsts-ci/windows/* + - tools/cgmanifest.json + - LICENSE.txt + - test/common/markdown/* + - test/perf/* + - tools/releaseBuild/* + - tools/install* + - tools/releaseBuild/azureDevOps/templates/* + - README.md + - .spelling + - .pipelines/* + +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 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + +resources: + repositories: + - repository: Docker + type: github + endpoint: PowerShell + name: PowerShell/PowerShell-Docker + ref: master + +stages: +- stage: BuildLinuxStage + displayName: Build for Linux + jobs: + - template: templates/ci-build.yml + parameters: + pool: ubuntu-20.04 + jobName: linux_build + displayName: linux Build + +- stage: TestUbuntu + displayName: Test for Ubuntu + dependsOn: [BuildLinuxStage] + jobs: + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: CI + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: CI + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: Others + + - template: templates/nix-test.yml + parameters: + name: Ubuntu + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: Others + + - template: templates/verify-xunit.yml + parameters: + pool: ubuntu-20.04 + +- stage: PackageLinux + displayName: Package Linux + dependsOn: ["BuildLinuxStage"] + jobs: + - template: linux/templates/packaging.yml + parameters: + pool: ubuntu-20.04 diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index 57c60bc25a7..06bd34ab9f1 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -23,6 +23,7 @@ trigger: - .vsts-ci/misc-analysis.yml - .github/ISSUE_TEMPLATE/* - .dependabot/config.yml + - .pipelines/* - test/perf/* pr: branches: @@ -32,22 +33,16 @@ pr: - feature* paths: include: - - '*' - exclude: - - .dependabot/config.yml - - .github/ISSUE_TEMPLATE/* - - .vsts-ci/misc-analysis.yml - - .vsts-ci/windows.yml - - .vsts-ci/windows/* - - tools/cgmanifest.json - - LICENSE.txt - - test/common/markdown/* - - test/perf/* - - tools/releaseBuild/* - - tools/install* - - tools/releaseBuild/azureDevOps/templates/* - - README.md - - .spelling + - .vsts-ci/linux.yml + - .vsts-ci/linux/templates/packaging.yml + - assets/manpage/* + - build.psm1 + - global.json + - nuget.config + - PowerShell.Common.props + - src/*.csproj + - tools/ci.psm1 + - tools/packaging/* variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -71,101 +66,14 @@ stages: jobs: - template: templates/ci-build.yml parameters: - pool: ubuntu-20.04 + pool: ubuntu-latest jobName: linux_build displayName: linux Build -- stage: TestUbuntu - displayName: Test for Ubuntu - dependsOn: [BuildLinuxStage] - jobs: - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: CI - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: CI - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: Others - - - template: templates/nix-test.yml - parameters: - name: Ubuntu - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: Others - - - template: templates/verify-xunit.yml - parameters: - pool: ubuntu-20.04 - -- stage: TestContainer - displayName: Test in a container - dependsOn: [BuildLinuxStage] - jobs: - - job: getContainerJob - displayName: Choose a container - pool: - vmImage: ubuntu-20.04 - steps: - - checkout: self - clean: true - - - checkout: Docker - clean: true - - - pwsh: | - # Initialize container test stage - Import-Module ./PowerShell/tools/ci.psm1 - Invoke-InitializeContainerStage -ContainerPattern '${{ parameters.ContainerPattern }}' - name: getContainerTask - displayName: Initialize Container Stage - continueOnError: true - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: CI - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: CI - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: UnelevatedPesterTests - tagSet: Others - - - template: templates/test/nix-container-test.yml - parameters: - name: container - pool: ubuntu-20.04 - purpose: ElevatedPesterTests - tagSet: Others - - stage: PackageLinux displayName: Package Linux dependsOn: ["BuildLinuxStage"] jobs: - template: linux/templates/packaging.yml parameters: - pool: ubuntu-20.04 + pool: ubuntu-latest diff --git a/.vsts-ci/linux/templates/packaging.yml b/.vsts-ci/linux/templates/packaging.yml index fab2e1101fa..8f77b8e24a0 100644 --- a/.vsts-ci/linux/templates/packaging.yml +++ b/.vsts-ci/linux/templates/packaging.yml @@ -13,8 +13,14 @@ jobs: displayName: ${{ parameters.name }} packaging steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() @@ -33,7 +39,7 @@ jobs: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap -Package + Start-PSBootstrap -Scenario Package displayName: Bootstrap - pwsh: | diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 4f5e999a335..9258d407650 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -15,6 +15,7 @@ trigger: - .vsts-ci/misc-analysis.yml - .github/ISSUE_TEMPLATE/* - .dependabot/config.yml + - .pipelines/* - test/perf/* pr: branches: @@ -40,6 +41,7 @@ pr: - tools/releaseBuild/azureDevOps/templates/* - README.md - .spelling + - .pipelines/* variables: DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -92,3 +94,20 @@ stages: parameters: pool: macOS-latest +- stage: PackageMac + dependsOn: ['BuildMac'] + displayName: Package macOS (bootstrap only) + jobs: + - job: macos_packaging + pool: + vmImage: macOS-latest + + displayName: macOS packaging (bootstrap only) + steps: + - checkout: self + clean: true + - pwsh: | + import-module ./build.psm1 + start-psbootstrap -Scenario package + displayName: Bootstrap packaging + condition: succeededOrFailed() diff --git a/.vsts-ci/misc-analysis.yml b/.vsts-ci/misc-analysis.yml deleted file mode 100644 index 15b3277635b..00000000000 --- a/.vsts-ci/misc-analysis.yml +++ /dev/null @@ -1,48 +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 - - feature* - -pr: - branches: - include: - - master - - feature* - -resources: - repositories: - - repository: ComplianceRepo - type: github - endpoint: PowerShell - name: PowerShell/compliance - ref: master - -variables: - - name: repoFolder - value: PowerShell - -stages: -- stage: Compliance - jobs: - - job: CI_Compliance - displayName: CI Compliance - - pool: - vmImage: windows-latest - - variables: - - name: repoPath - value: $(Agent.BuildDirectory)\$(repoFolder) - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - - - template: ci-compliance.yml@ComplianceRepo diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml new file mode 100644 index 00000000000..1a24983b5b5 --- /dev/null +++ b/.vsts-ci/psresourceget-acr.yml @@ -0,0 +1,157 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +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/* + - .github/workflows/* + - .dependabot/config.yml + - test/perf/* + - .pipelines/* +pr: + branches: + include: + - master + - release* + - feature* + paths: + include: + - '*' + exclude: + - .dependabot/config.yml + - .github/ISSUE_TEMPLATE/* + - .github/workflows/* + - .vsts-ci/misc-analysis.yml + - tools/cgmanifest.json + - LICENSE.txt + - test/common/markdown/* + - test/perf/* + - tools/packaging/* + - tools/releaseBuild/* + - tools/releaseBuild/azureDevOps/templates/* + - README.md + - .spelling + - .pipelines/* + +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 + __SuppressAnsiEscapeSequences: 1 + NugetSecurityAnalysisWarningLevel: none + nugetMultiFeedWarnLevel: none + +resources: +- repo: self + clean: true + +stages: +- stage: BuildWin + displayName: Build for Windows + jobs: + - template: templates/ci-build.yml + +- stage: TestWin + displayName: Test PSResourceGetACR + jobs: + - job: win_test_ACR + displayName: PSResourceGet ACR Tests + pool: + vmImage: 'windows-latest' + + steps: + - pwsh: | + Get-ChildItem -Path env: + 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: | + # 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: | + Install-Module -Name 'Microsoft.PowerShell.SecretManagement' -force -SkipPublisherCheck -AllowClobber + Install-Module -Name 'Microsoft.PowerShell.SecretStore' -force -SkipPublisherCheck -AllowClobber + $vaultPassword = ConvertTo-SecureString $("a!!"+ (Get-Random -Maximum ([int]::MaxValue))) -AsPlainText -Force + Set-SecretStoreConfiguration -Authentication None -Interaction None -Confirm:$false -Password $vaultPassword + Register-SecretVault -Name SecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault + displayName: 'Install Secret store' + + - task: AzurePowerShell@5 + inputs: + azureSubscription: PSResourceGetACR + azurePowerShellVersion: LatestVersion + ScriptType: InlineScript + pwsh: true + inline: | + Write-Verbose -Verbose "Getting Azure Container Registry" + Get-AzContainerRegistry -ResourceGroupName 'PSResourceGet' -Name 'psresourcegettest' | Select-Object -Property * + Write-Verbose -Verbose "Setting up secret for Azure Container Registry" + $azt = Get-AzAccessToken + $tenantId = $azt.TenantID + Set-Secret -Name $tenantId -Secret $azt.Token -Verbose + $vstsCommandString = "vso[task.setvariable variable=TenantId]$tenantId" + Write-Host "sending " + $vstsCommandString + Write-Host "##$vstsCommandString" + displayName: 'Setup Azure Container Registry secret' + + - 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 + + $pwshExe = Get-ChildItem -Path $rootPath -Recurse -Filter pwsh.exe | Select-Object -First 1 + + $outputFilePath = "$(Build.SourcesDirectory)\test\powershell\Modules\Microsoft.PowerShell.PSResourceGet\ACRTests.xml" + $cmdline = "`$env:ACRTESTS = 'true'; Invoke-Pester -Path '$(Build.SourcesDirectory)\test\powershell\Modules\Microsoft.PowerShell.PSResourceGet\Microsoft.PowerShell.PSResourceGet.Tests.ps1' -TestName 'PSResourceGet - ACR tests' -OutputFile $outputFilePath -OutputFormat NUnitXml" + Write-Verbose -Verbose "Running $cmdline" + + & $pwshExe -Command $cmdline + + Publish-TestResults -Title "PSResourceGet - ACR tests" -Path $outputFilePath -Type NUnit + displayName: 'PSResourceGet ACR functional tests using AzAuth' + diff --git a/.vsts-ci/sshremoting-tests.yml b/.vsts-ci/sshremoting-tests.yml index e7b7003c3b7..2eda2a18276 100644 --- a/.vsts-ci/sshremoting-tests.yml +++ b/.vsts-ci/sshremoting-tests.yml @@ -51,7 +51,7 @@ jobs: steps: - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() diff --git a/.vsts-ci/templates/ci-build.yml b/.vsts-ci/templates/ci-build.yml index c502a9a3d46..5ec458c3c5a 100644 --- a/.vsts-ci/templates/ci-build.yml +++ b/.vsts-ci/templates/ci-build.yml @@ -46,7 +46,7 @@ jobs: fetchDepth: 1000 - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() @@ -54,9 +54,15 @@ jobs: displayName: Set Build Name for Non-PR condition: ne(variables['Build.Reason'], 'PullRequest') - - ${{ if ne(variables['AzDevOpsFeed'], '') }}: + - ${{ if ne(variables['UseAzDevOpsFeed'], '') }}: - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - pwsh: | Import-Module .\tools\ci.psm1 Invoke-CIInstall -SkipUser diff --git a/.vsts-ci/templates/install-ps-phase.yml b/.vsts-ci/templates/install-ps-phase.yml index f521cda0444..4e650273264 100644 --- a/.vsts-ci/templates/install-ps-phase.yml +++ b/.vsts-ci/templates/install-ps-phase.yml @@ -22,7 +22,7 @@ jobs: steps: - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() 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/.vsts-ci/templates/nix-test.yml b/.vsts-ci/templates/nix-test.yml index ab3985dacd6..214ae14b2c6 100644 --- a/.vsts-ci/templates/nix-test.yml +++ b/.vsts-ci/templates/nix-test.yml @@ -13,6 +13,12 @@ jobs: displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - template: ./test/nix-test-steps.yml parameters: purpose: ${{ parameters.purpose }} diff --git a/.vsts-ci/templates/test/nix-container-test.yml b/.vsts-ci/templates/test/nix-container-test.yml index 931af6fc675..37c60a4c53b 100644 --- a/.vsts-ci/templates/test/nix-container-test.yml +++ b/.vsts-ci/templates/test/nix-container-test.yml @@ -23,6 +23,12 @@ jobs: displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} steps: + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + - template: ./nix-test-steps.yml parameters: purpose: ${{ parameters.purpose }} diff --git a/.vsts-ci/templates/test/nix-test-steps.yml b/.vsts-ci/templates/test/nix-test-steps.yml index 84d7a37b848..f15d59ea73a 100644 --- a/.vsts-ci/templates/test/nix-test-steps.yml +++ b/.vsts-ci/templates/test/nix-test-steps.yml @@ -5,7 +5,7 @@ parameters: steps: - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() diff --git a/.vsts-ci/templates/windows-test.yml b/.vsts-ci/templates/windows-test.yml index 50ff67a32a8..22758e3953c 100644 --- a/.vsts-ci/templates/windows-test.yml +++ b/.vsts-ci/templates/windows-test.yml @@ -37,7 +37,7 @@ jobs: condition: ne('${{ parameters.pool }}', 'windows-2019') - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() @@ -54,6 +54,13 @@ jobs: 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. @@ -74,7 +81,6 @@ jobs: - pwsh: | Import-Module .\build.psm1 -force - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' $options = (Get-PSOptions) diff --git a/.vsts-ci/windows-daily.yml b/.vsts-ci/windows-daily.yml index 4abcf8ec966..59dd3ba2f36 100644 --- a/.vsts-ci/windows-daily.yml +++ b/.vsts-ci/windows-daily.yml @@ -57,7 +57,7 @@ stages: steps: - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: 'Capture Environment' condition: succeededOrFailed() @@ -93,6 +93,13 @@ stages: 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' @@ -104,7 +111,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose UnelevatedPesterTests -TagSet CI @@ -113,7 +119,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose ElevatedPesterTests -TagSet CI @@ -122,7 +127,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose UnelevatedPesterTests -TagSet Others @@ -131,7 +135,6 @@ stages: - pwsh: | Import-Module .\build.psm1 - Start-PSBootstrap Import-Module .\tools\ci.psm1 Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' Invoke-CITest -Purpose ElevatedPesterTests -TagSet Others diff --git a/.vsts-ci/windows.yml b/.vsts-ci/windows.yml index c3a39647852..fcdee8e25bb 100644 --- a/.vsts-ci/windows.yml +++ b/.vsts-ci/windows.yml @@ -15,6 +15,7 @@ trigger: - .github/ISSUE_TEMPLATE/* - .dependabot/config.yml - test/perf/* + - .pipelines/* pr: branches: include: @@ -23,20 +24,18 @@ pr: - feature* paths: include: - - '*' + - .vsts-ci/templates/* + - .vsts-ci/windows.yml + - '*.props' + - build.psm1 + - src/* + - test/* + - tools/buildCommon/* + - tools/ci.psm1 + - tools/WindowsCI.psm1 exclude: - - .dependabot/config.yml - - .github/ISSUE_TEMPLATE/* - - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json - - LICENSE.txt - test/common/markdown/* - test/perf/* - - tools/packaging/* - - tools/releaseBuild/* - - tools/releaseBuild/azureDevOps/templates/* - - README.md - - .spelling variables: GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" diff --git a/.vsts-ci/windows/templates/windows-packaging.yml b/.vsts-ci/windows/templates/windows-packaging.yml index 3961214c86f..d23b745c30f 100644 --- a/.vsts-ci/windows/templates/windows-packaging.yml +++ b/.vsts-ci/windows/templates/windows-packaging.yml @@ -38,7 +38,7 @@ jobs: path: $(complianceRepoFolder) - powershell: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture environment condition: succeededOrFailed() @@ -47,8 +47,19 @@ jobs: displayName: Capture PowerShell Version Table condition: succeededOrFailed() + - pwsh: | + Import-Module .\tools\ci.psm1 + Switch-PSNugetConfig -Source Public + displayName: Switch to public feeds + condition: succeeded() + workingDirectory: $(repoPath) - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + packageType: 'sdk' + workingDirectory: $(repoPath) - pwsh: | Import-Module .\tools\ci.psm1 diff --git a/.vsts-ci/windows/windows-packaging.yml b/.vsts-ci/windows/windows-packaging.yml index d0e3c101081..05f69400719 100644 --- a/.vsts-ci/windows/windows-packaging.yml +++ b/.vsts-ci/windows/windows-packaging.yml @@ -38,6 +38,7 @@ pr: - test/packaging/windows/* - tools/ci.psm1 - tools/packaging/* + - tools/wix/* variables: - name: GIT_CONFIG_PARAMETERS diff --git a/Analyzers.props b/Analyzers.props index 2608f972630..6f906496c73 100644 --- a/Analyzers.props +++ b/Analyzers.props @@ -1,6 +1,6 @@ - + diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md new file mode 100644 index 00000000000..f2aee252a1f --- /dev/null +++ b/CHANGELOG/7.4.md @@ -0,0 +1,1505 @@ +# 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 + +- Move .NET method invocation logging to after the needed type conversion is done for method arguments (#25568) + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.411

+ +
+ +
    +
  • Correct Capitalization Referencing Templates (#25672)
  • +
  • Manually update SqlClient in TestService
  • +
  • Update cgmanifest
  • +
  • Update package references
  • +
  • Update .NET SDK to latest version
  • +
  • Change linux packaging tests to ubuntu latest (#25640)
  • +
+ +
+ +### Documentation and Help Content + +- Update Third Party Notices (#25524, #25659) + +[7.4.11]: https://github.com/PowerShell/PowerShell/compare/v7.4.10...v7.4.11 + + +## [7.4.10] + +### Engine Updates and Fixes + +- Fallback to AppLocker after `WldpCanExecuteFile` (#25229) + +### Code Cleanup + +
+ +
    +
  • Remove obsolete template from Windows Packaging CI (#25405)
  • +
  • Cleanup old release pipelines (#25404)
  • +
+ +
+ +### Tools + +- Do not run labels workflow in the internal repository (#25411) + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.408

+ +
+ +
    +
  • Update branch for release (#25518)
  • +
  • Move MSIXBundle to Packages and Release to GitHub (#25516)
  • +
  • Add CodeQL suppressions for PowerShell intended behavior (#25376)
  • +
  • Enhance path filters action to set outputs for all changes when not a PR (#25378)
  • +
  • Fix Merge Errors from #25401 and Internal 33077 (#25478)
  • +
  • Fix MSIX artifact upload, vPack template, changelog hashes, git tag command (#25476)
  • +
  • Fix Conditional Parameter to Skip NuGet Publish (#25475)
  • +
  • Use new variables template for vPack (#25474)
  • +
  • Add Windows Store Signing to MSIX bundle (#25472)
  • +
  • Update test result processing to use NUnitXml format and enhance logging for better clarity (#25471)
  • +
  • Fix the expected path of .NET after using UseDotnet 2 task to install (#25470)
  • +
  • Update Microsoft.PowerShell.PSResourceGet to 1.1.0 (#25469)
  • +
  • Combine GitHub and Nuget Release Stage (#25473)
  • +
  • Make GitHub Workflows work in the internal mirror (#25409)
  • +
  • Add default .NET install path for SDK validation (#25339)
  • +
  • Update APIScan to use new symbols server (#25400)
  • +
  • Use GitHubReleaseTask (#25401)
  • +
  • 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)
  • +
  • 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)
  • +
  • Update package pipeline windows image version (#25192)
  • +
+ +
+ +[7.4.10]: https://github.com/PowerShell/PowerShell/compare/v7.4.9...v7.4.10 + +## [7.4.9] + +### Notes + +_This release is internal only. It is not available for download._ + +### Tools + +- Check GH token availability for `Get-Changelog` (#25156) + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.407

+ +
+ +
    +
  • Update branch for release (#25101)
  • +
  • Only build Linux for packaging changes (#25161)
  • +
  • Skip additional packages when generating component manifest (#25160)
  • +
  • Remove Az module installs and AzureRM uninstalls in pipeline (#25157)
  • +
  • Add GitHub Actions workflow to verify PR labels (#25158)
  • +
  • Update security extensions (#25099)
  • +
  • Make Component Manifest Updater use neutral target in addition to RID target (#25100)
  • +
+ +
+ +[7.4.9]: https://github.com/PowerShell/PowerShell/compare/v7.4.8...v7.4.9 + +## [7.4.8] + +### Notes + +_This release is internal only. It is not available for download._ + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.406

+ +
+ +
    +
  • Update branch for release (#25085) (#24884)
  • +
  • Add UseDotnet task for installing dotnet (#25080)
  • +
  • Add Justin Chung as PowerShell team member in releaseTools.psm1 (#25074)
  • +
  • Fix V-Pack download package name (#25078)
  • +
  • Fix MSIX stage in release pipeline (#25079)
  • +
  • Give the pipeline runs meaningful names (#25081)
  • +
  • Make sure the vPack pipeline does not produce an empty package (#25082)
  • +
  • Update CODEOWNERS (#25083)
  • +
  • Add setup dotnet action to the build composite action (#25084)
  • +
  • Remove AzDO credscan as it is now in GitHub (#25077)
  • +
  • Use workload identity service connection to download makeappx tool from storage account (#25075)
  • +
  • Update .NET SDK (#24993)
  • +
  • Fix GitHub Action filter overmatching (#24957)
  • +
  • Fix release branch filters (#24960)
  • +
  • Convert powershell/PowerShell-CI-macos to GitHub Actions (#24955)
  • +
  • Convert powershell/PowerShell-CI-linux to GitHub Actions (#24945)
  • +
  • Convert powershell/PowerShell-Windows-CI to GitHub Actions (#24932)
  • +
  • PMC parse state correctly from update command's response (#24860)
  • +
  • Add EV2 support for publishing PowerShell packages to PMC (#24857)
  • +
+ +
+ +[7.4.8]: https://github.com/PowerShell/PowerShell/compare/v7.4.7...v7.4.8 + +## [7.4.7] + +### Build and Packaging Improvements + +
+ + + +

Update .NET SDK to 8.0.405

+ +
+ +
    +
  • Update branch for release - Transitive - true - minor (#24546)
  • +
  • Fix backport mistake in #24429 (#24545)
  • +
  • Fix seed max value for Container Linux CI (#24510) (#24543)
  • +
  • Add a way to use only NuGet feed sources (#24528) (#24542)
  • +
  • Bump Microsoft.PowerShell.PSResourceGet to 1.0.6 (#24419)
  • +
  • Update path due to pool change (Internal 33083)
  • +
  • Update pool for "Publish BuildInfo" job (Internal 33082)
  • +
  • Add missing backports and new fixes (Internal 33077)
  • +
  • Port copy blob changes (Internal 33055)
  • +
  • Update firewall to monitor (Internal 33048)
  • +
  • Fix typo in release-MakeBlobPublic.yml (Internal 33046)
  • +
  • Update change log for 7.4.6 (Internal 33040)
  • +
  • Update changelog for v7.4.6 release (Internal 32983)
  • +
  • Fix backport issues with release pipeline (#24835)
  • +
  • Remove duplicated parameter (#24832)
  • +
  • Make the AssemblyVersion not change for servicing releases 7.4.7 and onward (#24821)
  • +
  • Add *.props and sort path filters for windows CI (#24822) (#24823)
  • +
  • Take the newest windows signature nuget packages (#24818)
  • +
  • Use work load identity service connection to download makeappx tool from storage account (#24817) (#24820)
  • +
  • Update path filters for Windows CI (#24809) (#24819)
  • +
  • Fixed release pipeline errors and switched to KS3 (#24751) (#24816)
  • +
  • Update branch for release - Transitive - true - minor (#24806)
  • +
  • Add ability to capture MSBuild Binary logs when restore fails (#24128) (#24799)
  • +
  • Download package from package build for generating vpack (#24481) (#24801)
  • +
  • Add a parameter that skips verify packages step (#24763) (#24803)
  • +
  • Fix Changelog content grab during GitHub Release (#24788) (#24804)
  • +
  • Add tool package download in publish nuget stage (#24790) (#24805)
  • +
  • Add CodeQL scanning to APIScan build (#24303) (#24800)
  • +
  • Deploy Box Update (#24632) (#24802)
  • +
+ +
+ +### Documentation and Help Content + +- Update notices file (#24810) + +[7.4.7]: https://github.com/PowerShell/PowerShell/compare/v7.4.6...v7.4.7 + +## [7.4.6] - 2024-10-22 + +### Build and Packaging Improvements + +
+ + + +

Bump .NET SDK to 8.0.403

+ +
+ +
    +
  • Copy to static site instead of making blob public (#24269) (#24473)
  • +
  • Add ability to capture MSBuild Binary logs when restore fails (#24128)
  • +
  • Keep the roff file when gzipping it. (#24450)
  • +
  • Update PowerShell-Coordinated_Packages-Official.yml (#24449)
  • +
  • Update and add new NuGet package sources for different environments. (#24440)
  • +
  • Add PMC mapping for Debian 12 (bookworm) (#24413)
  • +
  • Fixes to Azure Public feed usage (#24429)
  • +
  • Delete assets/AppImageThirdPartyNotices.txt (#24256)
  • +
  • Delete demos directory (#24258)
  • +
  • Add specific path for issues in tsaconfig (#24244)
  • +
  • Checkin generated manpage (#24423)
  • +
  • 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)
  • +
  • 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)
  • +
  • Use Managed Identity for APIScan authentication (#24243)
  • +
  • Check Create and Submit in vPack build by default (#24181)
  • +
  • Capture environment better (#24148)
  • +
  • Refactor Nuget package source creation to use New-NugetPackageSource function (#24104)
  • +
  • Make Microsoft feeds the default (#24426)
  • +
  • Bump to .NET 8.0.403 and update dependencies (#24405)
  • +
+ +
+ +[7.4.6]: https://github.com/PowerShell/PowerShell/compare/v7.4.5...v7.4.6 + +## [7.4.5] - 2024-08-20 + +### General Cmdlet Updates and Fixes + +- Fix WebCmdlets when `-Body` is specified but `ContentType` is not (#24145) + +### Tests + +- Rewrite the mac syslog tests to make them less flaky (#24152) + +### Build and Packaging Improvements + +
+ + + +

Bump .NET SDK to 8.0.400

+ +
+ +
    +
  • Add feature flags for removing network isolation (Internal 32126)
  • +
  • Update ThirdPartyNotices.txt for v7.4.5 (#24160)
  • +
  • Update cgmanifest.json for v7.4.5 (#24159)
  • +
  • Update .NET SDK to 8.0.400 (#24151)
  • +
  • Cleanup unused csproj (#24146)
  • +
  • Remember installation options and used them to initialize options for the next installation (#24143)
  • +
  • Fix failures in GitHub action markdown-link-check (#24142)
  • +
  • Use correct signing certificates for RPM and DEBs (#21522)
  • +
+ +
+ +### Documentation and Help Content + +- Update docs sample nuget.config (#24147) +- Fix up broken links in Markdown files (#24144) + +[7.4.5]: https://github.com/PowerShell/PowerShell/compare/v7.4.4...v7.4.5 + +## [7.4.4] - 2024-07-18 + +### Engine Updates and Fixes + +- Resolve paths correctly when importing files or files referenced in the module manifest (Internal 31780) + +### Build and Packaging Improvements + +
+ + + +

Bump .NET to 8.0.303

+ +
+ +
    +
  • Enumerate over all signed zip packages in macos signing
  • +
  • Update TPN for the v7.4.4 release (Internal 31793)
  • +
  • Add update cgmanifest (Internal 31789)
  • +
  • Add macos signing for package files (#24015) (#24059)
  • +
  • Update .NET SDK to 8.0.303 (#24038)
  • +
+ +
+ +[7.4.4]: https://github.com/PowerShell/PowerShell/compare/v7.4.3...v7.4.4 + +## [7.4.3] - 2024-06-18 + +### General Cmdlet Updates and Fixes + +- Fix the error when using `Start-Process -Credential` without the admin privilege (#21393) (Thanks @jborean93!) +- Fix `Test-Path -IsValid` to check for invalid path and filename characters (#21358) + +### Engine Updates and Fixes + +- Fix generating `OutputType` when running in Constrained Language Mode (#21605) +- Expand `~` to `$home` on Windows with tab completion (#21529) +- Make sure both stdout and stderr can be redirected from a native executable (#20997) + +### Build and Packaging Improvements + +
+ + + +

Update to .NET 8.0.6

+

We thank the following contributors!

+

@ForNeVeR!

+ +
+ +
    +
  • Fixes for change to new Engineering System.
  • +
  • Fix argument passing in GlobalToolShim (#21333) (Thanks @ForNeVeR!)
  • +
  • Create powershell.config.json for PowerShell.Windows.x64 global tool (#23941)
  • +
  • Remove markdown link check on release branches (#23937)
  • +
  • Update to .NET 8.0.6 (#23936)
  • +
  • Fix error in the vPack release, debug script that blocked release (#23904)
  • +
  • Add branch counter variables for daily package builds (#21523)
  • +
  • Updates to package and release pipelines (#23800)
  • +
  • Fix exe signing with third party signing for WiX engine (#23878)
  • +
  • Use PSScriptRoot to find path to Wix module (#21611)
  • +
  • [StepSecurity] Apply security best practices (#21480)
  • +
  • Fix build failure due to missing reference in GlobalToolShim.cs (#21388)
  • +
  • Update installation on Wix module (#23808)
  • +
  • Use feed with Microsoft Wix toolset (#21651)
  • +
  • Create the Windows.x64 global tool with shim for signing (#21559)
  • +
  • Generate MSI for win-arm64 installer (#20516)
  • +
  • update wix package install (#21537)
  • +
  • Add a PAT for fetching PMC cli (#21503)
  • +
  • Official PowerShell Package pipeline (#21504)
  • +
+ +
+ +[7.4.3]: https://github.com/PowerShell/PowerShell/compare/v7.4.2...v7.4.3 + +## [7.4.2] - 2024-04-11 + +### General Cmdlet Updates and Fixes + +- Revert "Adjust PUT method behavior to POST one for default content type in WebCmdlets" (#21049) +- Fix regression with `Get-Content` when `-Tail 0` and `-Wait` are both used (#20734) (Thanks @CarloToso!) +- Fix `Get-Error` serialization of array values (#21085) (Thanks @jborean93!) +- Fix a regression in `Format-Table` when header label is empty (#21156) + +### Engine Updates and Fixes + +- Revert the PR #17856 (Do not preserve temporary results when no need to do so) (#21368) +- Make sure the assembly/library resolvers are registered at early stage (#21361) +- Handle the case that `Runspace.DefaultRunspace` is `null` when logging for WDAC Audit (#21344) +- Fix PowerShell class to support deriving from an abstract class with abstract properties (#21331) +- Fix the regression when doing type inference for `$_` (#21223) (Thanks @MartinGC94!) + +### Build and Packaging Improvements + +
+ + + +

Bump to .NET 8.0.4

+ +
+ +
    +
  • Revert analyzer package back to stable
  • +
  • Update SDK, deps and cgmanifest for 7.4.2
  • +
  • Revert changes to packaging.psm1
  • +
  • Update PSResourceGet version from 1.0.2 to 1.0.4.1 (#21439)
  • +
  • Verify environment variable for OneBranch before we try to copy (#21441)
  • +
  • Remove surrogateFile setting of APIScan (#21238)
  • +
  • Add dotenv install as latest version does not work with current Ruby version (#21239)
  • +
  • Multiple fixes in official build pipeline (#21408)
  • +
  • Add back 2 transitive dependency packages (#21415)
  • +
  • Update PSReadLine to v2.3.5 for the next v7.4.x servicing release (#21414)
  • +
  • PowerShell co-ordinated build OneBranch pipeline (#21364)
  • +
+ +
+ +[7.4.2]: https://github.com/PowerShell/PowerShell/compare/v7.4.1...v7.4.2 + +## [7.4.1] - 2024-01-11 + +### General Cmdlet Updates and Fixes + +- Fix `Group-Object` output using interpolated strings (#20745) (Thanks @mawosoft!) +- Fix `Start-Process -PassThru` to make sure the `ExitCode` property is accessible for the returned `Process` object (#20749) (#20866) (Thanks @CodeCyclone!) +- Fix rendering of DisplayRoot for network PSDrive (#20793) (#20863) + +### Engine Updates and Fixes + +- Ensure filename is not null when logging WDAC ETW events (#20910) (Thanks @jborean93!) +- Fix four regressions introduced by WDAC audit logging feature (#20913) + +### Build and Packaging Improvements + +
+ + + +Bump .NET 8 to version 8.0.101 + + + +
    +
  • Update .NET SDK and dependencies for v7.4.1 (Internal 29142)
  • +
  • Update cgmanifest for v7.4.1 (#20874)
  • +
  • Update package dependencies for v7.4.1 (#20871)
  • +
  • Set the rollForwardOnNoCandidateFx in runtimeconfig.json to roll forward only on minor and patch versions (#20689) (#20865)
  • +
  • Remove RHEL7 publishing to packages.microsoft.com as it's no longer supported (#20849) (#20864)
  • +
  • Fix the tab completion tests (#20867)
  • +
+ +
+ +[7.4.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.0...v7.4.1 + +## [7.4.0] - 2023-11-16 + +### General Cmdlet Updates and Fixes + +- Added a missing `ConfigureAwait(false)` call to webcmdlets so they don't block (#20622) +- Fix `Group-Object` so output uses current culture (#20623) +- Block getting help from network locations in restricted remoting sessions (#20615) + +### Build and Packaging Improvements + +
+ + + +

Bump .NET 8 to 8.0.0 RTM build

+ +
+ +
    +
  • Add internal .NET SDK URL parameter to release pipeline (Internal 28474)
  • +
  • Update the CGManifest file for v7.4.0 release (Internal 28457)
  • +
  • Fix repository root for the nuget.config (Internal 28456)
  • +
  • Add internal nuget feed to compliance build (Internal 28449)
  • +
  • Copy azure blob with PowerShell global tool to private blob and move to CDN during release (Internal 28438)
  • +
  • Fix release build by making the internal SDK parameter optional (#20658) (Internal 28440)
  • +
  • Make internal .NET SDK URL as a parameter for release builld (#20655) (Internal 28428)
  • +
  • Update PSResourceGet version for 1.0.1 release (#20652) (Internal 28427)
  • +
  • Bump .NET 8 to 8.0.0 RTM build (Internal 28360)
  • +
  • Remove Auth header content from ErrorRecord (Internal 28409)
  • +
  • Fix setting of variable to consume internal SDK source (Internal 28354)
  • +
  • Bump Microsoft.Management.Infrastructure to v3.0.0 (Internal 28352)
  • +
  • Bump Microsoft.PowerShell.Native to v7.4.0 (#20617) (#20624)
  • +
+ +
+ +[7.4.0]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-rc.1...v7.4.0 + +## [7.4.0-rc.1] - 2023-10-24 + +### General Cmdlet Updates and Fixes + +- Fix `Test-Connection` due to .NET 8 changes (#20369) (#20531) +- Add telemetry to check for specific tags when importing a module (#20371) (#20540) +- Fix `Copy-Item` progress to only show completed when all files are copied (#20517) (#20544) +- Fix `unixmode` to handle `setuid` and `sticky` when file is not an executable (#20366) (#20537) +- Fix UNC path completion regression (#20419) (#20541) +- Fix implicit remoting proxy cmdlets to act on common parameters (#20367) (#20530) +- Fix `Get-Service` non-terminating error message to include category (#20276) (#20529) +- Fixing regression in DSC (#20268) (#20528) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+ +
+ +
    +
  • Update ThirdPartyNotices.txt file (Internal 28110)
  • +
  • Update CGManifest for release
  • +
  • Fix package version for .NET nuget packages (#20551) (#20552)
  • +
  • Only registry App Path for release package (#20478) (#20549)
  • +
  • Bump PSReadLine from 2.2.6 to 2.3.4 (#20305) (#20533)
  • +
  • Bump Microsoft.Management.Infrastructure (#20511) (#20512) (#20433) (#20434) (#20534) (#20535) (#20545) (#20547)
  • +
  • Bump to .NET 8 RC2 (#20510) (#20543)
  • + +
  • Add SBOM for release pipeline (#20519) (#20548)
  • +
  • Bump version of Microsoft.PowerShell.PSResourceGet to v1.0.0 (#20485) (#20538)
  • +
  • Bump xunit.runner.visualstudio from 2.5.1 to 2.5.3 (#20486) (#20542)
  • +
  • Bump JsonSchema.Net from 5.2.5 to 5.2.6 (#20421) (#20532)
  • +
  • Fix alpine tar package name and do not crossgen alpine fxdependent package (#20459) (#20536)
  • +
  • Increase timeout when publishing packages to packages.microsoft.com (#20470) (#20539)
  • +
  • Block any preview vPack release (#20243) (#20526)
  • +
  • Add surrogate file for compliance scanning (#20423)
  • +
+ +
+ +[7.4.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.6...v7.4.0-rc.1 + +## [7.4.0-preview.6] - 2023-09-28 + +### General Cmdlet Updates and Fixes + +- Set approved experimental features to stable for 7.4 release (#20362) +- Revert changes to continue using `BinaryFormatter` for `Out-GridView` (#20360) +- Remove the comment trigger from feedback provider (#20346) + +### Tests + +- Continued improvement to tests for release automation (#20259) +- Skip the test on x86 as `InstallDate` is not visible on `Wow64` (#20255) +- Harden some problematic release tests (#20254) + +### Build and Packaging Improvements + +
+ + + +

Move to .NET 8.0.100-rc.1.23463.5

+ +
+ +
    +
  • Update the regex for package name validation (Internal 27783, 27795)
  • +
  • Update ThirdPartyNotices.txt (Internal 27772)
  • +
  • Remove the ref folder before running compliance (#20375)
  • +
  • Updates RIDs used to generate component Inventory (#20372)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.7.0 to 4.8.0-2.final (#20368)
  • +
  • Fix the release build by moving to the official .NET 8-rc.1 release build version (#20365)
  • +
  • Update the experimental feature JSON files (#20363)
  • +
  • Bump XunitXml.TestLogger from 3.1.11 to 3.1.17 (#20364)
  • +
  • Update Microsoft.PowerShell.PSResourceGet to 0.9.0-rc1 (#20361)
  • +
  • Update .NET SDK to version 8.0.100-rc.1.23455.8 (#20358)
  • +
  • Use fxdependent-win-desktop runtime for compliance runs (#20359)
  • +
  • Add mapping for mariner arm64 stable (#20348)
  • +
  • Bump xunit.runner.visualstudio from 2.5.0 to 2.5.1 (#20357)
  • +
  • Bump JsonSchema.Net from 5.2.1 to 5.2.5 (#20356)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2 (#20355)
  • +
  • Bump Markdig.Signed from 0.32.0 to 0.33.0 (#20354)
  • +
  • Bump JsonSchema.Net from 5.1.3 to 5.2.1 (#20353)
  • +
  • Bump actions/checkout from 3 to 4 (#20352)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1 (#20351)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.7.0-2.final to 4.7.0 (#20350)
  • +
  • Release build: Change the names of the PATs (#20349)
  • +
  • Put the calls to Set-AzDoProjectInfo and Set-AzDoAuthToken` in the right order (#20347)
  • +
  • Bump Microsoft.Management.Infrastructure (continued) (#20262)
  • +
  • Bump Microsoft.Management.Infrastructure to 3.0.0-preview.2 (#20261)
  • +
  • Enable vPack provenance data (#20260)
  • +
  • Start using new packages.microsoft.com cli (#20258)
  • +
  • Add mariner arm64 to PMC release (#20257)
  • +
  • Fix typo donet to dotnet in build scripts and pipelines (#20256)
  • +
+ +
+ +[7.4.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.5...v7.4.0-preview.6 + +## [7.4.0-preview.5] - 2023-08-21 + +### Breaking Changes + +- Change how relative paths in `Resolve-Path` are handled when using the `RelativeBasePath` parameter (#19755) (Thanks @MartinGC94!) + +### Engine Updates and Fixes + +- Fix dynamic parameter completion (#19510) (Thanks @MartinGC94!) +- Use `OrdinalIgnoreCase` to lookup script breakpoints (#20046) (Thanks @fflaten!) +- Guard against `null` or blank path components when adding to module path (#19922) (Thanks @stevenebutler!) +- Fix deadlock when piping to shell associated file extension (#19940) +- Fix completion regression for filesystem paths with custom `PSDrive` names (#19921) (Thanks @MartinGC94!) +- Add completion for variables assigned by the `Data` statement (#19831) (Thanks @MartinGC94!) +- Fix a null reference crash in completion code (#19916) (Thanks @MartinGC94!) + +### General Cmdlet Updates and Fixes + +- Fix `Out-GridView` by implementing `Clone()` method to replace old use of binary format serialization (#20050) +- Support Unix domain socket in WebCmdlets (#19343) (Thanks @CarloToso!) +- Wait-Process: add `-Any` and `-PassThru` parameters (#19423) (Thanks @dwtaber!) +- Added the switch parameter `-CaseInsensitive` to `Select-Object` and `Get-Unique` cmdlets (#19683) (Thanks @ArmaanMcleod!) +- `Restore-Computer` and `Stop-Computer` should fail with error when not running via `sudo` on Unix (#19824) +- Add Help proxy function for non-Windows platforms (#19972) +- Remove input text from the error message resulted by `SecureString` and `PSCredential` conversion failure (#19977) (Thanks @ArmaanMcleod!) +- Add `Microsoft.PowerShell.PSResourceGet` to the telemetry module list (#19926) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@eltociear, @Molkree, @MartinGC94

+ +
+ +
    +
  • Fix use of ThrowIf where the arguments were reversed (#20052)
  • +
  • Fix typo in Logging.Tests.ps1 (#20048) (Thanks @eltociear!)
  • +
  • Apply the InlineAsTypeCheck in the engine code - 2nd pass (#19694) (Thanks @Molkree!)
  • +
  • Apply the InlineAsTypeCheck rule in the engine code - 1st pass (#19692) (Thanks @Molkree!)
  • +
  • Remove unused string completion code (#19879) (Thanks @MartinGC94!)
  • +
+ +
+ +### Tools + +- Give the `assignPRs` workflow write permissions (#20021) + +### Tests + +- Additional test hardening for tests which fail in release pass. (#20093) +- Don't use a completion which has a space in it (#20064) +- Fixes for release tests (#20028) +- Remove spelling CI in favor of GitHub Action (#19973) +- Hide expected error for negative test on windows for script extension (#19929) +- Add more debugging to try to determine why these test fail in release build. (#19829) + +### Build and Packaging Improvements + +
    +
  • Update ThirdPartyNotices for 7.4.0-preview.5
  • +
  • Update PSResourceGet to 0.5.24-beta24 (#20118)
  • +
  • Fix build after the change to remove win-arm32 (#20102)
  • +
  • Add comment about pinned packages (#20096)
  • +
  • Bump to .NET 8 Preview 7 (#20092)
  • +
  • Remove Win-Arm32 from release build. (#20095)
  • +
  • Add alpine framework dependent package (#19995)
  • +
  • Bump JsonSchema.Net from 4.1.8 to 5.1.3 (#20089)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0 (#20088)
  • +
  • Move build to .NET 8 preview 6 (#19991)
  • +
  • Bump Microsoft.Management.Infrastructure from 2.0.0 to 3.0.0-preview.1 (#20081)
  • +
  • Bump Markdig.Signed from 0.31.0 to 0.32.0 (#20076)
  • +
  • Auto assign PR Maintainer (#20020)
  • +
  • Delete rule that was supposed to round-robin assign a maintainer (#20019)
  • +
  • Update the cgmanifest (#20012)
  • +
  • Update the cgmanifest (#20008)
  • +
  • Bump JsonSchema.Net from 4.1.7 to 4.1.8 (#20006)
  • +
  • Bump JsonSchema.Net from 4.1.6 to 4.1.7 (#20000)
  • +
  • Add mariner arm64 package build to release build (#19946)
  • +
  • Check for pre-release packages when it's a stable release (#19939)
  • +
  • Make PR creation tool use --web because it is more reliable (#19944)
  • +
  • Update to the latest NOTICES file (#19971)
  • +
  • Update variable used to bypass the blocking check for multiple NuGet feeds for release pipeline (#19963)
  • +
  • Update variable used to bypass the blocking check for multiple NuGet feeds (#19967)
  • +
  • Update README.md and metadata.json for release v7.2.13 and v7.3.6 (#19964)
  • +
  • Don't publish notice on failure because it prevent retry (#19955)
  • +
  • Change variable used to bypass nuget security scanning (#19954)
  • +
  • Update the cgmanifest (#19924)
  • +
  • Publish rpm package for rhel9 (#19750)
  • +
  • Bump XunitXml.TestLogger from 3.0.78 to 3.1.11 (#19900)
  • +
  • Bump JsonSchema.Net from 4.1.5 to 4.1.6 (#19885)
  • +
  • Bump xunit from 2.4.2 to 2.5.0 (#19902)
  • +
  • Remove HostArchitecture dynamic parameter for osxpkg (#19917)
  • +
  • FabricBot: Onboarding to GitOps.ResourceManagement because of FabricBot decommissioning (#19905)
  • +
  • Change variable used to bypass nuget security scanning (#19907)
  • +
  • Checkout history for markdown lint check (#19908)
  • +
  • Switch to GitHub Action for linting markdown (#19899)
  • +
  • Bump xunit.runner.visualstudio from 2.4.5 to 2.5.0 (#19901)
  • +
  • Add runtime and packaging type info for mariner2 arm64 (#19450)
  • +
  • Update to the latest NOTICES file (#19856)
  • +
+ + + +### Documentation and Help Content + +- Update `README.md` and `metadata.json` for `7.4.0-preview.4` release (#19872) +- Fix grammatical issue in `ADOPTERS.md` (#20037) (Thanks @nikohoffren!) +- Replace docs.microsoft.com URLs in code with FWLinks (#19996) +- Change `docs.microsoft.com` to `learn.microsoft.com` (#19994) +- Update man page to match current help for pwsh (#19993) +- Merge `7.3.5`, `7.3.6`, `7.2.12` and `7.2.13` changelogs (#19968) +- Fix ///-comments that violate the docs schema (#19957) +- Update the link for getting started in `README.md` (#19932) +- Migrate user docs to the PowerShell-Docs repository (#19871) + +[7.4.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.4...v7.4.0-preview.5 + +## [7.4.0-preview.4] - 2023-06-29 + +### Breaking Changes + +- `Test-Json`: Use `JsonSchema.Net` (`System.Text.Json`) instead of `NJsonSchema` (`Newtonsoft.Json`) (#18141) (Thanks @gregsdennis!) +- `Test-Connection`: Increase output detail when performing a TCP test (#11452) (Thanks @jackdcasey!) + +### Engine Updates and Fixes + +- Fix native executables not redirecting to file (#19842) +- Add a new experimental feature to control native argument passing style on Windows (#18706) +- Fix `TabExpansion2` variable leak when completing variables (#18763) (Thanks @MartinGC94!) +- Enable completion of variables across ScriptBlock scopes (#19819) (Thanks @MartinGC94!) +- Fix completion of the `foreach` statement variable (#19814) (Thanks @MartinGC94!) +- Fix variable type inference precedence (#18691) (Thanks @MartinGC94!) +- Fix member completion for PowerShell Enum class (#19740) (Thanks @MartinGC94!) +- Fix parsing for array literals in index expressions in method calls (#19224) (Thanks @MartinGC94!) +- Fix incorrect string to type conversion (#19560) (Thanks @MartinGC94!) +- Fix slow execution when many breakpoints are used (#14953) (Thanks @nohwnd!) +- Add a public API for getting locations of `PSModulePath` elements (#19422) +- Add WDAC Audit logging (#19641) +- Improve path completion (#19489) (Thanks @MartinGC94!) +- Fix an indexing out of bound error in `CompleteInput` for empty script input (#19501) (Thanks @MartinGC94!) +- Improve variable completion performance (#19595) (Thanks @MartinGC94!) +- Allow partial culture matching in `Update-Help` (#18037) (Thanks @dkaszews!) +- Fix the check when reading input in `NativeCommandProcessor` (#19614) +- Add support of respecting `$PSStyle.OutputRendering` on the remote host (#19601) +- Support byte stream piping between native commands and file redirection (#17857) + +### General Cmdlet Updates and Fixes + +- Disallow negative values for `Get-Content` cmdlet parameters `-Head` and `-Tail` (#19715) (Thanks @CarloToso!) +- Make `Update-Help` throw proper error when current culture is not associated with a language (#19765) (Thanks @josea!) +- Do not require activity when creating a completed progress record (#18474) (Thanks @MartinGC94!) +- WebCmdlets: Add alias for `-TimeoutSec` to `-ConnectionTimeoutSeconds` and add `-OperationTimeoutSeconds` (#19558) (Thanks @stevenebutler!) +- Avoid checking screen scraping on non-Windows platforms before launching native app (#19812) +- Add reference to PSResourceGet (#19597) +- Add `FileNameStar` to `MultipartFileContent` in WebCmdlets (#19467) (Thanks @CarloToso!) +- Add `ParameterSetName` for the `-Detailed` parameter of `Test-Connection` (#19727) +- Remove the property disabling optimization (#19701) +- Filter completion for enum parameter against `ValidateRange` attributes (#17750) (Thanks @fflaten!) +- Small cleanup `Invoke-RestMethod` (#19490) (Thanks @CarloToso!) +- Fix wildcard globbing in root of device paths (#19442) (Thanks @MartinGC94!) +- Add specific error message that creating Junctions requires absolute path (#19409) +- Fix array type parsing in generic types (#19205) (Thanks @MartinGC94!) +- Improve the verbose message of WebCmdlets to show correct HTTP version (#19616) (Thanks @CarloToso!) +- Fix HTTP status from 409 to 429 for WebCmdlets to get retry interval from Retry-After header. (#19622) (Thanks @mkht!) +- Remove minor versions from `PSCompatibleVersions` (#18635) (Thanks @xtqqczze!) +- Update `JsonSchema.Net` version to 4.1.0 (#19610) (Thanks @gregsdennis!) +- Allow combining of `-Skip` and `-SkipLast` parameters in `Select-Object` cmdlet. (#18849) (Thanks @ArmaanMcleod!) +- Fix constructing `PSModulePath` if a sub-path has trailing separator (#13147) +- Add `Get-SecureRandom` cmdlet (#19587) +- Fix `New-Item` to re-create `Junction` when `-Force` is specified (#18311) (Thanks @GigaScratch!) +- Improve Hashtable key completion for type constrained variable assignments, nested Hashtables and more (#17660) (Thanks @MartinGC94!) +- `Set-Clipboard -AsOSC52` for remote usage (#18222) (Thanks @dkaszews!) +- Refactor `MUIFileSearcher.AddFiles` in the help related code (#18825) (Thanks @xtqqczze!) +- Set `SetLastError` to `true` for symbolic and hard link native APIs (#19566) +- Fix `Get-AuthenticodeSignature -Content` to not roundtrip the bytes to a Unicode string and then back to bytes (#18774) (Thanks @jborean93!) +- WebCmdlets: Rename `-TimeoutSec` to `-ConnectionTimeoutSeconds` (with alias) and add `-OperationTimeoutSeconds` (#19558) (Thanks @stevenebutler!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@eltociear, @ArmaanMcleod, @turbedi, @CarloToso, @Molkree, @xtqqczze

+ +
+ +
    +
  • Fix typo in NativeCommandProcessor.cs (#19846) (Thanks @eltociear!)
  • +
  • Rename file from PingPathCommand.cs to TestPathCommand.cs (#19782) (Thanks @ArmaanMcleod!)
  • +
  • Make use of the new Random.Shared property (#18417) (Thanks @turbedi!)
  • +
  • six files (#19695) (Thanks @CarloToso!)
  • +
  • Apply IDE0019: InlineAsTypeCheck in Microsoft.PowerShell.Commands (#19688)(#19690)(#19687)(#19689) (Thanks @Molkree!)
  • +
  • Remove PSv2CompletionCompleter as part of the PowerShell v2 code cleanup (#18337) (Thanks @xtqqczze!)
  • +
  • Enable more nullable annotations in WebCmdlets (#19359) (Thanks @CarloToso!)
  • +
+ +
+ +### Tools + +- Add Git mailmap for Andy Jordan (#19469) +- Add backport function to release tools (#19568) + +### Tests + +- Improve reliability of the `Ctrl+c` tests for WebCmdlets (#19532) (Thanks @stevenebutler!) +- Fix logic for `Import-CliXml` test (#19805) +- Add some debugging to the transcript test for `SilentlyContinue` (#19770) +- Re-enable `Get-ComputerInfo` pending tests (#19746) +- Update syslog parser to handle modern formats. (#19737) +- Pass `-UserScope` as required by `RunUpdateHelpTests` (#13400) (Thanks @yecril71pl!) +- Change how `isPreview` is determined for default cmdlets tests (#19650) +- Skip file signature tests on 2012R2 where PKI cmdlet do not work (#19643) +- Change logic for testing missing or extra cmdlets. (#19635) +- Fix incorrect test cases in `ExecutionPolicy.Tests.ps1` (#19485) (Thanks @xtqqczze!) +- Fixing structure typo in test setup (#17458) (Thanks @powercode!) +- Fix test failures on Windows for time zone and remoting (#19466) +- Harden 'All approved Cmdlets present' test (#19530) + +### Build and Packaging Improvements + +
+ + +

Updated to .NET 8 Preview 4 +

We thank the following contributors!

+

@krishnayalavarthi

+ +
+ +
    +
  • Update to the latest NOTICES file (#19537)(#19820)(#19784)(#19720)(#19644)(#19620)(#19605)(#19546)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.5.0 to 17.6.3 (#19867)(#19762)(#19733)(#19668)(#19613)
  • +
  • Update the cgmanifest (#19847)(#19800)(#19792)(#19776)(#19763)(#19697)(#19631)
  • +
  • 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)
  • +
  • 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)
  • +
  • Bump Microsoft.PowerShell.MarkdownRender from 7.2.0 to 7.2.1 (#19751)(#19752)
  • +
  • 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))
  • +
  • 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)
  • +
  • Add prompt to fix conflict during backport (#19583)
  • +
  • Add comment in wix detailing use of UseMU (#19371)
  • +
  • Verify that packages have license data (#19543)
  • +
  • Add an explicit manual stage for changelog update (#19551)
  • +
  • Update the team member list in releaseTools.psm1 (#19544)
  • +
+ +
+ +### Documentation and Help Content + +- Update `metadata.json` and `README.md` for upcoming releases (#19863)(#19542) +- Update message to use the actual parameter name (#19851) +- Update `CONTRIBUTING.md` to include Code of Conduct enforcement (#19810) +- Update `working-group-definitions.md` (#19809)(#19561) +- Update `working-group.md` to add section about reporting working group members (#19758) +- Correct capitalization in readme (#19666) (Thanks @Aishat452!) +- Updated the public dashboard link (#19634) +- Fix a typo in `serialization.cs` (#19598) (Thanks @eltociear!) + +[7.4.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.3...v7.4.0-preview.4 + +## [7.4.0-preview.3] - 2023-04-20 + +### Breaking Changes + +- Remove code related to `#requires -pssnapin` (#19320) + +### Engine Updates and Fixes + +- Change the arrow used in feedback suggestion to a more common Unicode character (#19534) +- Support trigger registration in feedback provider (#19525) +- Update the `ICommandPredictor` interface to reduce boilerplate code from predictor implementation (#19414) +- Fix a crash in the type inference code (#19400) (Thanks @MartinGC94!) + +### Performance + +- Speed up `Resolve-Path` relative path resolution (#19171) (Thanks @MartinGC94!) + +### General Cmdlet Updates and Fixes + +- Infer external application output as strings (#19193) (Thanks @MartinGC94!) +- Fix a race condition in `Add-Type` (#19471) +- Detect insecure `https-to-http` redirect only if both URIs are absolute (#19468) (Thanks @CarloToso!) +- Support `Ctrl+c` when connection hangs while reading data in WebCmdlets (#19330) (Thanks @stevenebutler!) +- Enable type conversion of `AutomationNull` to `$null` for assignment (#19415) +- Add the parameter `-Environment` to `Start-Process` (#19374) +- Add the parameter `-RelativeBasePath` to `Resolve-Path` (#19358) (Thanks @MartinGC94!) +- Exclude redundant parameter aliases from completion results (#19382) (Thanks @MartinGC94!) +- Allow using a folder path in WebCmdlets' `-OutFile` parameter (#19007) (Thanks @CarloToso!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@eltociear, @CarloToso

+ +
+ +
    +
  • Fix typo in typeDataXmlLoader.cs (#19319) (Thanks @eltociear!)
  • +
  • Fix typo in Compiler.cs (#19491) (Thanks @eltociear!)
  • +
  • Inline the GetResponseObject method (#19380) (Thanks @CarloToso!)
  • +
  • Simplify ContentHelper methods (#19367) (Thanks @CarloToso!)
  • +
  • Initialize regex lazily in BasicHtmlWebResponseObject (#19361) (Thanks @CarloToso!)
  • +
  • Fix codefactor issue in if-statement (part 5) (#19286) (Thanks @CarloToso!)
  • +
  • Add nullable annotations in WebRequestSession.cs (#19291) (Thanks @CarloToso!)
  • +
+ +
+ +### Tests + +- Harden the default command test (#19416) +- Skip VT100 tests on Windows Server 2012R2 as console does not support it (#19413) +- Improve package management acceptance tests by not going to the gallery (#19412) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@dkattan

+ +
+ +
    +
  • Fixing MSI checkbox (#19325)
  • +
  • Update the experimental feature JSON files (#19297)
  • +
  • Update the cgmanifest (#19459, #19465)
  • +
  • Update .NET SDK version to 8.0.100-preview.3.23178.7 (#19381)
  • +
  • Force updating the transitive dependency on Microsoft.CSharp (#19514)
  • +
  • Update DotnetRuntimeMetadata.json to consume the .NET 8.0.0-preview.3 release (#19529)
  • +
  • Move PSGallery sync to a pool (#19523)
  • +
  • Fix the regex used for package name check in vPack build (#19511)
  • +
  • Make the vPack PAT library more obvious (#19505)
  • +
  • Change Microsoft.CodeAnalysis.CSharp back to 4.5.0 (#19464) (Thanks @dkattan!)
  • +
  • Update to the latest NOTICES file (#19332)
  • +
  • Add PoolNames variable group to compliance pipeline (#19408)
  • +
  • Fix stage dependencies and typo in release build (#19353)
  • +
  • Fix issues in release build and release pipeline (#19338)
  • +
+ +
+ +[7.4.0-preview.3]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.2...v7.4.0-preview.3 + +## [7.4.0-preview.2] - 2023-03-14 + +### Breaking Changes + +- Update some PowerShell APIs to throw `ArgumentException` instead of `ArgumentNullException` when the argument is an empty string (#19215) (Thanks @xtqqczze!) +- Add the parameter `-ProgressAction` to the common parameters (#18887) + +### Engine Updates and Fixes + +- Fix `PlainText` output to correctly remove the `Reset` VT sequence without number (#19283) +- Fix `ConciseView` to handle custom `ParserError` error records (#19239) +- Fix `VtSubstring` helper method to correctly check characters copied (#19240) +- Update the `FeedbackProvider` interface to return structured data (#19133) +- Make the exception error in PowerShell able to associate with the right history entry (#19095) +- Fix for JEA session leaking functions (#19024) +- Add WDAC events and system lockdown notification (#18893) +- Fix support for nanoserver due to lack of AMSI (#18882) + +### Performance + +- Use interpolated strings (#19002)(#19003)(#18977)(#18980)(#18996)(#18979)(#18997)(#18978)(#18983)(#18992)(#18993)(#18985)(#18988) (Thanks @CarloToso!) + +### General Cmdlet Updates and Fixes + +- Fix completion for `PSCustomObject` variable properties (#18682) (Thanks @MartinGC94!) +- Improve type inference for `Get-Random` (#18972) (Thanks @MartinGC94!) +- Make `-Encoding` parameter able to take `ANSI` encoding in PowerShell (#19298) (Thanks @CarloToso!) +- Telemetry improvements for tracking experimental feature opt out (#18762) +- Support HTTP persistent connections in Web Cmdlets (#19249) (Thanks @stevenebutler!) +- Fix using xml `-Body` in webcmdlets without an encoding (#19281) (Thanks @CarloToso!) +- Add the `Statement` property to `$MyInvocation` (#19027) (Thanks @IISResetMe!) +- Fix `Start-Process` `-Wait` with `-Credential` (#19096) (Thanks @jborean93!) +- Adjust `PUT` method behavior to `POST` one for default content type in WebCmdlets (#19152) (Thanks @CarloToso!) +- Improve verbose message in web cmdlets when content length is unknown (#19252) (Thanks @CarloToso!) +- Preserve `WebSession.MaximumRedirection` from changes (#19190) (Thanks @CarloToso!) +- Take into account `ContentType` from Headers in WebCmdlets (#19227) (Thanks @CarloToso!) +- Use C# 11 UTF-8 string literals (#19243) (Thanks @turbedi!) +- Add property assignment completion for enums (#19178) (Thanks @MartinGC94!) +- Fix class member completion for classes with base types (#19179) (Thanks @MartinGC94!) +- Add `-Path` and `-LiteralPath` parameters to `Test-Json` cmdlet (#19042) (Thanks @ArmaanMcleod!) +- Allow to preserve the original HTTP method by adding `-PreserveHttpMethodOnRedirect` to Web cmdlets (#18894) (Thanks @CarloToso!) +- Webcmdlets display an error on HTTPS to http redirect (#18595) (Thanks @CarloToso!) +- 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!) +- 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) +- Add `ValidateNotNullOrEmpty` to `OutFile` and `InFile` parameters of WebCmdlets (#19044) (Thanks @CarloToso!) +- Correct spelling of "custom" in event (#19059) (Thanks @spaette!) +- Ignore expected error for file systems not supporting alternate streams (#19065) +- Adding missing guard for telemetry opt out to avoid `NullReferenceException` when importing modules (#18949) (Thanks @powercode!) +- Fix progress calculation divide by zero in Copy-Item (#19038) +- Add progress to `Copy-Item` (#18735) +- WebCmdlets parse XML declaration to get encoding value, if present. (#18748) (Thanks @CarloToso!) +- `HttpKnownHeaderNames` update headers list (#18947) (Thanks @CarloToso!) +- Fix bug with managing redirection and `KeepAuthorization` in Web cmdlets (#18902) (Thanks @CarloToso!) +- Fix `Get-Error` to work with strict mode (#18895) +- Add `AllowInsecureRedirect` switch to Web cmdlets (#18546) (Thanks @CarloToso!) +- `Invoke-RestMethod` `-FollowRelLink` fix links containing commas (#18829) (Thanks @CarloToso!) +- Prioritize the default parameter set when completing positional arguments (#18755) (Thanks @MartinGC94!) +- Add `-CommandWithArgs` parameter to pwsh (#18726) +- Enable creating composite subsystem implementation in modules (#18888) +- Fix `Format-Table -RepeatHeader` for property derived tables (#18870) +- Add `StatusCode` to `HttpResponseException` (#18842) (Thanks @CarloToso!) +- Fix type inference for all scope variables (#18758) (Thanks @MartinGC94!) +- Add completion for Using keywords (#16514) (Thanks @MartinGC94!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@CarloToso, @iSazonov, @xtqqczze, @turbedi, @syntax-tm, @eltociear, @ArmaanMcleod

+ +
+ +
    +
  • Small cleanup in the WebCmdlet code (#19299) (Thanks @CarloToso!)
  • +
  • Remove unused GUID detection code from console host (#18871) (Thanks @iSazonov!)
  • +
  • Fix CodeFactor issues in the code base - part 4 (#19270) (Thanks @CarloToso!)
  • +
  • Fix codefactor if part 3 (#19269) (Thanks @CarloToso!)
  • +
  • Fix codefactor if part 2 (#19267) (Thanks @CarloToso!)
  • +
  • Fix codefactor if part 1 (#19266) (Thanks @CarloToso!)
  • +
  • Remove comment and simplify condition in WebCmdlets (#19251) (Thanks @CarloToso!)
  • +
  • Small style changes (#19241) (Thanks @CarloToso!)
  • +
  • Use ArgumentException.ThrowIfNullOrEmpty as appropriate [part 1] (#19215) (Thanks @xtqqczze!)
  • +
  • Use using variable to reduce the nested level (#19229) (Thanks @CarloToso!)
  • +
  • Use ArgumentException.ThrowIfNullOrEmpty() in more places (#19213) (Thanks @CarloToso!)
  • +
  • Replace BitConverter.ToString with Convert.ToHexString where appropriate (#19216) (Thanks @turbedi!)
  • +
  • Replace Requires.NotNullOrEmpty(string) with ArgumentException.ThrowIfNullOrEmpty (#19197) (Thanks @xtqqczze!)
  • +
  • Use ArgumentOutOfRangeException.ThrowIfNegativeOrZero when applicable (#19201) (Thanks @xtqqczze!)
  • +
  • Use CallerArgumentExpression on Requires.NotNull (#19200) (Thanks @xtqqczze!)
  • +
  • Revert a few change to not use 'ArgumentNullException.ThrowIfNull' (#19151)
  • +
  • Corrected some minor spelling mistakes (#19176) (Thanks @syntax-tm!)
  • +
  • Fix a typo in InitialSessionState.cs (#19177) (Thanks @eltociear!)
  • +
  • Fix a typo in pwsh help content (#19153)
  • +
  • Revert comment changes in WebRequestPSCmdlet.Common.cs (#19136) (Thanks @CarloToso!)
  • +
  • Small cleanup webcmdlets (#19128) (Thanks @CarloToso!)
  • +
  • Merge partials in WebRequestPSCmdlet.Common.cs (#19126) (Thanks @CarloToso!)
  • +
  • Cleanup WebCmdlets comments (#19124) (Thanks @CarloToso!)
  • +
  • Added minor readability and refactoring fixes to Process.cs (#19123) (Thanks @ArmaanMcleod!)
  • +
  • Small changes in Webcmdlets (#19109) (Thanks @CarloToso!)
  • +
  • Rework SetRequestContent in WebCmdlets (#18964) (Thanks @CarloToso!)
  • +
  • Small cleanup WebCmdlets (#19030) (Thanks @CarloToso!)
  • +
  • Update additional interpolated string changes (#19029)
  • +
  • Revert some of the interpolated string changes (#19018)
  • +
  • Cleanup StreamHelper.cs, WebRequestPSCmdlet.Common.cs and InvokeRestMethodCommand.Common.cs (#18950) (Thanks @CarloToso!)
  • +
  • Small cleanup common code of webcmdlets (#18946) (Thanks @CarloToso!)
  • +
  • Simplification of GetHttpMethod and HttpMethod in WebCmdlets (#18846) (Thanks @CarloToso!)
  • +
  • Fix typo in ModuleCmdletBase.cs (#18933) (Thanks @eltociear!)
  • +
  • Fix regression in RemoveNulls (#18881) (Thanks @iSazonov!)
  • +
  • Replace all NotNull with ArgumentNullException.ThrowIfNull (#18820) (Thanks @CarloToso!)
  • +
  • Cleanup InvokeRestMethodCommand.Common.cs (#18861) (Thanks @CarloToso!)
  • +
+ +
+ +### Tools + +- Add a Mariner install script (#19294) +- Add tool to trigger license information gathering for NuGet modules (#18827) + +### Tests + +- Update and enable the test for the type of `$input` (#18968) (Thanks @MartinGC94!) +- Increase the timeout for creating the `WebListener` (#19268) +- Increase the timeout when waiting for the event log (#19264) +- Add Windows ARM64 CI (#19040) +- Change test so output does not include newline (#19026) +- Allow system lock down test debug hook to work with new WLDP API (#18962) +- Add tests for `Allowinsecureredirect` parameter in Web cmdlets (#18939) (Thanks @CarloToso!) +- Enable `get-help` pattern tests on Unix (#18855) (Thanks @xtqqczze!) +- Create test to check if WebCmdlets decompress brotli-encoded data (#18905) (Thanks @CarloToso!) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@bergmeister, @xtqqczze

+ +
+ +
    +
  • Restructure the package build to simplify signing and packaging stages (#19321)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0 to 4.6.0-2.23152.6 (#19306)(#19233)
  • +
  • Test fixes for stabilizing tests (#19068)
  • +
  • Bump Newtonsoft.Json from 13.0.2 to 13.0.3 (#19290)(#19289)
  • +
  • Fix mariner sudo detection (#19304)
  • +
  • Add stage for symbols job in Release build (#18937)
  • +
  • Bump .NET to Preview 2 version (#19305)
  • +
  • Move workflows that create PRs to private repo (#19276)
  • +
  • Use reference assemblies generated by dotnet (#19302)
  • +
  • Update the cgmanifest (#18814)(#19165)(#19296)
  • +
  • Always regenerate files WXS fragment (#19196)
  • +
  • MSI installer: Add checkbox and MSI property DISABLE_TELEMETRY to optionally disable telemetry. (#10725) (Thanks @bergmeister!)
  • +
  • Add -Force to Move-Item to fix the GitHub workflow (#19262)
  • +
  • Update and remove outdated docs to fix the URL link checks (#19261)
  • +
  • Bump Markdig.Signed from 0.30.4 to 0.31.0 (#19232)
  • +
  • Add pattern to replace for reference API generation (#19214)
  • +
  • Split test artifact build into windows and non-windows (#19199)
  • +
  • Set LangVersion compiler option to 11.0 (#18877) (Thanks @xtqqczze!)
  • +
  • Update to .NET 8 preview 1 build (#19194)
  • +
  • Simplify Windows Packaging CI Trigger YAML (#19160)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.4.0 to 17.5.0 (#18823)(#19191)
  • +
  • Add URL for all distributions (#19159)
  • +
  • Bump Microsoft.Extensions.ObjectPool from 7.0.1 to 7.0.3 (#18925)(#19155)
  • +
  • Add verification of R2R at packaging (#19129)
  • +
  • Allow cross compiling windows (#19119)
  • +
  • Update CodeQL build agent (#19113)
  • +
  • Bump XunitXml.TestLogger from 3.0.70 to 3.0.78 (#19066)
  • +
  • Bump Microsoft.CodeAnalysis.Analyzers from 3.3.3 to 3.3.4 (#18975)
  • +
  • Bump BenchmarkDotNet to 0.13.3 (#18878) (Thanks @xtqqczze!)
  • +
  • Bump Microsoft.PowerShell.Native from 7.4.0-preview.1 to 7.4.0-preview.2 (#18910)
  • +
  • Add checks for Windows 8.1 and Server 2012 in the MSI installer (#18904)
  • +
  • Update build to include WinForms / WPF in all Windows builds (#18859)
  • +
+ +
+ +### Documentation and Help Content + +- Update to the latest NOTICES file (#19169)(#19309)(#19086)(#19077) +- Update supported distros in Readme (#18667) (Thanks @techguy16!) +- Remove the 'Code Coverage Status' badge (#19265) +- Pull in changelogs for `v7.2.10` and `v7.3.3` releases (#19219) +- Update tools `metadata` and `README` (#18831)(#19204)(#19014) +- Update a broken link in the `README.md` (#19187) +- Fix typos in comments (#19064) (Thanks @spaette!) +- Add `7.2` and `7.3` changelogs (#19025) +- typos (#19058) (Thanks @spaette!) +- Fix typo in `dotnet-tools/README.md` (#19021) (Thanks @spaette!) +- Fix up all comments to be in the proper order with proper spacing (#18619) +- Changelog for `v7.4.0-preview.1` release (#18835) + +[7.4.0-preview.2]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.1...v7.4.0-preview.2 + +## [7.4.0-preview.1] - 2022-12-20 + +### Engine Updates and Fixes + +- Add Instrumentation to `AmsiUtil` and make the init variable readonly (#18727) +- Fix typo in `OutOfProcTransportManager.cs` (#18766) (Thanks @eltociear!) +- Allow non-default encodings to be used in user's script/code (#18605) +- Add `Dim` and `DimOff` to `$PSStyle` (#18653) +- Change `exec` from alias to function to handle arbitrary arguments (#18567) +- The command prefix should also be in the error color for `NormalView` (#18555) +- Skip cloud files marked as "not on disk" during command discovery (#18152) +- Replace `UTF8Encoding(false)` with `Encoding.Default` (#18356) (Thanks @xtqqczze!) +- Fix `Switch-Process` to set `termios` appropriate for child process (#18467) +- On Unix, only explicitly terminate the native process if not in background (#18215) +- Treat `[NullString]::Value` as the string type when resolving methods (#18080) +- Improve pseudo binding for dynamic parameters (#18030) (Thanks @MartinGC94!) +- Make experimental feature `PSAnsiRenderingFileInfo` stable (#18042) +- Update to use version `2.21.0` of Application Insights. (#17903) +- Do not preserve temporary results when no need to do so (#17856) + +### Performance + +- Remove some static constants from `Utils.Separators` (#18154) (Thanks @iSazonov!) +- Avoid using regular expression when unnecessary in `ScriptWriter` (#18348) +- Use source generator for `PSVersionInfo` to improve startup time (#15603) (Thanks @iSazonov!) +- Skip evaluating suggestions at startup (#18232) +- Avoid using `Regex` when not necessary (#18210) + +### General Cmdlet Updates and Fixes + +- Update to use `ComputeCore.dll` for PowerShell Direct (#18194) +- Replace `ArgumentNullException(nameof())` with `ArgumentNullException.ThrowIfNull()` (#18792)(#18784) (Thanks @CarloToso!) +- Remove `TabExpansion` from remote session configuration (#18795) (Internal 23331) +- WebCmdlets get Retry-After from headers if status code is 429 (#18717) (Thanks @CarloToso!) +- Implement `SupportsShouldProcess` in `Stop-Transcript` (#18731) (Thanks @JohnLBevan!) +- Fix `New-Item -ItemType Hardlink` to resolve target to absolute path and not allow link to itself (#18634) +- Add output types to Format commands (#18746) (Thanks @MartinGC94!) +- Fix the process `CommandLine` on Linux (#18710) (Thanks @jborean93!) +- Fix `SuspiciousContentChecker.Match` to detect a predefined string when the text starts with it (#18693) +- Switch `$PSNativeCommandUseErrorActionPreference` to `$true` when feature is enabled (#18695) +- Fix `Start-Job` to check the existence of working directory using the PowerShell way (#18675) +- Webcmdlets add 308 to redirect codes and small cleanup (#18536) (Thanks @CarloToso!) +- Ensure `HelpInfo.Category` is consistently a string (#18254) +- Remove `gcloud` from the legacy list because it's resolved to a .ps1 script (#18575) +- Add `gcloud` and `sqlcmd` to list to use legacy argument passing (#18559) +- Fix native access violation (#18545) (#18547) (Thanks @chrullrich!) +- Fix issue when completing the first command in a script with an empty array expression (#18355) (Thanks @MartinGC94!) +- Improve type inference of hashtable keys (#17907) (Thanks @MartinGC94!) +- Fix `Switch-Process` to copy the current env to the new process (#18452) +- Fix `Switch-Process` error to include the command that is not found (#18443) +- Update `Out-Printer` to remove all decorating ANSI escape sequences from PowerShell formatting (#18425) +- Web cmdlets set default charset encoding to `UTF8` (#18219) (Thanks @CarloToso!) +- Fix incorrect cmdlet name in the script used by `Restart-Computer` (#18374) (Thanks @urizen-source!) +- Add the function `cd~` (#18308) (Thanks @GigaScratch!) +- Fix type inference error for empty return statements (#18351) (Thanks @MartinGC94!) +- Fix the exception reporting in `ConvertFrom-StringData` (#18336) (Thanks @GigaScratch!) +- Implement `IDisposable` in `NamedPipeClient` (#18341) (Thanks @xtqqczze!) +- Replace command-error suggestion with new implementation based on subsystem plugin (#18252) +- Remove the `ProcessorArchitecture` portion from the full name as it's obsolete (#18320) +- Make the fuzzy searching flexible by passing in the fuzzy matcher (#18270) +- Add `-FuzzyMinimumDistance` parameter to `Get-Command` (#18261) +- Improve startup time by triggering initialization of additional types on background thread (#18195) +- Fix decompression in web cmdlets (#17955) (Thanks @iSazonov!) +- Add `CustomTableHeaderLabel` formatting to differentiate table header labels that are not property names (#17346) +- Remove the extra new line form List formatting (#18185) +- Minor update to the `FileInfo` table formatting on Unix to make it more concise (#18183) +- Fix Parent property on processes with complex name (#17545) (Thanks @jborean93!) +- Make PowerShell class not affiliate with `Runspace` when declaring the `NoRunspaceAffinity` attribute (#18138) +- Complete the progress bar rendering in `Invoke-WebRequest` when downloading is complete or cancelled (#18130) +- Display download progress in human readable format for `Invoke-WebRequest` (#14611) (Thanks @bergmeister!) +- Update `WriteConsole` to not use `stackalloc` for buffer with too large size (#18084) +- Filter out compiler generated types for `Add-Type -PassThru` (#18095) +- Fixing `CA2014` warnings and removing the warning suppression (#17982) (Thanks @creative-cloud!) +- Make experimental feature `PSNativeCommandArgumentPassing` stable (#18044) +- Make experimental feature `PSAMSIMethodInvocationLogging` stable (#18041) +- Handle `PSObject` argument specially in method invocation logging (#18060) +- Fix typos in `EventResource.resx` (#18063) (Thanks @eltociear!) +- Make experimental feature `PSRemotingSSHTransportErrorHandling` stable (#18046) +- Make experimental feature `PSExec` stable (#18045) +- Make experimental feature `PSCleanBlock` stable (#18043) +- Fix error formatting to use color defined in `$PSStyle.Formatting` (#17987) +- Remove unneeded use of `chmod 777` (#17974) +- Support mapping foreground/background `ConsoleColor` values to VT escape sequences (#17938) +- Make `pwsh` server modes implicitly not show banner (#17921) +- Add output type attributes for `Get-WinEvent` (#17948) (Thanks @MartinGC94!) +- Remove 1 second minimum delay in `Invoke-WebRequest` for small files, and prevent file-download-error suppression. (#17896) (Thanks @AAATechGuy!) +- Add completion for values in comparisons when comparing Enums (#17654) (Thanks @MartinGC94!) +- Fix positional argument completion (#17796) (Thanks @MartinGC94!) +- Fix member completion in attribute argument (#17902) (Thanks @MartinGC94!) +- Throw when too many parameter sets are defined (#17881) (Thanks @fflaten!) +- Limit searching of `charset` attribute in `meta` tag for HTML to first 1024 characters in webcmdlets (#17813) +- Fix `Update-Help` failing silently with implicit non-US culture. (#17780) (Thanks @dkaszews!) +- Add the `ValidateNotNullOrWhiteSpace` attribute (#17191) (Thanks @wmentha!) +- Improve enumeration of inferred types in pipeline (#17799) (Thanks @MartinGC94!) + +### Code Cleanup + +
+ + + +

We thank the following contributors!

+

@MartinGC94, @CarloToso, @iSazonov, @xtqqczze, @turbedi, @trossr32, @eltociear, @AtariDreams, @jborean93

+ +
+ +
    +
  • Add TSAUpload for APIScan (#18446)
  • +
  • Use Pattern matching in ast.cs (#18794) (Thanks @MartinGC94!)
  • +
  • Cleanup webrequestpscmdlet.common.cs (#18596) (Thanks @CarloToso!)
  • +
  • Unify CreateFile pinvoke in SMA (#18751) (Thanks @iSazonov!)
  • +
  • Cleanup webresponseobject.common (#18785) (Thanks @CarloToso!)
  • +
  • InvokeRestMethodCommand.Common cleanup and merge partials (#18736) (Thanks @CarloToso!)
  • +
  • Replace GetDirectories in CimDscParser (#14319) (Thanks @xtqqczze!)
  • +
  • WebResponseObject.Common merge partials atomic commits (#18703) (Thanks @CarloToso!)
  • +
  • Enable pending test for Start-Process (#18724) (Thanks @iSazonov!)
  • +
  • Remove one CreateFileW (#18732) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport for WNetAddConnection2 (#18721) (Thanks @iSazonov!)
  • +
  • Use File.OpenHandle() instead CreateFileW pinvoke (#18722) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport for WNetGetConnection (#18690) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport - 1 (#18603) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA 3 (#18564) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA - 7 (#18594) (Thanks @iSazonov!)
  • +
  • Use static DateTime.UnixEpoch and RandomNumberGenerator.Fill() (#18621) (Thanks @turbedi!)
  • +
  • Rewrite Get-FileHash to use static HashData methods (#18471) (Thanks @turbedi!)
  • +
  • Replace DllImport with LibraryImport in SMA 8 (#18599) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA 4 (#18579) (Thanks @iSazonov!)
  • +
  • Remove NativeCultureResolver as dead code (#18582) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA 6 (#18581) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA 2 (#18543) (Thanks @iSazonov!)
  • +
  • Use standard SBCS detection (#18593) (Thanks @iSazonov!)
  • +
  • Remove unused pinvokes in RemoteSessionNamedPipe (#18583) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in SMA 5 (#18580) (Thanks @iSazonov!)
  • +
  • Remove SafeRegistryHandle (#18597) (Thanks @iSazonov!)
  • +
  • Remove ArchitectureSensitiveAttribute from the code base (#18598) (Thanks @iSazonov!)
  • +
  • Build COM adapter only on Windows (#18590)
  • +
  • Include timer instantiation for legacy telemetry in conditional compiler statements in Get-Help (#18475) (Thanks @trossr32!)
  • +
  • Convert DllImport to LibraryImport for recycle bin, clipboard, and computerinfo cmdlets (#18526)
  • +
  • Replace DllImport with LibraryImport in SMA 1 (#18520) (Thanks @iSazonov!)
  • +
  • Replace DllImport with LibraryImport in engine (#18496)
  • +
  • Fix typo in InitialSessionState.cs (#18435) (Thanks @eltociear!)
  • +
  • Remove remaining unused strings from resx files (#18448)
  • +
  • Use new LINQ Order() methods instead of OrderBy(static x => x) (#18395) (Thanks @turbedi!)
  • +
  • Make use of StringSplitOptions.TrimEntries when possible (#18412) (Thanks @turbedi!)
  • +
  • Replace some string.Join(string) calls with string.Join(char) (#18411) (Thanks @turbedi!)
  • +
  • Remove unused strings from FileSystem and Registry providers (#18403)
  • +
  • Use generic GetValues<T>, GetNames<T> enum methods (#18391) (Thanks @xtqqczze!)
  • +
  • Remove unused resource strings from SessionStateStrings (#18394)
  • +
  • Remove unused resource strings in System.Management.Automation (#18388)
  • +
  • Use Enum.HasFlags part 1 (#18386) (Thanks @xtqqczze!)
  • +
  • Remove unused strings from parser (#18383)
  • +
  • Remove unused strings from Utility module (#18370)
  • +
  • Remove unused console strings (#18369)
  • +
  • Remove unused strings from ConsoleInfoErrorStrings.resx (#18367)
  • +
  • Code cleanup in ContentHelper.Common.cs (#18288) (Thanks @CarloToso!)
  • +
  • Remove FusionAssemblyIdentity and GlobalAssemblyCache as they are not used (#18334) (Thanks @iSazonov!)
  • +
  • Remove some static initializations in StringManipulationHelper (#18243) (Thanks @xtqqczze!)
  • +
  • Use MemoryExtensions.IndexOfAny in PSv2CompletionCompleter (#18245) (Thanks @xtqqczze!)
  • +
  • Use MemoryExtensions.IndexOfAny in WildcardPattern (#18242) (Thanks @xtqqczze!)
  • +
  • Small cleanup of the stub code (#18301) (Thanks @CarloToso!)
  • +
  • Fix typo in RemoteRunspacePoolInternal.cs (#18263) (Thanks @eltociear!)
  • +
  • Some more code cleanup related to the use of PSVersionInfo (#18231)
  • +
  • Use MemoryExtensions.IndexOfAny in SessionStateInternal (#18244) (Thanks @xtqqczze!)
  • +
  • Use overload APIs that take char instead of string when it's possible (#18179) (Thanks @iSazonov!)
  • +
  • Replace UTF8Encoding(false) with Encoding.Default (#18144) (Thanks @xtqqczze!)
  • +
  • Remove unused variables (#18058) (Thanks @AtariDreams!)
  • +
  • Fix typo in PowerShell.Core.Instrumentation.man (#17963) (Thanks @eltociear!)
  • +
  • Migrate WinTrust functions to a common location (#17598) (Thanks @jborean93!)
  • +
+ +
+ +### Tools + +- Add a function to get the PR Back-port report (#18299) +- Add a workaround in automatic rebase workflow to continue on error (#18176) +- Update list of PowerShell team members in release tools (#17909) +- Don't block if we fail to create the comment (#17869) + +### Tests + +- Add `testexe.exe -echocmdline` to output raw command-line received by the process on Windows (#18591) +- Mark charset test as pending (#18511) +- Skip output rendering tests on Windows Server 2012 R2 (#18382) +- Increase timeout to make subsystem tests more reliable (#18380) +- Add missing -Tag 'CI' to describe blocks. (#18316) +- Use short path instead of multiple quotes in `Get-Item` test relying on node (#18250) +- Replace the CIM class used for `-Amended` parameter test (#17884) (Thanks @sethvs!) +- Stop ongoing progress-bar in `Write-Progress` test (#17880) (Thanks @fflaten!) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+ +
+ +
    +
  • Fix reference assembly generation logic for Microsoft.PowerShell.Commands.Utility (#18818)
  • +
  • Update the cgmanifest (#18676)(#18521)(#18415)(#18408)(#18197)(#18111)(#18051)(#17913)(#17867)(#17934)(#18088)
  • +
  • Bump Microsoft.PowerShell.Native to the latest preview version v7.4.0-preview.1 (#18805)
  • +
  • Remove unnecessary reference to System.Runtime.CompilerServices.Unsafe (#18806)
  • +
  • Update the release tag in metadata.json for next preview (#18799)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18750)
  • +
  • Bump .NET SDK to version 7.0.101 (#18786)
  • +
  • Bump cirrus-actions/rebase from 1.7 to 1.8 (#18788)
  • +
  • Bump decode-uri-component from 0.2.0 to 0.2.2 (#18712)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0-4.final to 4.4.0 (#18562)
  • +
  • Bump Newtonsoft.Json from 13.0.1 to 13.0.2 (#18657)
  • +
  • Apply expected file permissions to Linux files after Authenticode signing (#18643)
  • +
  • Remove extra quotes after agent moves to pwsh 7.3 (#18577)
  • +
  • Don't install based on build-id for RPM (#18560)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.0 (#18487)
  • +
  • Bump minimatch from 3.0.4 to 3.1.2 (#18514)
  • +
  • Avoid depending on the pre-generated experimental feature list in private and CI builds (#18484)
  • +
  • Update release-MsixBundle.yml to add retries (#18465)
  • +
  • Bump System.Data.SqlClient from 4.8.4 to 4.8.5 in /src/Microsoft.PowerShell.SDK (#18515)
  • +
  • Bump to use internal .NET 7 GA build (#18508)
  • +
  • Insert the pre-release nuget feed before building test artifacts (#18507)
  • +
  • Add test for framework dependent package in release pipeline (#18506) (Internal 23139)
  • +
  • Update to azCopy 10 (#18509)
  • +
  • Fix issues with uploading changelog to GitHub release draft (#18504)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18442)
  • +
  • Add authenticode signing for assemblies on linux builds (#18440)
  • +
  • Do not remove penimc_cor3.dll from build (#18438)
  • +
  • Bump Microsoft.PowerShell.Native from 7.3.0-rc.1 to 7.3.0 (#18405)
  • +
  • Allow two-digit revisions in vPack package validation pattern (#18392)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18363)
  • +
  • Bump to .NET 7 RC2 official version (#18328)
  • +
  • Bump to .NET 7 to version 7.0.100-rc.2.22477.20 (#18286)
  • +
  • Replace win7 runtime with win8 and remove APISets (#18304)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18312)
  • +
  • Recurse the file listing. (#18277)
  • +
  • Create tasks to collect and publish hashes for build files. (#18276)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18262)
  • +
  • Remove ETW trace collection and uploading for CLR CAP (#18253)
  • +
  • Do not cleanup pwsh.deps.json for framework dependent packages (#18226)
  • +
  • Add branch counter to APIScan build (#18214)
  • +
  • Remove unnecessary native dependencies from the package (#18213)
  • +
  • Remove XML files for min-size package (#18189)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18216)
  • +
  • Bump Microsoft.PowerShell.Native from 7.3.0-preview.1 to 7.3.0-rc.1 (#18217)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18201)
  • +
  • Move ApiScan to compliance build (#18191)
  • +
  • Fix the verbose message when using dotnet-install.sh (#18184)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#18163)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18164)
  • +
  • Make the link to minimal package blob public during release (#18158)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18147)
  • +
  • Update MSI exit message (#18137)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0-1.final to 4.4.0-2.final (#18132)
  • +
  • Re-enable building with Ready-to-Run (#18105)
  • +
  • Update DotnetRuntimeMetadata.json for .NET 7 RC1 build (#18091)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18096)
  • +
  • Add schema for cgmanifest.json (#18036)
  • +
  • Bump Microsoft.CodeAnalysis.CSharp from 4.3.0-3.final to 4.3.0 (#18012)
  • +
  • Add XML reference documents to NuPkg files for SDK (#17997)
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.3.0 to 17.3.1 (#18000)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17988)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17983)
  • +
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17945)
  • +
  • Make sure Security.types.ps1xml gets signed in release build (#17916)
  • +
  • Make Register Microsoft Update timeout (#17910)
  • +
  • Merge changes from v7.0.12 v7.2.6 and v7.3.0-preview.7
  • +
  • Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.0 (#17871)
  • +
+ +
+ +### Documentation and Help Content + +- Update readme and metadata for releases (#18780)(#18493)(#18393)(#18332)(#18128)(#17870) +- Remove 'please' and 'Core' from README.md per MS style guide (#18578) (Thanks @Rick-Anderson!) +- Change unsupported XML documentation tag (#18608) +- Change public API mention of `monad` to PowerShell (#18491) +- Update security reporting policy to recommend security portal for more streamlined reporting (#18437) +- Changelog for v7.3.0 (#18505) (Internal 23161) +- Replace `msh` in public API comment based documentation with PowerShell equivalent (#18483) +- Add missing XML doc elements for methods in `RunspaceFactory` (#18450) +- Changelog for `v7.3.0-rc.1` (#18400) +- Update changelogs for `v7.2.7` and `v7.0.13` (#18342) +- Update the changelog for v7.3.0-preview.8 (#18136) +- Add the `ConfigurationFile` option to the PowerShell help content (#18093) +- Update help content about the PowerShell flag `-NonInteractive` (#17952) + +[7.4.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.3.0-preview.8...v7.4.0-preview.1 diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index d8ba3d0958e..28605544ff7 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,967 +1,3 @@ -# Current preview release +# Preview Changelog -## [7.4.0-rc.1] - 2023-10-24 - -### General Cmdlet Updates and Fixes - -- Fix `Test-Connection` due to .NET 8 changes (#20369) (#20531) -- Add telemetry to check for specific tags when importing a module (#20371) (#20540) -- Fix `Copy-Item` progress to only show completed when all files are copied (#20517) (#20544) -- Fix `unixmode` to handle `setuid` and `sticky` when file is not an executable (#20366) (#20537) -- Fix UNC path completion regression (#20419) (#20541) -- Fix implicit remoting proxy cmdlets to act on common parameters (#20367) (#20530) -- Fix `Get-Service` non-terminating error message to include category (#20276) (#20529) -- Fixing regression in DSC (#20268) (#20528) - -### Build and Packaging Improvements - -
- - - -

We thank the following contributors!

- -
- -
    -
  • Update ThirdPartyNotices.txt file (Internal 28110)
  • -
  • Update CGManifest for release
  • -
  • Fix package version for .NET nuget packages (#20551) (#20552)
  • -
  • Only registry App Path for release package (#20478) (#20549)
  • -
  • Bump PSReadLine from 2.2.6 to 2.3.4 (#20305) (#20533)
  • -
  • Bump Microsoft.Management.Infrastructure (#20511) (#20512) (#20433) (#20434) (#20534) (#20535) (#20545) (#20547)
  • -
  • Bump to .NET 8 RC2 (#20510) (#20543)
  • - -
  • Add SBOM for release pipeline (#20519) (#20548)
  • -
  • Bump version of Microsoft.PowerShell.PSResourceGet to v1.0.0 (#20485) (#20538)
  • -
  • Bump xunit.runner.visualstudio from 2.5.1 to 2.5.3 (#20486) (#20542)
  • -
  • Bump JsonSchema.Net from 5.2.5 to 5.2.6 (#20421) (#20532)
  • -
  • Fix alpine tar package name and do not crossgen alpine fxdependent package (#20459) (#20536)
  • -
  • Increase timeout when publishing packages to packages.microsoft.com (#20470) (#20539)
  • -
  • Block any preview vPack release (#20243) (#20526)
  • -
  • Add surrogate file for compliance scanning (#20423)
  • -
- -
- -[7.4.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.6...v7.4.0-rc.1 - -## [7.4.0-preview.6] - 2023-09-28 - -### General Cmdlet Updates and Fixes - -- Set approved experimental features to stable for 7.4 release (#20362) -- Revert changes to continue using `BinaryFormatter` for `Out-GridView` (#20360) -- Remove the comment trigger from feedback provider (#20346) - -### Tests - -- Continued improvement to tests for release automation (#20259) -- Skip the test on x86 as `InstallDate` is not visible on `Wow64` (#20255) -- Harden some problematic release tests (#20254) - -### Build and Packaging Improvements - -
- - - -

Move to .NET 8.0.100-rc.1.23463.5

- -
- -
    -
  • Update the regex for package name validation (Internal 27783, 27795)
  • -
  • Update ThirdPartyNotices.txt (Internal 27772)
  • -
  • Remove the ref folder before running compliance (#20375)
  • -
  • Updates RIDs used to generate component Inventory (#20372)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.7.0 to 4.8.0-2.final (#20368)
  • -
  • Fix the release build by moving to the official .NET 8-rc.1 release build version (#20365)
  • -
  • Update the experimental feature JSON files (#20363)
  • -
  • Bump XunitXml.TestLogger from 3.1.11 to 3.1.17 (#20364)
  • -
  • Update Microsoft.PowerShell.PSResourceGet to 0.9.0-rc1 (#20361)
  • -
  • Update .NET SDK to version 8.0.100-rc.1.23455.8 (#20358)
  • -
  • Use fxdependent-win-desktop runtime for compliance runs (#20359)
  • -
  • Add mapping for mariner arm64 stable (#20348)
  • -
  • Bump xunit.runner.visualstudio from 2.5.0 to 2.5.1 (#20357)
  • -
  • Bump JsonSchema.Net from 5.2.1 to 5.2.5 (#20356)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2 (#20355)
  • -
  • Bump Markdig.Signed from 0.32.0 to 0.33.0 (#20354)
  • -
  • Bump JsonSchema.Net from 5.1.3 to 5.2.1 (#20353)
  • -
  • Bump actions/checkout from 3 to 4 (#20352)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1 (#20351)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.7.0-2.final to 4.7.0 (#20350)
  • -
  • Release build: Change the names of the PATs (#20349)
  • -
  • Put the calls to Set-AzDoProjectInfo and Set-AzDoAuthToken` in the right order (#20347)
  • -
  • Bump Microsoft.Management.Infrastructure (continued) (#20262)
  • -
  • Bump Microsoft.Management.Infrastructure to 3.0.0-preview.2 (#20261)
  • -
  • Enable vPack provenance data (#20260)
  • -
  • Start using new packages.microsoft.com cli (#20258)
  • -
  • Add mariner arm64 to PMC release (#20257)
  • -
  • Fix typo donet to dotnet in build scripts and pipelines (#20256)
  • -
- -
- -[7.4.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.5...v7.4.0-preview.6 - -## [7.4.0-preview.5] - 2023-08-21 - -### Breaking Changes - -- Change how relative paths in `Resolve-Path` are handled when using the `RelativeBasePath` parameter (#19755) (Thanks @MartinGC94!) - -### Engine Updates and Fixes - -- Fix dynamic parameter completion (#19510) (Thanks @MartinGC94!) -- Use `OrdinalIgnoreCase` to lookup script breakpoints (#20046) (Thanks @fflaten!) -- Guard against `null` or blank path components when adding to module path (#19922) (Thanks @stevenebutler!) -- Fix deadlock when piping to shell associated file extension (#19940) -- Fix completion regression for filesystem paths with custom `PSDrive` names (#19921) (Thanks @MartinGC94!) -- Add completion for variables assigned by the `Data` statement (#19831) (Thanks @MartinGC94!) -- Fix a null reference crash in completion code (#19916) (Thanks @MartinGC94!) - -### General Cmdlet Updates and Fixes - -- Fix `Out-GridView` by implementing `Clone()` method to replace old use of binary format serialization (#20050) -- Support Unix domain socket in WebCmdlets (#19343) (Thanks @CarloToso!) -- Wait-Process: add `-Any` and `-PassThru` parameters (#19423) (Thanks @dwtaber!) -- Added the switch parameter `-CaseInsensitive` to `Select-Object` and `Get-Unique` cmdlets (#19683) (Thanks @ArmaanMcleod!) -- `Restore-Computer` and `Stop-Computer` should fail with error when not running via `sudo` on Unix (#19824) -- Add Help proxy function for non-Windows platforms (#19972) -- Remove input text from the error message resulted by `SecureString` and `PSCredential` conversion failure (#19977) (Thanks @ArmaanMcleod!) -- Add `Microsoft.PowerShell.PSResourceGet` to the telemetry module list (#19926) - -### Code Cleanup - -
- - - -

We thank the following contributors!

-

@eltociear, @Molkree, @MartinGC94

- -
- -
    -
  • Fix use of ThrowIf where the arguments were reversed (#20052)
  • -
  • Fix typo in Logging.Tests.ps1 (#20048) (Thanks @eltociear!)
  • -
  • Apply the InlineAsTypeCheck in the engine code - 2nd pass (#19694) (Thanks @Molkree!)
  • -
  • Apply the InlineAsTypeCheck rule in the engine code - 1st pass (#19692) (Thanks @Molkree!)
  • -
  • Remove unused string completion code (#19879) (Thanks @MartinGC94!)
  • -
- -
- -### Tools - -- Give the `assignPRs` workflow write permissions (#20021) - -### Tests - -- Additional test hardening for tests which fail in release pass. (#20093) -- Don't use a completion which has a space in it (#20064) -- Fixes for release tests (#20028) -- Remove spelling CI in favor of GitHub Action (#19973) -- Hide expected error for negative test on windows for script extension (#19929) -- Add more debugging to try to determine why these test fail in release build. (#19829) - -### Build and Packaging Improvements - -
    -
  • Update ThirdPartyNotices for 7.4.0-preview.5
  • -
  • Update PSResourceGet to 0.5.24-beta24 (#20118)
  • -
  • Fix build after the change to remove win-arm32 (#20102)
  • -
  • Add comment about pinned packages (#20096)
  • -
  • Bump to .NET 8 Preview 7 (#20092)
  • -
  • Remove Win-Arm32 from release build. (#20095)
  • -
  • Add alpine framework dependent package (#19995)
  • -
  • Bump JsonSchema.Net from 4.1.8 to 5.1.3 (#20089)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0 (#20088)
  • -
  • Move build to .NET 8 preview 6 (#19991)
  • -
  • Bump Microsoft.Management.Infrastructure from 2.0.0 to 3.0.0-preview.1 (#20081)
  • -
  • Bump Markdig.Signed from 0.31.0 to 0.32.0 (#20076)
  • -
  • Auto assign PR Maintainer (#20020)
  • -
  • Delete rule that was supposed to round-robin assign a maintainer (#20019)
  • -
  • Update the cgmanifest (#20012)
  • -
  • Update the cgmanifest (#20008)
  • -
  • Bump JsonSchema.Net from 4.1.7 to 4.1.8 (#20006)
  • -
  • Bump JsonSchema.Net from 4.1.6 to 4.1.7 (#20000)
  • -
  • Add mariner arm64 package build to release build (#19946)
  • -
  • Check for pre-release packages when it's a stable release (#19939)
  • -
  • Make PR creation tool use --web because it is more reliable (#19944)
  • -
  • Update to the latest NOTICES file (#19971)
  • -
  • Update variable used to bypass the blocking check for multiple NuGet feeds for release pipeline (#19963)
  • -
  • Update variable used to bypass the blocking check for multiple NuGet feeds (#19967)
  • -
  • Update README.md and metadata.json for release v7.2.13 and v7.3.6 (#19964)
  • -
  • Don't publish notice on failure because it prevent retry (#19955)
  • -
  • Change variable used to bypass nuget security scanning (#19954)
  • -
  • Update the cgmanifest (#19924)
  • -
  • Publish rpm package for rhel9 (#19750)
  • -
  • Bump XunitXml.TestLogger from 3.0.78 to 3.1.11 (#19900)
  • -
  • Bump JsonSchema.Net from 4.1.5 to 4.1.6 (#19885)
  • -
  • Bump xunit from 2.4.2 to 2.5.0 (#19902)
  • -
  • Remove HostArchitecture dynamic parameter for osxpkg (#19917)
  • -
  • FabricBot: Onboarding to GitOps.ResourceManagement because of FabricBot decommissioning (#19905)
  • -
  • Change variable used to bypass nuget security scanning (#19907)
  • -
  • Checkout history for markdown lint check (#19908)
  • -
  • Switch to GitHub Action for linting markdown (#19899)
  • -
  • Bump xunit.runner.visualstudio from 2.4.5 to 2.5.0 (#19901)
  • -
  • Add runtime and packaging type info for mariner2 arm64 (#19450)
  • -
  • Update to the latest NOTICES file (#19856)
  • -
- - - -### Documentation and Help Content - -- Update `README.md` and `metadata.json` for `7.4.0-preview.4` release (#19872) -- Fix grammatical issue in `ADOPTERS.md` (#20037) (Thanks @nikohoffren!) -- Replace docs.microsoft.com URLs in code with FWLinks (#19996) -- Change `docs.microsoft.com` to `learn.microsoft.com` (#19994) -- Update man page to match current help for pwsh (#19993) -- Merge `7.3.5`, `7.3.6`, `7.2.12` and `7.2.13` changelogs (#19968) -- Fix ///-comments that violate the docs schema (#19957) -- Update the link for getting started in `README.md` (#19932) -- Migrate user docs to the PowerShell-Docs repository (#19871) - -[7.4.0-preview.5]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.4...v7.4.0-preview.5 - -## [7.4.0-preview.4] - 2023-06-29 - -### Breaking Changes - -- `Test-Json`: Use `JsonSchema.Net` (`System.Text.Json`) instead of `NJsonSchema` (`Newtonsoft.Json`) (#18141) (Thanks @gregsdennis!) -- `Test-Connection`: Increase output detail when performing a TCP test (#11452) (Thanks @jackdcasey!) - -### Engine Updates and Fixes - -- Fix native executables not redirecting to file (#19842) -- Add a new experimental feature to control native argument passing style on Windows (#18706) -- Fix `TabExpansion2` variable leak when completing variables (#18763) (Thanks @MartinGC94!) -- Enable completion of variables across ScriptBlock scopes (#19819) (Thanks @MartinGC94!) -- Fix completion of the `foreach` statement variable (#19814) (Thanks @MartinGC94!) -- Fix variable type inference precedence (#18691) (Thanks @MartinGC94!) -- Fix member completion for PowerShell Enum class (#19740) (Thanks @MartinGC94!) -- Fix parsing for array literals in index expressions in method calls (#19224) (Thanks @MartinGC94!) -- Fix incorrect string to type conversion (#19560) (Thanks @MartinGC94!) -- Fix slow execution when many breakpoints are used (#14953) (Thanks @nohwnd!) -- Add a public API for getting locations of `PSModulePath` elements (#19422) -- Add WDAC Audit logging (#19641) -- Improve path completion (#19489) (Thanks @MartinGC94!) -- Fix an indexing out of bound error in `CompleteInput` for empty script input (#19501) (Thanks @MartinGC94!) -- Improve variable completion performance (#19595) (Thanks @MartinGC94!) -- Allow partial culture matching in `Update-Help` (#18037) (Thanks @dkaszews!) -- Fix the check when reading input in `NativeCommandProcessor` (#19614) -- Add support of respecting `$PSStyle.OutputRendering` on the remote host (#19601) -- Support byte stream piping between native commands and file redirection (#17857) - -### General Cmdlet Updates and Fixes - -- Disallow negative values for `Get-Content` cmdlet parameters `-Head` and `-Tail` (#19715) (Thanks @CarloToso!) -- Make `Update-Help` throw proper error when current culture is not associated with a language (#19765) (Thanks @josea!) -- Do not require activity when creating a completed progress record (#18474) (Thanks @MartinGC94!) -- WebCmdlets: Add alias for `-TimeoutSec` to `-ConnectionTimeoutSeconds` and add `-OperationTimeoutSeconds` (#19558) (Thanks @stevenebutler!) -- Avoid checking screen scraping on non-Windows platforms before launching native app (#19812) -- Add reference to PSResourceGet (#19597) -- Add `FileNameStar` to `MultipartFileContent` in WebCmdlets (#19467) (Thanks @CarloToso!) -- Add `ParameterSetName` for the `-Detailed` parameter of `Test-Connection` (#19727) -- Remove the property disabling optimization (#19701) -- Filter completion for enum parameter against `ValidateRange` attributes (#17750) (Thanks @fflaten!) -- Small cleanup `Invoke-RestMethod` (#19490) (Thanks @CarloToso!) -- Fix wildcard globbing in root of device paths (#19442) (Thanks @MartinGC94!) -- Add specific error message that creating Junctions requires absolute path (#19409) -- Fix array type parsing in generic types (#19205) (Thanks @MartinGC94!) -- Improve the verbose message of WebCmdlets to show correct HTTP version (#19616) (Thanks @CarloToso!) -- Fix HTTP status from 409 to 429 for WebCmdlets to get retry interval from Retry-After header. (#19622) (Thanks @mkht!) -- Remove minor versions from `PSCompatibleVersions` (#18635) (Thanks @xtqqczze!) -- Update `JsonSchema.Net` version to 4.1.0 (#19610) (Thanks @gregsdennis!) -- Allow combining of `-Skip` and `-SkipLast` parameters in `Select-Object` cmdlet. (#18849) (Thanks @ArmaanMcleod!) -- Fix constructing `PSModulePath` if a sub-path has trailing separator (#13147) -- Add `Get-SecureRandom` cmdlet (#19587) -- Fix `New-Item` to re-create `Junction` when `-Force` is specified (#18311) (Thanks @GigaScratch!) -- Improve Hashtable key completion for type constrained variable assignments, nested Hashtables and more (#17660) (Thanks @MartinGC94!) -- `Set-Clipboard -AsOSC52` for remote usage (#18222) (Thanks @dkaszews!) -- Refactor `MUIFileSearcher.AddFiles` in the help related code (#18825) (Thanks @xtqqczze!) -- Set `SetLastError` to `true` for symbolic and hard link native APIs (#19566) -- Fix `Get-AuthenticodeSignature -Content` to not roundtrip the bytes to a Unicode string and then back to bytes (#18774) (Thanks @jborean93!) -- WebCmdlets: Rename `-TimeoutSec` to `-ConnectionTimeoutSeconds` (with alias) and add `-OperationTimeoutSeconds` (#19558) (Thanks @stevenebutler!) - -### Code Cleanup - -
- - - -

We thank the following contributors!

-

@eltociear, @ArmaanMcleod, @turbedi, @CarloToso, @Molkree, @xtqqczze

- -
- -
    -
  • Fix typo in NativeCommandProcessor.cs (#19846) (Thanks @eltociear!)
  • -
  • Rename file from PingPathCommand.cs to TestPathCommand.cs (#19782) (Thanks @ArmaanMcleod!)
  • -
  • Make use of the new Random.Shared property (#18417) (Thanks @turbedi!)
  • -
  • six files (#19695) (Thanks @CarloToso!)
  • -
  • Apply IDE0019: InlineAsTypeCheck in Microsoft.PowerShell.Commands (#19688)(#19690)(#19687)(#19689) (Thanks @Molkree!)
  • -
  • Remove PSv2CompletionCompleter as part of the PowerShell v2 code cleanup (#18337) (Thanks @xtqqczze!)
  • -
  • Enable more nullable annotations in WebCmdlets (#19359) (Thanks @CarloToso!)
  • -
- -
- -### Tools - -- Add Git mailmap for Andy Jordan (#19469) -- Add backport function to release tools (#19568) - -### Tests - -- Improve reliability of the `Ctrl+c` tests for WebCmdlets (#19532) (Thanks @stevenebutler!) -- Fix logic for `Import-CliXml` test (#19805) -- Add some debugging to the transcript test for `SilentlyContinue` (#19770) -- Re-enable `Get-ComputerInfo` pending tests (#19746) -- Update syslog parser to handle modern formats. (#19737) -- Pass `-UserScope` as required by `RunUpdateHelpTests` (#13400) (Thanks @yecril71pl!) -- Change how `isPreview` is determined for default cmdlets tests (#19650) -- Skip file signature tests on 2012R2 where PKI cmdlet do not work (#19643) -- Change logic for testing missing or extra cmdlets. (#19635) -- Fix incorrect test cases in `ExecutionPolicy.Tests.ps1` (#19485) (Thanks @xtqqczze!) -- Fixing structure typo in test setup (#17458) (Thanks @powercode!) -- Fix test failures on Windows for time zone and remoting (#19466) -- Harden 'All approved Cmdlets present' test (#19530) - -### Build and Packaging Improvements - -
- - -

Updated to .NET 8 Preview 4 -

We thank the following contributors!

-

@krishnayalavarthi

- -
- -
    -
  • Update to the latest NOTICES file (#19537)(#19820)(#19784)(#19720)(#19644)(#19620)(#19605)(#19546)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.5.0 to 17.6.3 (#19867)(#19762)(#19733)(#19668)(#19613)
  • -
  • Update the cgmanifest (#19847)(#19800)(#19792)(#19776)(#19763)(#19697)(#19631)
  • -
  • 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)
  • -
  • 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)
  • -
  • Bump Microsoft.PowerShell.MarkdownRender from 7.2.0 to 7.2.1 (#19751)(#19752)
  • -
  • 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))
  • -
  • 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)
  • -
  • Add prompt to fix conflict during backport (#19583)
  • -
  • Add comment in wix detailing use of UseMU (#19371)
  • -
  • Verify that packages have license data (#19543)
  • -
  • Add an explicit manual stage for changelog update (#19551)
  • -
  • Update the team member list in releaseTools.psm1 (#19544)
  • -
- -
- -### Documentation and Help Content - -- Update `metadata.json` and `README.md` for upcoming releases (#19863)(#19542) -- Update message to use the actual parameter name (#19851) -- Update `CONTRIBUTING.md` to include Code of Conduct enforcement (#19810) -- Update `working-group-definitions.md` (#19809)(#19561) -- Update `working-group.md` to add section about reporting working group members (#19758) -- Correct capitalization in readme (#19666) (Thanks @Aishat452!) -- Updated the public dashboard link (#19634) -- Fix a typo in `serialization.cs` (#19598) (Thanks @eltociear!) - -[7.4.0-preview.4]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.3...v7.4.0-preview.4 - -## [7.4.0-preview.3] - 2023-04-20 - -### Breaking Changes - -- Remove code related to `#requires -pssnapin` (#19320) - -### Engine Updates and Fixes - -- Change the arrow used in feedback suggestion to a more common Unicode character (#19534) -- Support trigger registration in feedback provider (#19525) -- Update the `ICommandPredictor` interface to reduce boilerplate code from predictor implementation (#19414) -- Fix a crash in the type inference code (#19400) (Thanks @MartinGC94!) - -### Performance - -- Speed up `Resolve-Path` relative path resolution (#19171) (Thanks @MartinGC94!) - -### General Cmdlet Updates and Fixes - -- Infer external application output as strings (#19193) (Thanks @MartinGC94!) -- Fix a race condition in `Add-Type` (#19471) -- Detect insecure `https-to-http` redirect only if both URIs are absolute (#19468) (Thanks @CarloToso!) -- Support `Ctrl+c` when connection hangs while reading data in WebCmdlets (#19330) (Thanks @stevenebutler!) -- Enable type conversion of `AutomationNull` to `$null` for assignment (#19415) -- Add the parameter `-Environment` to `Start-Process` (#19374) -- Add the parameter `-RelativeBasePath` to `Resolve-Path` (#19358) (Thanks @MartinGC94!) -- Exclude redundant parameter aliases from completion results (#19382) (Thanks @MartinGC94!) -- Allow using a folder path in WebCmdlets' `-OutFile` parameter (#19007) (Thanks @CarloToso!) - -### Code Cleanup - -
- - - -

We thank the following contributors!

-

@eltociear, @CarloToso

- -
- -
    -
  • Fix typo in typeDataXmlLoader.cs (#19319) (Thanks @eltociear!)
  • -
  • Fix typo in Compiler.cs (#19491) (Thanks @eltociear!)
  • -
  • Inline the GetResponseObject method (#19380) (Thanks @CarloToso!)
  • -
  • Simplify ContentHelper methods (#19367) (Thanks @CarloToso!)
  • -
  • Initialize regex lazily in BasicHtmlWebResponseObject (#19361) (Thanks @CarloToso!)
  • -
  • Fix codefactor issue in if-statement (part 5) (#19286) (Thanks @CarloToso!)
  • -
  • Add nullable annotations in WebRequestSession.cs (#19291) (Thanks @CarloToso!)
  • -
- -
- -### Tests - -- Harden the default command test (#19416) -- Skip VT100 tests on Windows Server 2012R2 as console does not support it (#19413) -- Improve package management acceptance tests by not going to the gallery (#19412) - -### Build and Packaging Improvements - -
- - - -

We thank the following contributors!

-

@dkattan

- -
- -
    -
  • Fixing MSI checkbox (#19325)
  • -
  • Update the experimental feature JSON files (#19297)
  • -
  • Update the cgmanifest (#19459, #19465)
  • -
  • Update .NET SDK version to 8.0.100-preview.3.23178.7 (#19381)
  • -
  • Force updating the transitive dependency on Microsoft.CSharp (#19514)
  • -
  • Update DotnetRuntimeMetadata.json to consume the .NET 8.0.0-preview.3 release (#19529)
  • -
  • Move PSGallery sync to a pool (#19523)
  • -
  • Fix the regex used for package name check in vPack build (#19511)
  • -
  • Make the vPack PAT library more obvious (#19505)
  • -
  • Change Microsoft.CodeAnalysis.CSharp back to 4.5.0 (#19464) (Thanks @dkattan!)
  • -
  • Update to the latest NOTICES file (#19332)
  • -
  • Add PoolNames variable group to compliance pipeline (#19408)
  • -
  • Fix stage dependencies and typo in release build (#19353)
  • -
  • Fix issues in release build and release pipeline (#19338)
  • -
- -
- -[7.4.0-preview.3]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.2...v7.4.0-preview.3 - -## [7.4.0-preview.2] - 2023-03-14 - -### Breaking Changes - -- Update some PowerShell APIs to throw `ArgumentException` instead of `ArgumentNullException` when the argument is an empty string (#19215) (Thanks @xtqqczze!) -- Add the parameter `-ProgressAction` to the common parameters (#18887) - -### Engine Updates and Fixes - -- Fix `PlainText` output to correctly remove the `Reset` VT sequence without number (#19283) -- Fix `ConciseView` to handle custom `ParserError` error records (#19239) -- Fix `VtSubstring` helper method to correctly check characters copied (#19240) -- Update the `FeedbackProvider` interface to return structured data (#19133) -- Make the exception error in PowerShell able to associate with the right history entry (#19095) -- Fix for JEA session leaking functions (#19024) -- Add WDAC events and system lockdown notification (#18893) -- Fix support for nanoserver due to lack of AMSI (#18882) - -### Performance - -- Use interpolated strings (#19002)(#19003)(#18977)(#18980)(#18996)(#18979)(#18997)(#18978)(#18983)(#18992)(#18993)(#18985)(#18988) (Thanks @CarloToso!) - -### General Cmdlet Updates and Fixes - -- Fix completion for `PSCustomObject` variable properties (#18682) (Thanks @MartinGC94!) -- Improve type inference for `Get-Random` (#18972) (Thanks @MartinGC94!) -- Make `-Encoding` parameter able to take `ANSI` encoding in PowerShell (#19298) (Thanks @CarloToso!) -- Telemetry improvements for tracking experimental feature opt out (#18762) -- Support HTTP persistent connections in Web Cmdlets (#19249) (Thanks @stevenebutler!) -- Fix using xml `-Body` in webcmdlets without an encoding (#19281) (Thanks @CarloToso!) -- Add the `Statement` property to `$MyInvocation` (#19027) (Thanks @IISResetMe!) -- Fix `Start-Process` `-Wait` with `-Credential` (#19096) (Thanks @jborean93!) -- Adjust `PUT` method behavior to `POST` one for default content type in WebCmdlets (#19152) (Thanks @CarloToso!) -- Improve verbose message in web cmdlets when content length is unknown (#19252) (Thanks @CarloToso!) -- Preserve `WebSession.MaximumRedirection` from changes (#19190) (Thanks @CarloToso!) -- Take into account `ContentType` from Headers in WebCmdlets (#19227) (Thanks @CarloToso!) -- Use C# 11 UTF-8 string literals (#19243) (Thanks @turbedi!) -- Add property assignment completion for enums (#19178) (Thanks @MartinGC94!) -- Fix class member completion for classes with base types (#19179) (Thanks @MartinGC94!) -- Add `-Path` and `-LiteralPath` parameters to `Test-Json` cmdlet (#19042) (Thanks @ArmaanMcleod!) -- Allow to preserve the original HTTP method by adding `-PreserveHttpMethodOnRedirect` to Web cmdlets (#18894) (Thanks @CarloToso!) -- Webcmdlets display an error on HTTPS to http redirect (#18595) (Thanks @CarloToso!) -- 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!) -- 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) -- Add `ValidateNotNullOrEmpty` to `OutFile` and `InFile` parameters of WebCmdlets (#19044) (Thanks @CarloToso!) -- Correct spelling of "custom" in event (#19059) (Thanks @spaette!) -- Ignore expected error for file systems not supporting alternate streams (#19065) -- Adding missing guard for telemetry opt out to avoid `NullReferenceException` when importing modules (#18949) (Thanks @powercode!) -- Fix progress calculation divide by zero in Copy-Item (#19038) -- Add progress to `Copy-Item` (#18735) -- WebCmdlets parse XML declaration to get encoding value, if present. (#18748) (Thanks @CarloToso!) -- `HttpKnownHeaderNames` update headers list (#18947) (Thanks @CarloToso!) -- Fix bug with managing redirection and `KeepAuthorization` in Web cmdlets (#18902) (Thanks @CarloToso!) -- Fix `Get-Error` to work with strict mode (#18895) -- Add `AllowInsecureRedirect` switch to Web cmdlets (#18546) (Thanks @CarloToso!) -- `Invoke-RestMethod` `-FollowRelLink` fix links containing commas (#18829) (Thanks @CarloToso!) -- Prioritize the default parameter set when completing positional arguments (#18755) (Thanks @MartinGC94!) -- Add `-CommandWithArgs` parameter to pwsh (#18726) -- Enable creating composite subsystem implementation in modules (#18888) -- Fix `Format-Table -RepeatHeader` for property derived tables (#18870) -- Add `StatusCode` to `HttpResponseException` (#18842) (Thanks @CarloToso!) -- Fix type inference for all scope variables (#18758) (Thanks @MartinGC94!) -- Add completion for Using keywords (#16514) (Thanks @MartinGC94!) - -### Code Cleanup - -
- - - -

We thank the following contributors!

-

@CarloToso, @iSazonov, @xtqqczze, @turbedi, @syntax-tm, @eltociear, @ArmaanMcleod

- -
- -
    -
  • Small cleanup in the WebCmdlet code (#19299) (Thanks @CarloToso!)
  • -
  • Remove unused GUID detection code from console host (#18871) (Thanks @iSazonov!)
  • -
  • Fix CodeFactor issues in the code base - part 4 (#19270) (Thanks @CarloToso!)
  • -
  • Fix codefactor if part 3 (#19269) (Thanks @CarloToso!)
  • -
  • Fix codefactor if part 2 (#19267) (Thanks @CarloToso!)
  • -
  • Fix codefactor if part 1 (#19266) (Thanks @CarloToso!)
  • -
  • Remove comment and simplify condition in WebCmdlets (#19251) (Thanks @CarloToso!)
  • -
  • Small style changes (#19241) (Thanks @CarloToso!)
  • -
  • Use ArgumentException.ThrowIfNullOrEmpty as appropriate [part 1] (#19215) (Thanks @xtqqczze!)
  • -
  • Use using variable to reduce the nested level (#19229) (Thanks @CarloToso!)
  • -
  • Use ArgumentException.ThrowIfNullOrEmpty() in more places (#19213) (Thanks @CarloToso!)
  • -
  • Replace BitConverter.ToString with Convert.ToHexString where appropriate (#19216) (Thanks @turbedi!)
  • -
  • Replace Requires.NotNullOrEmpty(string) with ArgumentException.ThrowIfNullOrEmpty (#19197) (Thanks @xtqqczze!)
  • -
  • Use ArgumentOutOfRangeException.ThrowIfNegativeOrZero when applicable (#19201) (Thanks @xtqqczze!)
  • -
  • Use CallerArgumentExpression on Requires.NotNull (#19200) (Thanks @xtqqczze!)
  • -
  • Revert a few change to not use 'ArgumentNullException.ThrowIfNull' (#19151)
  • -
  • Corrected some minor spelling mistakes (#19176) (Thanks @syntax-tm!)
  • -
  • Fix a typo in InitialSessionState.cs (#19177) (Thanks @eltociear!)
  • -
  • Fix a typo in pwsh help content (#19153)
  • -
  • Revert comment changes in WebRequestPSCmdlet.Common.cs (#19136) (Thanks @CarloToso!)
  • -
  • Small cleanup webcmdlets (#19128) (Thanks @CarloToso!)
  • -
  • Merge partials in WebRequestPSCmdlet.Common.cs (#19126) (Thanks @CarloToso!)
  • -
  • Cleanup WebCmdlets comments (#19124) (Thanks @CarloToso!)
  • -
  • Added minor readability and refactoring fixes to Process.cs (#19123) (Thanks @ArmaanMcleod!)
  • -
  • Small changes in Webcmdlets (#19109) (Thanks @CarloToso!)
  • -
  • Rework SetRequestContent in WebCmdlets (#18964) (Thanks @CarloToso!)
  • -
  • Small cleanup WebCmdlets (#19030) (Thanks @CarloToso!)
  • -
  • Update additional interpolated string changes (#19029)
  • -
  • Revert some of the interpolated string changes (#19018)
  • -
  • Cleanup StreamHelper.cs, WebRequestPSCmdlet.Common.cs and InvokeRestMethodCommand.Common.cs (#18950) (Thanks @CarloToso!)
  • -
  • Small cleanup common code of webcmdlets (#18946) (Thanks @CarloToso!)
  • -
  • Simplification of GetHttpMethod and HttpMethod in WebCmdlets (#18846) (Thanks @CarloToso!)
  • -
  • Fix typo in ModuleCmdletBase.cs (#18933) (Thanks @eltociear!)
  • -
  • Fix regression in RemoveNulls (#18881) (Thanks @iSazonov!)
  • -
  • Replace all NotNull with ArgumentNullException.ThrowIfNull (#18820) (Thanks @CarloToso!)
  • -
  • Cleanup InvokeRestMethodCommand.Common.cs (#18861) (Thanks @CarloToso!)
  • -
- -
- -### Tools - -- Add a Mariner install script (#19294) -- Add tool to trigger license information gathering for NuGet modules (#18827) - -### Tests - -- Update and enable the test for the type of `$input` (#18968) (Thanks @MartinGC94!) -- Increase the timeout for creating the `WebListener` (#19268) -- Increase the timeout when waiting for the event log (#19264) -- Add Windows ARM64 CI (#19040) -- Change test so output does not include newline (#19026) -- Allow system lock down test debug hook to work with new WLDP API (#18962) -- Add tests for `Allowinsecureredirect` parameter in Web cmdlets (#18939) (Thanks @CarloToso!) -- Enable `get-help` pattern tests on Unix (#18855) (Thanks @xtqqczze!) -- Create test to check if WebCmdlets decompress brotli-encoded data (#18905) (Thanks @CarloToso!) - -### Build and Packaging Improvements - -
- - - -

We thank the following contributors!

-

@bergmeister, @xtqqczze

- -
- -
    -
  • Restructure the package build to simplify signing and packaging stages (#19321)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0 to 4.6.0-2.23152.6 (#19306)(#19233)
  • -
  • Test fixes for stabilizing tests (#19068)
  • -
  • Bump Newtonsoft.Json from 13.0.2 to 13.0.3 (#19290)(#19289)
  • -
  • Fix mariner sudo detection (#19304)
  • -
  • Add stage for symbols job in Release build (#18937)
  • -
  • Bump .NET to Preview 2 version (#19305)
  • -
  • Move workflows that create PRs to private repo (#19276)
  • -
  • Use reference assemblies generated by dotnet (#19302)
  • -
  • Update the cgmanifest (#18814)(#19165)(#19296)
  • -
  • Always regenerate files WXS fragment (#19196)
  • -
  • MSI installer: Add checkbox and MSI property DISABLE_TELEMETRY to optionally disable telemetry. (#10725) (Thanks @bergmeister!)
  • -
  • Add -Force to Move-Item to fix the GitHub workflow (#19262)
  • -
  • Update and remove outdated docs to fix the URL link checks (#19261)
  • -
  • Bump Markdig.Signed from 0.30.4 to 0.31.0 (#19232)
  • -
  • Add pattern to replace for reference API generation (#19214)
  • -
  • Split test artifact build into windows and non-windows (#19199)
  • -
  • Set LangVersion compiler option to 11.0 (#18877) (Thanks @xtqqczze!)
  • -
  • Update to .NET 8 preview 1 build (#19194)
  • -
  • Simplify Windows Packaging CI Trigger YAML (#19160)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.4.0 to 17.5.0 (#18823)(#19191)
  • -
  • Add URL for all distributions (#19159)
  • -
  • Bump Microsoft.Extensions.ObjectPool from 7.0.1 to 7.0.3 (#18925)(#19155)
  • -
  • Add verification of R2R at packaging (#19129)
  • -
  • Allow cross compiling windows (#19119)
  • -
  • Update CodeQL build agent (#19113)
  • -
  • Bump XunitXml.TestLogger from 3.0.70 to 3.0.78 (#19066)
  • -
  • Bump Microsoft.CodeAnalysis.Analyzers from 3.3.3 to 3.3.4 (#18975)
  • -
  • Bump BenchmarkDotNet to 0.13.3 (#18878) (Thanks @xtqqczze!)
  • -
  • Bump Microsoft.PowerShell.Native from 7.4.0-preview.1 to 7.4.0-preview.2 (#18910)
  • -
  • Add checks for Windows 8.1 and Server 2012 in the MSI installer (#18904)
  • -
  • Update build to include WinForms / WPF in all Windows builds (#18859)
  • -
- -
- -### Documentation and Help Content - -- Update to the latest NOTICES file (#19169)(#19309)(#19086)(#19077) -- Update supported distros in Readme (#18667) (Thanks @techguy16!) -- Remove the 'Code Coverage Status' badge (#19265) -- Pull in changelogs for `v7.2.10` and `v7.3.3` releases (#19219) -- Update tools `metadata` and `README` (#18831)(#19204)(#19014) -- Update a broken link in the `README.md` (#19187) -- Fix typos in comments (#19064) (Thanks @spaette!) -- Add `7.2` and `7.3` changelogs (#19025) -- typos (#19058) (Thanks @spaette!) -- Fix typo in `dotnet-tools/README.md` (#19021) (Thanks @spaette!) -- Fix up all comments to be in the proper order with proper spacing (#18619) -- Changelog for `v7.4.0-preview.1` release (#18835) - -[7.4.0-preview.2]: https://github.com/PowerShell/PowerShell/compare/v7.4.0-preview.1...v7.4.0-preview.2 - -## [7.4.0-preview.1] - 2022-12-20 - -### Engine Updates and Fixes - -- Add Instrumentation to `AmsiUtil` and make the init variable readonly (#18727) -- Fix typo in `OutOfProcTransportManager.cs` (#18766) (Thanks @eltociear!) -- Allow non-default encodings to be used in user's script/code (#18605) -- Add `Dim` and `DimOff` to `$PSStyle` (#18653) -- Change `exec` from alias to function to handle arbitrary arguments (#18567) -- The command prefix should also be in the error color for `NormalView` (#18555) -- Skip cloud files marked as "not on disk" during command discovery (#18152) -- Replace `UTF8Encoding(false)` with `Encoding.Default` (#18356) (Thanks @xtqqczze!) -- Fix `Switch-Process` to set `termios` appropriate for child process (#18467) -- On Unix, only explicitly terminate the native process if not in background (#18215) -- Treat `[NullString]::Value` as the string type when resolving methods (#18080) -- Improve pseudo binding for dynamic parameters (#18030) (Thanks @MartinGC94!) -- Make experimental feature `PSAnsiRenderingFileInfo` stable (#18042) -- Update to use version `2.21.0` of Application Insights. (#17903) -- Do not preserve temporary results when no need to do so (#17856) - -### Performance - -- Remove some static constants from `Utils.Separators` (#18154) (Thanks @iSazonov!) -- Avoid using regular expression when unnecessary in `ScriptWriter` (#18348) -- Use source generator for `PSVersionInfo` to improve startup time (#15603) (Thanks @iSazonov!) -- Skip evaluating suggestions at startup (#18232) -- Avoid using `Regex` when not necessary (#18210) - -### General Cmdlet Updates and Fixes - -- Update to use `ComputeCore.dll` for PowerShell Direct (#18194) -- Replace `ArgumentNullException(nameof())` with `ArgumentNullException.ThrowIfNull()` (#18792)(#18784) (Thanks @CarloToso!) -- Remove `TabExpansion` from remote session configuration (#18795) (Internal 23331) -- WebCmdlets get Retry-After from headers if status code is 429 (#18717) (Thanks @CarloToso!) -- Implement `SupportsShouldProcess` in `Stop-Transcript` (#18731) (Thanks @JohnLBevan!) -- Fix `New-Item -ItemType Hardlink` to resolve target to absolute path and not allow link to itself (#18634) -- Add output types to Format commands (#18746) (Thanks @MartinGC94!) -- Fix the process `CommandLine` on Linux (#18710) (Thanks @jborean93!) -- Fix `SuspiciousContentChecker.Match` to detect a predefined string when the text starts with it (#18693) -- Switch `$PSNativeCommandUseErrorActionPreference` to `$true` when feature is enabled (#18695) -- Fix `Start-Job` to check the existence of working directory using the PowerShell way (#18675) -- Webcmdlets add 308 to redirect codes and small cleanup (#18536) (Thanks @CarloToso!) -- Ensure `HelpInfo.Category` is consistently a string (#18254) -- Remove `gcloud` from the legacy list because it's resolved to a .ps1 script (#18575) -- Add `gcloud` and `sqlcmd` to list to use legacy argument passing (#18559) -- Fix native access violation (#18545) (#18547) (Thanks @chrullrich!) -- Fix issue when completing the first command in a script with an empty array expression (#18355) (Thanks @MartinGC94!) -- Improve type inference of hashtable keys (#17907) (Thanks @MartinGC94!) -- Fix `Switch-Process` to copy the current env to the new process (#18452) -- Fix `Switch-Process` error to include the command that is not found (#18443) -- Update `Out-Printer` to remove all decorating ANSI escape sequences from PowerShell formatting (#18425) -- Web cmdlets set default charset encoding to `UTF8` (#18219) (Thanks @CarloToso!) -- Fix incorrect cmdlet name in the script used by `Restart-Computer` (#18374) (Thanks @urizen-source!) -- Add the function `cd~` (#18308) (Thanks @GigaScratch!) -- Fix type inference error for empty return statements (#18351) (Thanks @MartinGC94!) -- Fix the exception reporting in `ConvertFrom-StringData` (#18336) (Thanks @GigaScratch!) -- Implement `IDisposable` in `NamedPipeClient` (#18341) (Thanks @xtqqczze!) -- Replace command-error suggestion with new implementation based on subsystem plugin (#18252) -- Remove the `ProcessorArchitecture` portion from the full name as it's obsolete (#18320) -- Make the fuzzy searching flexible by passing in the fuzzy matcher (#18270) -- Add `-FuzzyMinimumDistance` parameter to `Get-Command` (#18261) -- Improve startup time by triggering initialization of additional types on background thread (#18195) -- Fix decompression in web cmdlets (#17955) (Thanks @iSazonov!) -- Add `CustomTableHeaderLabel` formatting to differentiate table header labels that are not property names (#17346) -- Remove the extra new line form List formatting (#18185) -- Minor update to the `FileInfo` table formatting on Unix to make it more concise (#18183) -- Fix Parent property on processes with complex name (#17545) (Thanks @jborean93!) -- Make PowerShell class not affiliate with `Runspace` when declaring the `NoRunspaceAffinity` attribute (#18138) -- Complete the progress bar rendering in `Invoke-WebRequest` when downloading is complete or cancelled (#18130) -- Display download progress in human readable format for `Invoke-WebRequest` (#14611) (Thanks @bergmeister!) -- Update `WriteConsole` to not use `stackalloc` for buffer with too large size (#18084) -- Filter out compiler generated types for `Add-Type -PassThru` (#18095) -- Fixing `CA2014` warnings and removing the warning suppression (#17982) (Thanks @creative-cloud!) -- Make experimental feature `PSNativeCommandArgumentPassing` stable (#18044) -- Make experimental feature `PSAMSIMethodInvocationLogging` stable (#18041) -- Handle `PSObject` argument specially in method invocation logging (#18060) -- Fix typos in `EventResource.resx` (#18063) (Thanks @eltociear!) -- Make experimental feature `PSRemotingSSHTransportErrorHandling` stable (#18046) -- Make experimental feature `PSExec` stable (#18045) -- Make experimental feature `PSCleanBlock` stable (#18043) -- Fix error formatting to use color defined in `$PSStyle.Formatting` (#17987) -- Remove unneeded use of `chmod 777` (#17974) -- Support mapping foreground/background `ConsoleColor` values to VT escape sequences (#17938) -- Make `pwsh` server modes implicitly not show banner (#17921) -- Add output type attributes for `Get-WinEvent` (#17948) (Thanks @MartinGC94!) -- Remove 1 second minimum delay in `Invoke-WebRequest` for small files, and prevent file-download-error suppression. (#17896) (Thanks @AAATechGuy!) -- Add completion for values in comparisons when comparing Enums (#17654) (Thanks @MartinGC94!) -- Fix positional argument completion (#17796) (Thanks @MartinGC94!) -- Fix member completion in attribute argument (#17902) (Thanks @MartinGC94!) -- Throw when too many parameter sets are defined (#17881) (Thanks @fflaten!) -- Limit searching of `charset` attribute in `meta` tag for HTML to first 1024 characters in webcmdlets (#17813) -- Fix `Update-Help` failing silently with implicit non-US culture. (#17780) (Thanks @dkaszews!) -- Add the `ValidateNotNullOrWhiteSpace` attribute (#17191) (Thanks @wmentha!) -- Improve enumeration of inferred types in pipeline (#17799) (Thanks @MartinGC94!) - -### Code Cleanup - -
- - - -

We thank the following contributors!

-

@MartinGC94, @CarloToso, @iSazonov, @xtqqczze, @turbedi, @trossr32, @eltociear, @AtariDreams, @jborean93

- -
- -
    -
  • Add TSAUpload for APIScan (#18446)
  • -
  • Use Pattern matching in ast.cs (#18794) (Thanks @MartinGC94!)
  • -
  • Cleanup webrequestpscmdlet.common.cs (#18596) (Thanks @CarloToso!)
  • -
  • Unify CreateFile pinvoke in SMA (#18751) (Thanks @iSazonov!)
  • -
  • Cleanup webresponseobject.common (#18785) (Thanks @CarloToso!)
  • -
  • InvokeRestMethodCommand.Common cleanup and merge partials (#18736) (Thanks @CarloToso!)
  • -
  • Replace GetDirectories in CimDscParser (#14319) (Thanks @xtqqczze!)
  • -
  • WebResponseObject.Common merge partials atomic commits (#18703) (Thanks @CarloToso!)
  • -
  • Enable pending test for Start-Process (#18724) (Thanks @iSazonov!)
  • -
  • Remove one CreateFileW (#18732) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport for WNetAddConnection2 (#18721) (Thanks @iSazonov!)
  • -
  • Use File.OpenHandle() instead CreateFileW pinvoke (#18722) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport for WNetGetConnection (#18690) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport - 1 (#18603) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA 3 (#18564) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA - 7 (#18594) (Thanks @iSazonov!)
  • -
  • Use static DateTime.UnixEpoch and RandomNumberGenerator.Fill() (#18621) (Thanks @turbedi!)
  • -
  • Rewrite Get-FileHash to use static HashData methods (#18471) (Thanks @turbedi!)
  • -
  • Replace DllImport with LibraryImport in SMA 8 (#18599) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA 4 (#18579) (Thanks @iSazonov!)
  • -
  • Remove NativeCultureResolver as dead code (#18582) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA 6 (#18581) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA 2 (#18543) (Thanks @iSazonov!)
  • -
  • Use standard SBCS detection (#18593) (Thanks @iSazonov!)
  • -
  • Remove unused pinvokes in RemoteSessionNamedPipe (#18583) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in SMA 5 (#18580) (Thanks @iSazonov!)
  • -
  • Remove SafeRegistryHandle (#18597) (Thanks @iSazonov!)
  • -
  • Remove ArchitectureSensitiveAttribute from the code base (#18598) (Thanks @iSazonov!)
  • -
  • Build COM adapter only on Windows (#18590)
  • -
  • Include timer instantiation for legacy telemetry in conditional compiler statements in Get-Help (#18475) (Thanks @trossr32!)
  • -
  • Convert DllImport to LibraryImport for recycle bin, clipboard, and computerinfo cmdlets (#18526)
  • -
  • Replace DllImport with LibraryImport in SMA 1 (#18520) (Thanks @iSazonov!)
  • -
  • Replace DllImport with LibraryImport in engine (#18496)
  • -
  • Fix typo in InitialSessionState.cs (#18435) (Thanks @eltociear!)
  • -
  • Remove remaining unused strings from resx files (#18448)
  • -
  • Use new LINQ Order() methods instead of OrderBy(static x => x) (#18395) (Thanks @turbedi!)
  • -
  • Make use of StringSplitOptions.TrimEntries when possible (#18412) (Thanks @turbedi!)
  • -
  • Replace some string.Join(string) calls with string.Join(char) (#18411) (Thanks @turbedi!)
  • -
  • Remove unused strings from FileSystem and Registry providers (#18403)
  • -
  • Use generic GetValues<T>, GetNames<T> enum methods (#18391) (Thanks @xtqqczze!)
  • -
  • Remove unused resource strings from SessionStateStrings (#18394)
  • -
  • Remove unused resource strings in System.Management.Automation (#18388)
  • -
  • Use Enum.HasFlags part 1 (#18386) (Thanks @xtqqczze!)
  • -
  • Remove unused strings from parser (#18383)
  • -
  • Remove unused strings from Utility module (#18370)
  • -
  • Remove unused console strings (#18369)
  • -
  • Remove unused strings from ConsoleInfoErrorStrings.resx (#18367)
  • -
  • Code cleanup in ContentHelper.Common.cs (#18288) (Thanks @CarloToso!)
  • -
  • Remove FusionAssemblyIdentity and GlobalAssemblyCache as they are not used (#18334) (Thanks @iSazonov!)
  • -
  • Remove some static initializations in StringManipulationHelper (#18243) (Thanks @xtqqczze!)
  • -
  • Use MemoryExtensions.IndexOfAny in PSv2CompletionCompleter (#18245) (Thanks @xtqqczze!)
  • -
  • Use MemoryExtensions.IndexOfAny in WildcardPattern (#18242) (Thanks @xtqqczze!)
  • -
  • Small cleanup of the stub code (#18301) (Thanks @CarloToso!)
  • -
  • Fix typo in RemoteRunspacePoolInternal.cs (#18263) (Thanks @eltociear!)
  • -
  • Some more code cleanup related to the use of PSVersionInfo (#18231)
  • -
  • Use MemoryExtensions.IndexOfAny in SessionStateInternal (#18244) (Thanks @xtqqczze!)
  • -
  • Use overload APIs that take char instead of string when it's possible (#18179) (Thanks @iSazonov!)
  • -
  • Replace UTF8Encoding(false) with Encoding.Default (#18144) (Thanks @xtqqczze!)
  • -
  • Remove unused variables (#18058) (Thanks @AtariDreams!)
  • -
  • Fix typo in PowerShell.Core.Instrumentation.man (#17963) (Thanks @eltociear!)
  • -
  • Migrate WinTrust functions to a common location (#17598) (Thanks @jborean93!)
  • -
- -
- -### Tools - -- Add a function to get the PR Back-port report (#18299) -- Add a workaround in automatic rebase workflow to continue on error (#18176) -- Update list of PowerShell team members in release tools (#17909) -- Don't block if we fail to create the comment (#17869) - -### Tests - -- Add `testexe.exe -echocmdline` to output raw command-line received by the process on Windows (#18591) -- Mark charset test as pending (#18511) -- Skip output rendering tests on Windows Server 2012 R2 (#18382) -- Increase timeout to make subsystem tests more reliable (#18380) -- Add missing -Tag 'CI' to describe blocks. (#18316) -- Use short path instead of multiple quotes in `Get-Item` test relying on node (#18250) -- Replace the CIM class used for `-Amended` parameter test (#17884) (Thanks @sethvs!) -- Stop ongoing progress-bar in `Write-Progress` test (#17880) (Thanks @fflaten!) - -### Build and Packaging Improvements - -
- - - -

We thank the following contributors!

- -
- -
    -
  • Fix reference assembly generation logic for Microsoft.PowerShell.Commands.Utility (#18818)
  • -
  • Update the cgmanifest (#18676)(#18521)(#18415)(#18408)(#18197)(#18111)(#18051)(#17913)(#17867)(#17934)(#18088)
  • -
  • Bump Microsoft.PowerShell.Native to the latest preview version v7.4.0-preview.1 (#18805)
  • -
  • Remove unnecessary reference to System.Runtime.CompilerServices.Unsafe (#18806)
  • -
  • Update the release tag in metadata.json for next preview (#18799)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18750)
  • -
  • Bump .NET SDK to version 7.0.101 (#18786)
  • -
  • Bump cirrus-actions/rebase from 1.7 to 1.8 (#18788)
  • -
  • Bump decode-uri-component from 0.2.0 to 0.2.2 (#18712)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0-4.final to 4.4.0 (#18562)
  • -
  • Bump Newtonsoft.Json from 13.0.1 to 13.0.2 (#18657)
  • -
  • Apply expected file permissions to Linux files after Authenticode signing (#18643)
  • -
  • Remove extra quotes after agent moves to pwsh 7.3 (#18577)
  • -
  • Don't install based on build-id for RPM (#18560)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.0 (#18487)
  • -
  • Bump minimatch from 3.0.4 to 3.1.2 (#18514)
  • -
  • Avoid depending on the pre-generated experimental feature list in private and CI builds (#18484)
  • -
  • Update release-MsixBundle.yml to add retries (#18465)
  • -
  • Bump System.Data.SqlClient from 4.8.4 to 4.8.5 in /src/Microsoft.PowerShell.SDK (#18515)
  • -
  • Bump to use internal .NET 7 GA build (#18508)
  • -
  • Insert the pre-release nuget feed before building test artifacts (#18507)
  • -
  • Add test for framework dependent package in release pipeline (#18506) (Internal 23139)
  • -
  • Update to azCopy 10 (#18509)
  • -
  • Fix issues with uploading changelog to GitHub release draft (#18504)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18442)
  • -
  • Add authenticode signing for assemblies on linux builds (#18440)
  • -
  • Do not remove penimc_cor3.dll from build (#18438)
  • -
  • Bump Microsoft.PowerShell.Native from 7.3.0-rc.1 to 7.3.0 (#18405)
  • -
  • Allow two-digit revisions in vPack package validation pattern (#18392)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18363)
  • -
  • Bump to .NET 7 RC2 official version (#18328)
  • -
  • Bump to .NET 7 to version 7.0.100-rc.2.22477.20 (#18286)
  • -
  • Replace win7 runtime with win8 and remove APISets (#18304)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18312)
  • -
  • Recurse the file listing. (#18277)
  • -
  • Create tasks to collect and publish hashes for build files. (#18276)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18262)
  • -
  • Remove ETW trace collection and uploading for CLR CAP (#18253)
  • -
  • Do not cleanup pwsh.deps.json for framework dependent packages (#18226)
  • -
  • Add branch counter to APIScan build (#18214)
  • -
  • Remove unnecessary native dependencies from the package (#18213)
  • -
  • Remove XML files for min-size package (#18189)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18216)
  • -
  • Bump Microsoft.PowerShell.Native from 7.3.0-preview.1 to 7.3.0-rc.1 (#18217)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18201)
  • -
  • Move ApiScan to compliance build (#18191)
  • -
  • Fix the verbose message when using dotnet-install.sh (#18184)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#18163)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18164)
  • -
  • Make the link to minimal package blob public during release (#18158)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18147)
  • -
  • Update MSI exit message (#18137)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.4.0-1.final to 4.4.0-2.final (#18132)
  • -
  • Re-enable building with Ready-to-Run (#18105)
  • -
  • Update DotnetRuntimeMetadata.json for .NET 7 RC1 build (#18091)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#18096)
  • -
  • Add schema for cgmanifest.json (#18036)
  • -
  • Bump Microsoft.CodeAnalysis.CSharp from 4.3.0-3.final to 4.3.0 (#18012)
  • -
  • Add XML reference documents to NuPkg files for SDK (#17997)
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.3.0 to 17.3.1 (#18000)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17988)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17983)
  • -
  • Bump Microsoft.CodeAnalysis.NetAnalyzers (#17945)
  • -
  • Make sure Security.types.ps1xml gets signed in release build (#17916)
  • -
  • Make Register Microsoft Update timeout (#17910)
  • -
  • Merge changes from v7.0.12 v7.2.6 and v7.3.0-preview.7
  • -
  • Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.0 (#17871)
  • -
- -
- -### Documentation and Help Content - -- Update readme and metadata for releases (#18780)(#18493)(#18393)(#18332)(#18128)(#17870) -- Remove 'please' and 'Core' from README.md per MS style guide (#18578) (Thanks @Rick-Anderson!) -- Change unsupported XML documentation tag (#18608) -- Change public API mention of `monad` to PowerShell (#18491) -- Update security reporting policy to recommend security portal for more streamlined reporting (#18437) -- Changelog for v7.3.0 (#18505) (Internal 23161) -- Replace `msh` in public API comment based documentation with PowerShell equivalent (#18483) -- Add missing XML doc elements for methods in `RunspaceFactory` (#18450) -- Changelog for `v7.3.0-rc.1` (#18400) -- Update changelogs for `v7.2.7` and `v7.0.13` (#18342) -- Update the changelog for v7.3.0-preview.8 (#18136) -- Add the `ConfigurationFile` option to the PowerShell help content (#18093) -- Update help content about the PowerShell flag `-NonInteractive` (#17952) - -[7.4.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.3.0-preview.8...v7.4.0-preview.1 +Information about PowerShell previews will be found in this file diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 5b6ac60b802..72003fd1bcd 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -1,13 +1,13 @@ { "sdk": { - "channel": "8.0.1xx-rc2", + "channel": "8.0.1xx", "quality": "daily", "qualityFallback": "preview", - "packageVersionPattern": "8.0.0-rc.2", - "sdkImageVersion": "8.0.100", - "nextChannel": "8.0.1xx-rc2", + "packageVersionPattern": "8.0.0", + "sdkImageVersion": "8.0.415", + "nextChannel": "8.0.1xx", "azureFeed": "", - "sdkImageOverride": "8.0.100-rc.2.23502.2" + "sdkImageOverride": "" }, "internalfeed": { "url": "" diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 72fbf3c86a8..fe03cfbc877 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -58,6 +58,11 @@ $(ReleaseTagVersionPart).$(ReleaseTagSemVersionPart) $(ReleaseTagVersionPart).$(GAIncrementValue) + + $(PSCoreFileVersion) + $([System.Version]::Parse($(PSCoreFileVersion)).Major).$([System.Version]::Parse($(PSCoreFileVersion)).Minor).6.$([System.Version]::Parse($(PSCoreFileVersion)).Revision) @@ -84,7 +89,7 @@ --> $(PSCoreFileVersion) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index b7d54550aff..68e3eed4704 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,124 +17,6 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 5.0.10 - Apache-2.0 - - -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright (c) 2019 David Fowler -Copyright (c) 2016 Richard Morris -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) Microsoft Corporation -Copyright (c) 2014-2018 Michael Daines -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2019-2020 West Wind Technologies -Copyright (c) 2010-2019 Google LLC. http://angular.io/license -Copyright (c) Sindre Sorhus (https://sindresorhus.com) - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - - - "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - - - - "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - - - - "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - - - "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - - - - "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - - - - "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - - - - "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - - - - "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - - - - "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - - - - "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); - -you may not use this file except in compliance with the License. - -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software - -distributed under the License is distributed on an "AS IS" BASIS, - -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -See the License for the specific language governing permissions and - -limitations under the License. - ---------------------------------------------------------- - ---------------------------------------------------------- - Markdig.Signed 0.33.0 - BSD-2-Clause @@ -153,10 +35,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND --------------------------------------------------------- -JetBrains.Annotations 2021.2.0 - MIT +Humanizer.Core 2.14.1 - MIT -Copyright (c) 2016 JetBrains http://www.jetbrains.com +Copyright .NET Foundation and Contributors +Copyright (c) .NET Foundation and Contributors MIT License @@ -172,15 +55,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Json.More.Net 1.9.0 - MIT +Json.More.Net 2.0.2 - MIT -(c) Microsoft 2023 -Copyright (c) 2022 Greg Dennis +Copyright (c) .NET Foundation and Contributors MIT License -Copyright (c) 2022 Greg Dennis +Copyright (c) .NET Foundation and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -205,15 +87,14 @@ SOFTWARE. --------------------------------------------------------- -JsonPointer.Net 3.0.3 - MIT +JsonPointer.Net 5.0.2 - MIT -(c) Microsoft 2023 -Copyright (c) 2022 Greg Dennis +Copyright (c) .NET Foundation and Contributors MIT License -Copyright (c) 2022 Greg Dennis +Copyright (c) .NET Foundation and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -238,7 +119,7 @@ SOFTWARE. --------------------------------------------------------- -JsonSchema.Net 5.2.6 - MIT +JsonSchema.Net 7.0.4 - MIT @@ -259,6 +140,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Microsoft.ApplicationInsights 2.21.0 - MIT +(c) Microsoft Corporation MIT License @@ -274,45 +156,62 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 5.0.0 - MIT +Microsoft.Bcl.AsyncInterfaces 8.0.0 - MIT -(c) Microsoft Corporation. +Copyright (c) Six Labors +(c) Microsoft Corporation Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. +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) 2012-2014, Yann Collet +Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin +Copyright (c) The Internet Society 1997 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -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 -Copyright (c) The Internet Society (2003). +Copyright (c) 2020 Mara Bos 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) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +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. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To +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 The MIT License (MIT) @@ -343,7 +242,7 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.7.0 - MIT +Microsoft.CodeAnalysis.Common 4.9.2 - MIT (c) Microsoft Corporation @@ -363,7 +262,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.7.0 - MIT +Microsoft.CodeAnalysis.CSharp 4.9.2 - MIT (c) Microsoft Corporation @@ -385,10 +284,41 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Management.Infrastructure 2.0.0 - MIT +Microsoft.Extensions.ObjectPool 8.0.19 - MIT -(c) Microsoft Corporation. +Copyright Jorn Zaefferer +(c) Microsoft Corporation +Copyright (c) Andrew Arnott +Copyright (c) 2015, Google Inc. +Copyright (c) 2019 David Fowler +Copyright (c) HTML5 Boilerplate +Copyright 2019 The gRPC Authors +Copyright (c) 2016 Richard Morris +Copyright (c) 1998 John D. Polstra +Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) Microsoft Corporation +Copyright (c) 2007 James Newton-King +Copyright (c) 2013 - 2018 AngleSharp +Copyright (c) 2000-2013 Julian Seward +Copyright (c) 2011-2021 Twitter, Inc. +Copyright (c) 2014-2018 Michael Daines +Copyright (c) 1996-1998 John D. Polstra +Copyright (c) 2013-2017, Milosz Krajewski +Copyright (c) .NET Foundation Contributors +Copyright (c) 2011-2021 The Bootstrap Authors +Copyright (c) 2019-2023 The Bootstrap Authors +Copyright (c) .NET Foundation and Contributors +Copyright (c) 2019-2020 West Wind Technologies +Copyright (c) 2007 John Birrell (jb@freebsd.org) +Copyright (c) 2011 Alex MacCaw (info@eribium.org) +Copyright (c) Nicolas Gallagher and Jonathan Neal +Copyright (c) 2010-2019 Google LLC. http://angular.io/license +Copyright (c) 2011 Nicolas Gallagher (nicolas@nicolasgallagher.com) +Copyright (c) 1989, 1993 The Regents of the University of California +Copyright (c) 1990, 1993 The Regents of the University of California +Copyright OpenJS Foundation and other contributors, https://openjsf.org +Copyright (c) Sindre Sorhus (https://sindresorhus.com) MIT License @@ -404,7 +334,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Management.Infrastructure.Runtime.Unix 2.0.0 - MIT +Microsoft.Management.Infrastructure 2.0.0 - MIT (c) Microsoft Corporation. @@ -423,11 +353,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.PowerShell.MarkdownRender 7.2.1 - MIT +Microsoft.Management.Infrastructure.Runtime.Unix 2.0.0 - MIT -(c) Microsoft Corporation -(c) Microsoft Corporation. PowerShell's Markdown Rendering project PowerShell Markdown Renderer +(c) Microsoft Corporation. MIT License @@ -443,11 +372,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.PowerShell.Native 7.3.2 - MIT +Microsoft.PowerShell.MarkdownRender 7.2.1 - MIT (c) Microsoft Corporation -Copyright (c) by P.J. Plauger +(c) Microsoft Corporation. PowerShell's Markdown Rendering project PowerShell Markdown Renderer MIT License @@ -463,9 +392,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Security.Extensions 1.2.0 - MIT +Microsoft.PowerShell.Native 7.3.2 - MIT +(c) Microsoft Corporation +Copyright (c) by P.J. Plauger MIT License @@ -481,62 +412,30 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry 4.7.0 - MIT +Microsoft.Security.Extensions 1.4.0 - MIT -(c) Microsoft Corporation. -Copyright (c) .NET Foundation. -Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson. -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2017 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) .NET Foundation Contributors -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors +(c) Microsoft Corporation +Copyright (c) Microsoft Corporation -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) -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.Registry.AccessControl 7.0.0 - MIT +Microsoft.Win32.Registry.AccessControl 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -546,11 +445,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -565,12 +466,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -584,7 +488,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -615,9 +518,10 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Win32.SystemEvents 7.0.0 - MIT +Microsoft.Win32.SystemEvents 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -627,11 +531,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -646,12 +552,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -665,7 +574,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -696,82 +604,20 @@ SOFTWARE. --------------------------------------------------------- -Microsoft.Windows.Compatibility 7.0.5 - MIT +Microsoft.Windows.Compatibility 8.0.19 - MIT (c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -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) 1998 Microsoft. To -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2005-2020 Rich Felker -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -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) 2021 csFastFloat authors -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 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 -Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors -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) 1995-2022 Jean-loup Gailly and Mark Adler -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. -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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To -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) -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. --------------------------------------------------------- @@ -811,9 +657,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -823,11 +670,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -842,12 +691,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -861,7 +713,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -892,9 +743,10 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -904,11 +756,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -923,12 +777,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -942,7 +799,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -973,9 +829,10 @@ SOFTWARE. --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -985,11 +842,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1004,12 +863,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1023,7 +885,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1054,29 +915,21 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.Data.SqlClient.sni 4.7.0 - MIT +runtime.native.System.Data.SqlClient.sni 4.4.0 - MIT -(c) Microsoft Corporation. -Copyright (c) .NET Foundation. -Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson. -Copyright (c) 2007 James Newton-King +(c) 2022 GitHub, Inc. +(c) Microsoft Corporation +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1991-2017 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) .NET Foundation Contributors Copyright (c) .NET Foundation and Contributors Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers The MIT License (MIT) @@ -1107,9 +960,10 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1119,11 +973,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1138,12 +994,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1157,7 +1016,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1188,9 +1046,10 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1200,11 +1059,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1219,12 +1080,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1238,7 +1102,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1269,9 +1132,10 @@ SOFTWARE. --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 7.0.0 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1281,11 +1145,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1300,12 +1166,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1319,7 +1188,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1350,9 +1218,10 @@ SOFTWARE. --------------------------------------------------------- -System.CodeDom 7.0.0 - MIT +System.CodeDom 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1362,11 +1231,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1381,12 +1252,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1400,7 +1274,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1431,23 +1304,27 @@ SOFTWARE. --------------------------------------------------------- -System.Collections.Immutable 7.0.0 - MIT +System.Collections.Immutable 8.0.0 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1455,19 +1332,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1476,12 +1354,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1512,9 +1390,10 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition 7.0.0 - MIT +System.ComponentModel.Composition 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1524,11 +1403,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1543,12 +1424,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1562,7 +1446,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1593,9 +1476,10 @@ SOFTWARE. --------------------------------------------------------- -System.ComponentModel.Composition.Registration 7.0.0 - MIT +System.ComponentModel.Composition.Registration 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1605,11 +1489,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1624,12 +1510,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1643,7 +1532,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1674,9 +1562,10 @@ SOFTWARE. --------------------------------------------------------- -System.Configuration.ConfigurationManager 7.0.0 - MIT +System.Configuration.ConfigurationManager 8.0.1 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -1686,11 +1575,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1705,12 +1596,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1724,7 +1618,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1755,23 +1648,27 @@ SOFTWARE. --------------------------------------------------------- -System.Data.Odbc 7.0.0 - MIT +System.Data.Odbc 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1779,19 +1676,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1800,12 +1698,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -1836,23 +1734,27 @@ SOFTWARE. --------------------------------------------------------- -System.Data.OleDb 7.0.0 - MIT +System.Data.OleDb 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -1860,19 +1762,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -1881,65 +1784,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -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.Data.SqlClient 4.8.5 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2017 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Portions (c) International Organization -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) .NET Foundation Contributors -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers The MIT License (MIT) @@ -1970,90 +1820,29 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.DiagnosticSource 7.0.2 - MIT +System.Data.SqlClient 4.9.0 - MIT (c) Microsoft Corporation -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -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) 1998 Microsoft. To -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2005-2020 Rich Felker -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -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) 2021 csFastFloat authors -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Portions (c) International Organization -Copyright (c) 2004-2006 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 -Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors -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) 1995-2022 Jean-loup Gailly and Mark Adler -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. -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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To -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) -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.EventLog 7.0.0 - MIT +System.Diagnostics.DiagnosticSource 8.0.1 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -2063,11 +1852,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2082,12 +1873,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2101,7 +1895,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2132,23 +1925,27 @@ SOFTWARE. --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 7.0.0 - MIT +System.Diagnostics.EventLog 8.0.2 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2156,19 +1953,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2177,12 +1975,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2213,23 +2011,27 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices 7.0.1 - MIT +System.Diagnostics.PerformanceCounter 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2237,19 +2039,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2258,12 +2061,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2294,9 +2097,10 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.AccountManagement 7.0.1 - MIT +System.DirectoryServices 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -2306,11 +2110,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2325,12 +2131,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2344,7 +2153,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2375,23 +2183,27 @@ SOFTWARE. --------------------------------------------------------- -System.DirectoryServices.Protocols 7.0.1 - MIT +System.DirectoryServices.AccountManagement 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2399,19 +2211,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2420,12 +2233,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2456,23 +2269,27 @@ SOFTWARE. --------------------------------------------------------- -System.Drawing.Common 7.0.0 - MIT +System.DirectoryServices.Protocols 8.0.2 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2480,19 +2297,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2501,12 +2319,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2537,23 +2355,62 @@ SOFTWARE. --------------------------------------------------------- -System.Formats.Asn1 7.0.0 - MIT +System.Drawing.Common 8.0.19 - MIT + + +(c) Microsoft Corporation +Copyright (c) Sven Groot (Ookii.org) 2009 +Copyright (c) .NET Foundation and Contributors + +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.Formats.Asn1 8.0.2 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2561,19 +2418,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2582,12 +2440,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2618,23 +2476,27 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 7.0.0 - MIT +System.IO.Packaging 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2642,19 +2504,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2663,12 +2526,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2699,9 +2562,10 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Ports 7.0.0 - MIT +System.IO.Ports 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -2711,11 +2575,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2730,12 +2596,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2749,7 +2618,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2780,9 +2648,10 @@ SOFTWARE. --------------------------------------------------------- -System.Management 7.0.2 - MIT +System.Management 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -2792,11 +2661,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2811,12 +2682,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2830,7 +2704,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2861,23 +2734,27 @@ SOFTWARE. --------------------------------------------------------- -System.Net.Http.WinHttpHandler 7.0.0 - MIT +System.Net.Http.WinHttpHandler 8.0.3 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -2885,19 +2762,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -2906,12 +2784,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -2945,20 +2823,22 @@ SOFTWARE. System.Numerics.Vectors 4.5.0 - MIT -(c) Microsoft Corporation. +(c) 2023 GitHub, Inc. +(c) Microsoft Corporation +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. -(c) 1997-2005 Sean Eron Anderson. +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1991-2017 Unicode, Inc. +Copyright (c) 2015 The Chromium Authors Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. Copyright (c) 2004-2006 Intel Corporation Copyright (c) .NET Foundation Contributors Copyright (c) .NET Foundation and Contributors Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors +Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers The MIT License (MIT) @@ -3025,9 +2905,10 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Context 7.0.0 - MIT +System.Reflection.Context 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -3037,11 +2918,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3056,12 +2939,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3075,7 +2961,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3159,23 +3044,28 @@ SOFTWARE. --------------------------------------------------------- -System.Reflection.Metadata 7.0.0 - MIT +System.Reflection.Metadata 8.0.0 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors +Gets the Copyright Table (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3183,19 +3073,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3204,12 +3095,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3240,9 +3131,10 @@ SOFTWARE. --------------------------------------------------------- -System.Runtime.Caching 7.0.0 - MIT +System.Runtime.Caching 8.0.1 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -3252,11 +3144,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3271,12 +3165,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3290,7 +3187,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3324,42 +3220,46 @@ SOFTWARE. System.Runtime.CompilerServices.Unsafe 6.0.0 - MIT -(c) Microsoft Corporation. +(c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2005-2020 Rich Felker Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2020 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, 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 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. Copyright (c) 2004-2006 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 -Copyright (c) The Internet Society (2003). Copyright (c) .NET Foundation and Contributors Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +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. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -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) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3391,45 +3291,50 @@ SOFTWARE. --------------------------------------------------------- -System.Security.AccessControl 6.0.0 - MIT +System.Security.AccessControl 6.0.1 - MIT -(c) Microsoft Corporation. +(c) Microsoft Corporation Copyright (c) Andrew Arnott +Copyright 2019 LLVM Project Copyright 2018 Daniel Lemire -Copyright 2012 the V8 project -Copyright (c) .NET Foundation. +Copyright (c) .NET Foundation Copyright (c) 2011, Google Inc. +Copyright (c) 2020 Dan Shechter +(c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To -(c) 1997-2005 Sean Eron Anderson. Copyright (c) 2017 Yoshifumi Kawai +Copyright (c) 2005-2020 Rich Felker Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King Copyright (c) 2012-2014, Yann Collet +Copyright (c) 1991-2020 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp +Copyright 2012 the V8 project authors +Copyright (c) 2011-2020 Microsoft Corp Copyright (c) 2015-2017, 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 Portions (c) International Organization -Copyright (c) 2015 The Chromium Authors. -Copyright (c) The Internet Society 1997. Copyright (c) 2004-2006 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 -Copyright (c) The Internet Society (2003). Copyright (c) .NET Foundation and Contributors Copyright (c) 2019 Microsoft Corporation, Daan Leijen Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler +Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. +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. -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS -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) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3461,23 +3366,27 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Pkcs 7.0.3 - MIT +System.Security.Cryptography.Pkcs 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3485,19 +3394,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3506,12 +3416,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3542,9 +3452,10 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 7.0.1 - MIT +System.Security.Cryptography.ProtectedData 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -3554,11 +3465,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3573,12 +3486,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3592,7 +3508,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3623,23 +3538,27 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Cryptography.Xml 7.0.1 - MIT +System.Security.Cryptography.Xml 8.0.2 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3647,19 +3566,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3668,12 +3588,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -3704,9 +3624,10 @@ SOFTWARE. --------------------------------------------------------- -System.Security.Permissions 7.0.0 - MIT +System.Security.Permissions 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -3716,11 +3637,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -3735,12 +3658,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -3754,7 +3680,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4034,9 +3959,10 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 7.0.0 - MIT +System.ServiceModel.Syndication 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -4046,11 +3972,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4065,12 +3993,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4084,7 +4015,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4115,23 +4045,27 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 7.0.1 - MIT +System.ServiceProcess.ServiceController 8.0.1 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4139,19 +4073,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4160,12 +4095,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4196,9 +4131,10 @@ SOFTWARE. --------------------------------------------------------- -System.Speech 7.0.0 - MIT +System.Speech 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -4208,11 +4144,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4227,12 +4165,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4246,7 +4187,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4277,23 +4217,27 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encoding.CodePages 7.0.0 - MIT +System.Text.Encoding.CodePages 8.0.0 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4301,19 +4245,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4322,12 +4267,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4358,23 +4303,27 @@ SOFTWARE. --------------------------------------------------------- -System.Text.Encodings.Web 7.0.0 - MIT +System.Text.Encodings.Web 8.0.0 - MIT +Copyright (c) 2021 +Copyright (c) Six Labors (c) Microsoft Corporation 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) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4382,19 +4331,20 @@ 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) 2021 csFastFloat authors Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015 The Chromium Authors Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 -Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4403,86 +4353,12 @@ 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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers +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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To - -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.Text.Json 6.0.2 - MIT - - -(c) Microsoft Corporation -Copyright (c) Andrew Arnott -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) 1998 Microsoft. To -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2005-2020 Rich Felker -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 2012-2014, Yann Collet -Copyright (c) 1991-2020 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright 2012 the V8 project authors -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, 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 -Portions (c) International Organization -Copyright (c) 2004-2006 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 -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler -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. -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4513,9 +4389,10 @@ SOFTWARE. --------------------------------------------------------- -System.Threading.AccessControl 7.0.1 - MIT +System.Threading.AccessControl 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -4525,11 +4402,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4544,12 +4423,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4563,7 +4445,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) @@ -4594,9 +4475,12 @@ SOFTWARE. --------------------------------------------------------- -System.Web.Services.Description 4.10.0 - MIT +System.Web.Services.Description 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) @@ -4627,9 +4511,10 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 7.0.0 - MIT +System.Windows.Extensions 8.0.0 - MIT +Copyright (c) Six Labors (c) Microsoft Corporation Copyright (c) Andrew Arnott Copyright 2019 LLVM Project @@ -4639,11 +4524,13 @@ Copyright (c) 2011, Google Inc. Copyright (c) 2020 Dan Shechter (c) 1997-2005 Sean Eron Anderson Copyright (c) 1998 Microsoft. To +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) 2012-2014, Yann Collet Copyright (c) 1991-2022 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright 2012 the V8 project authors @@ -4658,12 +4545,15 @@ Copyright (c) 2018 Alexander Chermyanin Copyright (c) The Internet Society 1997 Portions (c) International Organization 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 Copyright (c) 2020 Mara Bos 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) @@ -4677,7 +4567,6 @@ 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) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To The MIT License (MIT) diff --git a/assets/AppImageThirdPartyNotices.txt b/assets/AppImageThirdPartyNotices.txt deleted file mode 100644 index d492e7c3b53..00000000000 --- a/assets/AppImageThirdPartyNotices.txt +++ /dev/null @@ -1,506 +0,0 @@ -------------------------------------------- START OF THIRD PARTY NOTICE ----------------------------------------- - - This file is based on or incorporates material from the projects listed below (Third Party IP). The original copyright notice and the license under which Microsoft received such Third Party IP, are set forth below. Such licenses and notices are provided for informational purposes only. Microsoft licenses the Third Party IP to you under the licensing terms for the Microsoft product. Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, estoppel or otherwise. - - - - -Copyright (c) 1991-2016 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in http://www.unicode.org/copyright.html - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that either -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, or -(b) this copyright and permission notice appear in associated -Documentation. - -THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. - ---------------------- - -Third-Party Software Licenses - -This section contains third-party software notices and/or additional -terms for licensed third-party software components included within ICU -libraries. - -1. ICU License - ICU 1.8.1 to ICU 57.1 - -COPYRIGHT AND PERMISSION NOTICE - -Copyright (c) 1995-2016 International Business Machines Corporation and others -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, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, provided that the above -copyright notice(s) and this permission notice appear in all copies of -the Software and that both the above copyright notice(s) and this -permission notice appear in supporting documentation. - -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 -OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY -SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER -RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF -CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -of the copyright holder. - -All trademarks and registered trademarks mentioned herein are the -property of their respective owners. - -2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) - - # The Google Chrome software developed by Google is licensed under - # the BSD license. Other software included in this distribution is - # provided under other licenses, as set forth below. - # - # The BSD License - # https://opensource.org/licenses/bsd-license.php - # Copyright (C) 2006-2008, Google Inc. - # - # All rights reserved. - # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions are met: - # - # Redistributions of source code must retain the above copyright notice, - # this list of conditions and the following disclaimer. - # Redistributions in binary form must reproduce the above - # copyright notice, this list of conditions and the following - # disclaimer in the documentation and/or other materials provided with - # the distribution. - # Neither the name of Google Inc. nor the names of its - # contributors may be used to endorse or promote products derived from - # this software without specific prior written permission. - # - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # - # - # The word list in cjdict.txt are generated by combining three word lists - # listed below with further processing for compound word breaking. The - # frequency is generated with an iterative training against Google web - # corpora. - # - # * Libtabe (Chinese) - # - https://sourceforge.net/project/?group_id=1519 - # - Its license terms and conditions are shown below. - # - # * IPADIC (Japanese) - # - http://chasen.aist-nara.ac.jp/chasen/distribution.html - # - Its license terms and conditions are shown below. - # - # ---------COPYING.libtabe ---- BEGIN-------------------- - # - # /* - # * Copyrighy (c) 1999 TaBE Project. - # * Copyright (c) 1999 Pai-Hsiang Hsiao. - # * All rights reserved. - # * - # * Redistribution and use in source and binary forms, with or without - # * modification, are permitted provided that the following conditions - # * are met: - # * - # * . Redistributions of source code must retain the above copyright - # * notice, this list of conditions and the following disclaimer. - # * . Redistributions in binary form must reproduce the above copyright - # * notice, this list of conditions and the following disclaimer in - # * the documentation and/or other materials provided with the - # * distribution. - # * . Neither the name of the TaBE Project nor the names of its - # * contributors may be used to endorse or promote products derived - # * from this software without specific prior written permission. - # * - # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - # * OF THE POSSIBILITY OF SUCH DAMAGE. - # */ - # - # /* - # * Copyright (c) 1999 Computer Systems and Communication Lab, - # * Institute of Information Science, Academia - # * Sinica. All rights reserved. - # * - # * Redistribution and use in source and binary forms, with or without - # * modification, are permitted provided that the following conditions - # * are met: - # * - # * . Redistributions of source code must retain the above copyright - # * notice, this list of conditions and the following disclaimer. - # * . Redistributions in binary form must reproduce the above copyright - # * notice, this list of conditions and the following disclaimer in - # * the documentation and/or other materials provided with the - # * distribution. - # * . Neither the name of the Computer Systems and Communication Lab - # * nor the names of its contributors may be used to endorse or - # * promote products derived from this software without specific - # * prior written permission. - # * - # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - # * OF THE POSSIBILITY OF SUCH DAMAGE. - # */ - # - # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, - # University of Illinois - # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 - # - # ---------------COPYING.libtabe-----END-------------------------------- - # - # - # ---------------COPYING.ipadic-----BEGIN------------------------------- - # - # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science - # and Technology. All Rights Reserved. - # - # Use, reproduction, and distribution of this software is permitted. - # Any copy of this software, whether in its original form or modified, - # must include both the above copyright notice and the following - # paragraphs. - # - # Nara Institute of Science and Technology (NAIST), - # the copyright holders, disclaims all warranties with regard to this - # software, including all implied warranties of merchantability and - # fitness, in no event shall NAIST be liable for - # any special, indirect or consequential damages or any damages - # whatsoever resulting from loss of use, data or profits, whether in an - # action of contract, negligence or other tortuous action, arising out - # of or in connection with the use or performance of this software. - # - # A large portion of the dictionary entries - # originate from ICOT Free Software. The following conditions for ICOT - # Free Software applies to the current dictionary as well. - # - # Each User may also freely distribute the Program, whether in its - # original form or modified, to any third party or parties, PROVIDED - # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear - # on, or be attached to, the Program, which is distributed substantially - # in the same form as set out herein and that such intended - # distribution, if actually made, will neither violate or otherwise - # contravene any of the laws and regulations of the countries having - # jurisdiction over the User or the intended distribution itself. - # - # NO WARRANTY - # - # The program was produced on an experimental basis in the course of the - # research and development conducted during the project and is provided - # to users as so produced on an experimental basis. Accordingly, the - # program is provided without any warranty whatsoever, whether express, - # implied, statutory or otherwise. The term "warranty" used herein - # includes, but is not limited to, any warranty of the quality, - # performance, merchantability and fitness for a particular purpose of - # the program and the nonexistence of any infringement or violation of - # any right of any third party. - # - # Each user of the program will agree and understand, and be deemed to - # have agreed and understood, that there is no warranty whatsoever for - # the program and, accordingly, the entire risk arising from or - # otherwise connected with the program is assumed by the user. - # - # Therefore, neither ICOT, the copyright holder, or any other - # organization that participated in or was otherwise related to the - # development of the program and their respective officials, directors, - # officers and other employees shall be held liable for any and all - # damages, including, without limitation, general, special, incidental - # and consequential damages, arising out of or otherwise in connection - # with the use or inability to use the program or any product, material - # or result produced or otherwise obtained by using the program, - # regardless of whether they have been advised of, or otherwise had - # knowledge of, the possibility of such damages at any time during the - # project or thereafter. Each user will be deemed to have agreed to the - # foregoing by his or her commencement of use of the program. The term - # "use" as used herein includes, but is not limited to, the use, - # modification, copying and distribution of the program and the - # production of secondary products from the program. - # - # In the case where the program, whether in its original form or - # modified, was distributed or delivered to or received by a user from - # any person, organization or entity other than ICOT, unless it makes or - # grants independently of ICOT any specific warranty to the user in - # writing, such person, organization or entity, will also be exempted - # from and not be held liable to the user for any such damages as noted - # above as far as the program is concerned. - # - # ---------------COPYING.ipadic-----END---------------------------------- - -3. Lao Word Break Dictionary Data (laodict.txt) - - # Copyright (c) 2013 International Business Machines Corporation - # and others. All Rights Reserved. - # - # Project: https://code.google.com/p/lao-dictionary/ - # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt - # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt - # (copied below) - # - # This file is derived from the above dictionary, with slight - # modifications. - # ---------------------------------------------------------------------- - # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. - # All rights reserved. - # - # Redistribution and use in source and binary forms, with or without - # modification, - # are permitted provided that the following conditions are met: - # - # - # Redistributions of source code must retain the above copyright notice, this - # list of conditions and the following disclaimer. Redistributions in - # binary form must reproduce the above copyright notice, this list of - # conditions and the following disclaimer in the documentation and/or - # other materials provided with the distribution. - # - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - # OF THE POSSIBILITY OF SUCH DAMAGE. - # -------------------------------------------------------------------------- - -4. Burmese Word Break Dictionary Data (burmesedict.txt) - - # Copyright (c) 2014 International Business Machines Corporation - # and others. All Rights Reserved. - # - # This list is part of a project hosted at: - # github.com/kanyawtech/myanmar-karen-word-lists - # - # -------------------------------------------------------------------------- - # Copyright (c) 2013, LeRoy Benjamin Sharon - # All rights reserved. - # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions - # are met: Redistributions of source code must retain the above - # copyright notice, this list of conditions and the following - # disclaimer. Redistributions in binary form must reproduce the - # above copyright notice, this list of conditions and the following - # disclaimer in the documentation and/or other materials provided - # with the distribution. - # - # Neither the name Myanmar Karen Word Lists, nor the names of its - # contributors may be used to endorse or promote products derived - # from this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS - # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - # SUCH DAMAGE. - # -------------------------------------------------------------------------- - -5. Time Zone Database - - ICU uses the public domain data and code derived from Time Zone -Database for its time zone support. The ownership of the TZ database -is explained in BCP 175: Procedure for Maintaining the Time Zone -Database section 7. - - # 7. Database Ownership - # - # The TZ database itself is not an IETF Contribution or an IETF - # document. Rather it is a pre-existing and regularly updated work - # that is in the public domain, and is intended to remain in the - # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do - # not apply to the TZ Database or contributions that individuals make - # to it. Should any claims be made and substantiated against the TZ - # Database, the organization that is providing the IANA - # Considerations defined in this RFC, under the memorandum of - # understanding with the IETF, currently ICANN, may act in accordance - # with all competent court orders. No ownership claims will be made - # by ICANN or the IETF Trust on the database or the code. Any person - # making a contribution to the database or code waives all rights to - # future claims in that contribution or in the TZ Database. - - -8. liblzma - -XZ Utils Licensing -================== - - Different licenses apply to different files in this package. Here - is a rough summary of which licenses apply to which parts of this - package (but check the individual files to be sure!): - - - liblzma is in the public domain. - - - xz, xzdec, and lzmadec command line tools are in the public - domain unless GNU getopt_long had to be compiled and linked - in from the lib directory. The getopt_long code is under - GNU LGPLv2.1+. - - - The scripts to grep, diff, and view compressed files have been - adapted from gzip. These scripts and their documentation are - under GNU GPLv2+. - - - All the documentation in the doc directory and most of the - XZ Utils specific documentation files in other directories - are in the public domain. - - - Translated messages are in the public domain. - - - The build system contains public domain files, and files that - are under GNU GPLv2+ or GNU GPLv3+. None of these files end up - in the binaries being built. - - - Test files and test code in the tests directory, and debugging - utilities in the debug directory are in the public domain. - - - The extra directory may contain public domain files, and files - that are under various free software licenses. - - You can do whatever you want with the files that have been put into - the public domain. If you find public domain legally problematic, - take the previous sentence as a license grant. If you still find - the lack of copyright legally problematic, you have too many - lawyers. - - As usual, this software is provided "as is", without any warranty. - - If you copy significant amounts of public domain code from XZ Utils - into your project, acknowledging this somewhere in your software is - polite (especially if it is proprietary, non-free software), but - naturally it is not legally required. Here is an example of a good - notice to put into "about box" or into documentation: - - This software includes code from XZ Utils . - - The following license texts are included in the following files: - - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1 - - COPYING.GPLv2: GNU General Public License version 2 - - COPYING.GPLv3: GNU General Public License version 3 - - Note that the toolchain (compiler, linker etc.) may add some code - pieces that are copyrighted. Thus, it is possible that e.g. liblzma - binary wouldn't actually be in the public domain in its entirety - even though it contains no copyrighted code from the XZ Utils source - package. - - If you have questions, don't hesitate to ask the author(s) for more - information. - - -BSD License - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -9. libunwind - -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. - -Provided for Informational Purposes Only - -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: - -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. - - - - ------------------------------------------------ END OF THIRD PARTY NOTICE ------------------------------------------ diff --git a/assets/manpage/pwsh.1 b/assets/manpage/pwsh.1 new file mode 100644 index 00000000000..14c191241a9 --- /dev/null +++ b/assets/manpage/pwsh.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "PWSH" "1" "October 2023" "" "" +. +.SH "NAME" +\fBpwsh\fR \- PowerShell command\-line shell and \.NET REPL +. +.SH "SYNOPSIS" +\fBpwsh\fR [\fB\-Login\fR] [ [\fB\-File\fR] \fIfilePath\fR [args] ] [\fB\-Command\fR { \- | \fIscript\-block\fR [\fB\-args\fR \fIarg\-array\fR] | \fIstring\fR [\fICommandParameters\fR] } ] [\fB\-ConfigurationFile\fR \fIfilePath\fR] [\fB\-ConfigurationName\fR \fIstring\fR] [\fB\-CustomPipeName\fR \fIstring\fR] [\fB\-EncodedArguments\fR \fIBase64EncodedArguments\fR] [\fB\-EncodedCommand\fR \fIBase64EncodedCommand\fR] [\fB\-ExecutionPolicy\fR \fIExecutionPolicy\fR] [\fB\-Help\fR] [\fB\-InputFormat\fR {Text | XML}] [\fB\-Interactive\fR] [\fB\-MTA\fR] [\fB\-NoExit\fR] [\fB\-NoLogo\fR] [\fB\-NonInteractive\fR] [\fB\-NoProfile\fR] [\fB\-NoProfileLoadTime\fR] [\fB\-OutputFormat\fR {Text | XML}] [\fB\-SettingsFile\fR \fIfilePath\fR] [\fB\-SSHServerMode\fR] [\fB\-STA\fR] [\fB\-Version\fR] [\fB\-WindowStyle\fR diff --git a/assets/pwsh.1.ronn b/assets/manpage/pwsh.1.ronn similarity index 100% rename from assets/pwsh.1.ronn rename to assets/manpage/pwsh.1.ronn diff --git a/assets/wix/Product.wxs b/assets/wix/Product.wxs index 6f34a33849e..0b525288ae1 100644 --- a/assets/wix/Product.wxs +++ b/assets/wix/Product.wxs @@ -20,6 +20,15 @@ + + + + + + + + + @@ -35,6 +44,12 @@ + + + + + + + + + + + + + + + + not INSTALLFOLDER and PREVIOUS_INSTALLFOLDER + + + + + + + + not ADD_PATH and PREVIOUS_ADD_PATH + + + not ADD_PATH + + + ADD_PATH<>1 + + + not ADD_PATH + + + + + + + + not REGISTER_MANIFEST and PREVIOUS_REGISTER_MANIFEST + + + not REGISTER_MANIFEST + + + REGISTER_MANIFEST<>1 + + + not REGISTER_MANIFEST + + + + + + + + not ENABLE_PSREMOTING and PREVIOUS_ENABLE_PSREMOTING + + + ENABLE_PSREMOTING<>1 + + + not ENABLE_PSREMOTING + + + + + + + + not DISABLE_TELEMETRY and PREVIOUS_DISABLE_TELEMETRY + + + DISABLE_TELEMETRY<>1 + + + not DISABLE_TELEMETRY + + + + + + + + not ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL and PREVIOUS_ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL + + + ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL<>1 + + + not ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL + + + + + + + + not ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL and PREVIOUS_ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL + + + ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL<>1 + + + not ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL + + + + + + + + not USE_MU and PREVIOUS_USE_MU + + + not USE_MU + + + USE_MU<>1 + + + not USE_MU + + + + + + + + not ENABLE_MU and PREVIOUS_ENABLE_MU + + + not ENABLE_MU + + + ENABLE_MU<>1 + + + not ENABLE_MU + + + + + @@ -221,7 +403,7 @@ - DISABLE_TELEMETRY + DISABLE_TELEMETRY=1 @@ -236,7 +418,7 @@ - ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL + ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 @@ -286,7 +468,7 @@ - ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL + ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 @@ -296,6 +478,17 @@ + + + + + + + + + + + @@ -319,8 +512,6 @@ - - @@ -328,12 +519,12 @@ - - - - - - + + + + + + The application is distributed under the MIT license.]]> @@ -354,8 +545,6 @@ - - diff --git a/assets/wix/bundle.wxs b/assets/wix/bundle.wxs index dc577cb36b0..a2d93b47099 100644 --- a/assets/wix/bundle.wxs +++ b/assets/wix/bundle.wxs @@ -9,6 +9,15 @@ + + + + + + + + + diff --git a/build.psm1 b/build.psm1 index ec95e071bf7..78d966c73ae 100644 --- a/build.psm1 +++ b/build.psm1 @@ -19,7 +19,8 @@ $script:Options = $null $dotnetMetadata = Get-Content $PSScriptRoot/DotnetRuntimeMetadata.json | ConvertFrom-Json $dotnetCLIChannel = $dotnetMetadata.Sdk.Channel $dotnetCLIQuality = $dotnetMetadata.Sdk.Quality -$dotnetAzureFeed = if (-not $env:__DOTNET_RUNTIME_FEED ) { $dotnetMetadata.Sdk.azureFeed } +# __DOTNET_RUNTIME_FEED and __DOTNET_RUNTIME_FEED_KEY are private variables used in release builds +$dotnetAzureFeed = if ([string]::IsNullOrWhiteSpace($env:__DOTNET_RUNTIME_FEED)) { $dotnetMetadata.Sdk.azureFeed } else { $env:__DOTNET_RUNTIME_FEED } $dotnetAzureFeedSecret = $env:__DOTNET_RUNTIME_FEED_KEY $dotnetSDKVersionOveride = $dotnetMetadata.Sdk.sdkImageOverride $dotnetCLIRequiredVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version @@ -178,6 +179,8 @@ function Get-EnvironmentInformation $environment += @{'IsUbuntu16' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '16.04'} $environment += @{'IsUbuntu18' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '18.04'} $environment += @{'IsUbuntu20' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '20.04'} + $environment += @{'IsUbuntu22' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '22.04'} + $environment += @{'IsUbuntu24' = $environment.IsUbuntu -and $LinuxInfo.VERSION_ID -match '24.04'} $environment += @{'IsCentOS' = $LinuxInfo.ID -match 'centos' -and $LinuxInfo.VERSION_ID -match '7'} $environment += @{'IsFedora' = $LinuxInfo.ID -match 'fedora' -and $LinuxInfo.VERSION_ID -ge 24} $environment += @{'IsOpenSUSE' = $LinuxInfo.ID -match 'opensuse'} @@ -190,6 +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' -or $LinuxInfo.ID -match 'azurelinux'} # Workaround for temporary LD_LIBRARY_PATH hack for Fedora 24 # https://github.com/PowerShell/PowerShell/issues/2511 @@ -203,7 +207,8 @@ function Get-EnvironmentInformation $environment.IsUbuntu -or $environment.IsRedHatFamily -or $environment.IsSUSEFamily -or - $environment.IsAlpine) + $environment.IsAlpine -or + $environment.IsMariner) ) { if ($SkipLinuxDistroCheck) { Write-Warning "The current OS : $($LinuxInfo.ID) is not supported for building PowerShell." @@ -304,6 +309,9 @@ function Start-PSBuild { # it's useful for development, to do a quick changes in the engine [switch]$SMAOnly, + # Use nuget.org instead of the PowerShell specific feed + [switch]$UseNuGetOrg, + # These runtimes must match those in project.json # We do not use ValidateScript since we want tab completion # If this parameter is not provided it will get determined automatically. @@ -345,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) { @@ -359,6 +367,12 @@ function Start-PSBuild { } } + if ($UseNuGetOrg) { + Switch-PSNugetConfig -Source Public + } else { + Write-Verbose -Message "Using default feeds which are Microsoft, use `-UseNuGetOrg` to switch to Public feeds" -Verbose + } + function Stop-DevPowerShell { Get-Process pwsh* | Where-Object { @@ -371,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 @@ -379,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 } } @@ -511,7 +526,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 @@ -541,6 +558,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 @@ -588,6 +606,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) { @@ -595,6 +614,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(';') } @@ -608,6 +628,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Publish Reference Assemblies" if ($ReleaseTag) { $psVersion = $ReleaseTag @@ -650,10 +671,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*") { @@ -696,11 +720,16 @@ Fix steps: if ($config.Count -gt 0) { $configPublishPath = Join-Path -Path $publishPath -ChildPath "powershell.config.json" Set-Content -Path $configPublishPath -Value ($config | ConvertTo-Json) -Force -ErrorAction Stop + } 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 @@ -715,6 +744,56 @@ Fix steps: } } +function Switch-PSNugetConfig { + param( + [Parameter(Mandatory = $true, ParameterSetName = 'user')] + [Parameter(Mandatory = $true, ParameterSetName = 'nouser')] + [ValidateSet('Public', 'Private', 'NuGetOnly')] + [string] $Source, + + [Parameter(Mandatory = $true, ParameterSetName = 'user')] + [string] $UserName, + + [Parameter(Mandatory = $true, ParameterSetName = 'user')] + [string] $ClearTextPAT + ) + + Clear-PipelineNugetAuthentication + + $extraParams = @() + if ($UserName) { + $extraParams = @{ + UserName = $UserName + ClearTextPAT = $ClearTextPAT + } + } + + $dotnetSdk = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v2'; Name = 'dotnet' } + $gallery = [NugetPackageSource] @{Url = 'https://www.powershellgallery.com/api/v2/'; Name = 'psgallery' } + $nugetorg = [NugetPackageSource] @{Url = 'https://api.nuget.org/v3/index.json'; Name = 'nuget.org' } + if ( $Source -eq 'Public') { + New-NugetConfigFile -NugetPackageSource $nugetorg, $dotnetSdk -Destination "$PSScriptRoot/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams + } elseif ( $Source -eq 'NuGetOnly') { + New-NugetConfigFile -NugetPackageSource $nugetorg -Destination "$PSScriptRoot/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $gallery -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams + } elseif ( $Source -eq 'Private') { + $powerShellPackages = [NugetPackageSource] @{Url = 'https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShell/nuget/v3/index.json'; Name = 'powershell' } + + New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/" @extraParams + New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/src/Modules/" @extraParams + New-NugetConfigFile -NugetPackageSource $powerShellPackages -Destination "$PSScriptRoot/test/tools/Modules/" @extraParams + } else { + throw "Unknown source: $Source" + } + + if ($UserName -or $ClearTextPAT) { + Set-PipelineNugetAuthentication + } +} + function Test-ShouldGenerateExperimentalFeatures { param( @@ -775,7 +854,7 @@ function Restore-PSPackage if (-not $ProjectDirs) { - $ProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules") + $ProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules", "$PSScriptRoot/tools/wix") if ($Options.Runtime -like 'fxdependent*') { $ProjectDirs += "$PSScriptRoot/src/Microsoft.PowerShell.GlobalTool.Shim" @@ -818,6 +897,10 @@ function Restore-PSPackage $RestoreArguments += "--interactive" } + if ($env:ENABLE_MSBUILD_BINLOGS) { + $RestoreArguments += '-bl' + } + $ProjectDirs | ForEach-Object { $project = $_ Write-Log -message "Run dotnet restore $project $RestoreArguments" @@ -835,6 +918,23 @@ function Restore-PSPackage $retryCount++ if($retryCount -ge $maxTries) { + if ($env:ENABLE_MSBUILD_BINLOGS) { + if ( Test-Path ./msbuild.binlog ) { + if (!(Test-Path $env:OB_OUTPUTDIRECTORY -PathType Container)) { + $null = New-Item -path $env:OB_OUTPUTDIRECTORY -ItemType Directory -Force -Verbose + } + + $projectName = Split-Path -Leaf -Path $project + $binlogFileName = "${projectName}.msbuild.binlog" + if ($IsMacOS) { + $resolvedPath = (Resolve-Path -Path ./msbuild.binlog).ProviderPath + Write-Host "##vso[artifact.upload containerfolder=$binLogFileName;artifactname=$binLogFileName]$resolvedPath" + } else { + Copy-Item -Path ./msbuild.binlog -Destination "$env:OB_OUTPUTDIRECTORY/${projectName}.msbuild.binlog" -Verbose + } + } + } + throw } continue @@ -1137,6 +1237,7 @@ function Get-PesterTag { # testing PowerShell remote custom connections. function Publish-CustomConnectionTestModule { + Write-LogGroupStart -Title "Publish-CustomConnectionTestModule" $sourcePath = "${PSScriptRoot}/test/tools/NamedPipeConnection" $outPath = "${PSScriptRoot}/test/tools/NamedPipeConnection/out/Microsoft.PowerShell.NamedPipeConnection" $publishPath = "${PSScriptRoot}/test/tools/Modules" @@ -1161,6 +1262,8 @@ function Publish-CustomConnectionTestModule finally { Pop-Location } + + Write-LogGroupEnd -Title "Publish-CustomConnectionTestModule" } function Publish-PSTestTools { @@ -1170,16 +1273,21 @@ function Publish-PSTestTools { $runtime ) + Write-LogGroupStart -Title "Publish-PSTestTools" Find-Dotnet $tools = @( @{ Path="${PSScriptRoot}/test/tools/TestAlc"; Output="library" } @{ Path="${PSScriptRoot}/test/tools/TestExe"; Output="exe" } - @{ Path="${PSScriptRoot}/test/tools/TestService"; Output="exe" } @{ Path="${PSScriptRoot}/test/tools/UnixSocket"; Output="exe" } @{ Path="${PSScriptRoot}/test/tools/WebListener"; Output="exe" } ) + # This is a windows service, so it only works on windows + if ($environment.IsWindows) { + $tools += @{ Path = "${PSScriptRoot}/test/tools/TestService"; Output = "exe" } + } + $Options = Get-PSOptions -DefaultToNew # Publish tools so it can be run by tests @@ -1237,6 +1345,7 @@ function Publish-PSTestTools { # Publish the Microsoft.PowerShell.NamedPipeConnection module Publish-CustomConnectionTestModule + Write-LogGroupEnd -Title "Publish-PSTestTools" } function Get-ExperimentalFeatureTests { @@ -1281,9 +1390,14 @@ function Start-PSPester { [Parameter(ParameterSetName='Wait', Mandatory=$true, HelpMessage='Wait for the debugger to attach to PowerShell before Pester starts. Debug builds only!')] [switch]$Wait, - [switch]$SkipTestToolBuild + [switch]$SkipTestToolBuild, + [switch]$UseNuGetOrg ) + if ($UseNuGetOrg) { + Switch-PSNugetConfig -Source Public + } + if (-not (Get-Module -ListAvailable -Name $Pester -ErrorAction SilentlyContinue | Where-Object { $_.Version -ge "4.2" } )) { Restore-PSPester @@ -1657,6 +1771,16 @@ function Publish-TestResults $resolvedPath = (Resolve-Path -Path $Path).ProviderPath Write-Host "##vso[artifact.upload containerfolder=testResults;artifactname=testResults]$resolvedPath" + } elseif ($env:GITHUB_WORKFLOW -and $env:RUNNER_WORKSPACE) { + # In GitHub Actions + $destinationPath = Join-Path -Path $env:RUNNER_WORKSPACE -ChildPath 'testResults' + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $Path -Destination $destinationPath -Force -Verbose } } @@ -1709,12 +1833,16 @@ function Show-PSPesterError throw 'Unknown Show-PSPester parameter set' } - Write-Log -isError -message ("Description: " + $description) - Write-Log -isError -message ("Name: " + $name) - Write-Log -isError -message "message:" - Write-Log -isError -message $message - Write-Log -isError -message "stack-trace:" - Write-Log -isError -message $stack_trace + # Empty line at the end is intentional formatting + Write-Log -isError -message @" +Description: $description +Name: $name +message: +$message +stack-trace: +$stack_trace + +"@ } @@ -1754,13 +1882,17 @@ function Test-XUnitTestResults $message = $failure.failure.message $stack_trace = $failure.failure.'stack-trace' - Write-Log -isError -message ("Description: " + $description) - Write-Log -isError -message ("Name: " + $name) - Write-Log -isError -message "message:" - Write-Log -isError -message $message - Write-Log -isError -message "stack-trace:" - Write-Log -isError -message $stack_trace - Write-Log -isError -message " " + # Empty line at the end is intentional formatting + Write-Log -isError -message @" + Description: $description + Name: $name + message: + $message + stack-trace: + $stack_trace + +"@ + } throw "$($results.assemblies.assembly.failed) tests failed" @@ -1796,7 +1928,8 @@ function Test-PSPesterResults $x = [xml](Get-Content -Raw $testResultsFile) if ([int]$x.'test-results'.failures -gt 0) { - Write-Log -isError -message "TEST FAILURES" + Write-LogGroupStart -Title 'TEST FAILURES' + # switch between methods, SelectNode is not available on dotnet core if ( "System.Xml.XmlDocumentXPathExtensions" -as [Type] ) { @@ -1810,6 +1943,8 @@ function Test-PSPesterResults { Show-PSPesterError -testFailure $testfail } + + Write-LogGroupEnd -Title 'TEST FAILURES' throw "$($x.'test-results'.failures) tests in $TestArea failed" } } @@ -1830,11 +1965,12 @@ function Test-PSPesterResults } elseif ($ResultObject.FailedCount -gt 0) { - Write-Log -isError -message 'TEST FAILURES' + Write-LogGroupStart -Title 'TEST FAILURES' $ResultObject.TestResult | Where-Object {$_.Passed -eq $false} | ForEach-Object { Show-PSPesterError -testFailureObject $_ } + Write-LogGroupEnd -Title 'TEST FAILURES' throw "$($ResultObject.FailedCount) tests in $TestArea failed" } @@ -1843,7 +1979,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 @@ -1901,9 +2039,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 + ) + } - Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + if($DebugLogging) { + $extraParams += @( + "--logger:console;verbosity=detailed" + ) + } else { + $extraParams += @( + "--logger:xunit;LogFilePath=$xUnitTestResultsFile" + ) + } + dotnet test @extraParams --configuration $Options.configuration --test-adapter-path:. + + if(!$DebugLogging){ + Publish-TestResults -Path $xUnitTestResultsFile -Type 'XUnit' -Title 'Xunit Sequential' + } } finally { $env:DOTNET_ROOT = $originalDOTNET_ROOT @@ -1924,14 +2081,15 @@ 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 # 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 @@ -2022,7 +2180,6 @@ function Install-Dotnet { $installArgs += @{ SkipNonVersionedFiles = $true } $installArgs | Out-String | Write-Verbose -Verbose - & ./$installScript @installArgs } else { @@ -2059,6 +2216,7 @@ function Install-Dotnet { } } } + Write-LogGroupEnd -Title "Install .NET SDK $Version" } function Get-RedHatPackageManager { @@ -2066,48 +2224,13 @@ 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." } } -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) { - $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( @@ -2115,10 +2238,17 @@ function Start-PSBootstrap { # we currently pin dotnet-cli version, and will # update it when more stable version comes out. [string]$Version = $dotnetCLIRequiredVersion, - [switch]$Package, [switch]$NoSudo, [switch]$BuildLinuxArm, - [switch]$Force + [switch]$Force, + [Parameter(Mandatory = $true)] + # 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) + # All: Install all dependencies (packaging, .NET SDK, and tools) + [ValidateSet("Package", "DotNet", "Both", "Tools", "All")] + [string]$Scenario = "Package" ) Write-Log -message "Installing PowerShell build dependencies" @@ -2131,12 +2261,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) { - 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" + Write-LogGroupEnd -Title "Install Native Dependencies" return } @@ -2151,7 +2283,9 @@ function Start-PSBootstrap { elseif ($environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($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 @@ -2167,7 +2301,7 @@ function Start-PSBootstrap { # change the apt frontend back to the original $env:DEBIAN_FRONTEND=$originalDebianFrontEnd } - } elseif ($environment.IsLinux -and $environment.IsRedHatFamily) { + } elseif ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsMariner)) { # Build tools $Deps += "which", "curl", "wget" @@ -2175,7 +2309,9 @@ function Start-PSBootstrap { $Deps += "libicu", "openssl-libs" # Packaging tools - if ($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 @@ -2196,7 +2332,8 @@ function Start-PSBootstrap { $Deps += "wget" # Packaging tools - if ($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" @@ -2235,54 +2372,86 @@ function Start-PSBootstrap { } } - # Install [fpm](https://github.com/jordansissel/fpm) and [ronn](https://github.com/rtomayko/ronn) - if ($Package) { - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.12.0" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.11.0" - Install-GlobalGem -Sudo $sudo -GemName "ronn" -GemVersion "0.7.3" + if ($Scenario -in 'All', 'Both', 'Package') { + # 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 + } + } + + # 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 "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 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 + } + } + } } + Write-LogGroupEnd -Title "Install Native Dependencies" } - Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" + if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + Write-LogGroupStart -Title "Install .NET SDK" - # Try to locate dotnet-SDK before installing it - Find-Dotnet + Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" - Write-Verbose -Verbose "Back from calling Find-Dotnet from Start-PSBootstrap" + # Try to locate dotnet-SDK before installing it + Find-Dotnet - # Install dotnet-SDK - $dotNetExists = precheck 'dotnet' $null - $dotNetVersion = [string]::Empty - if($dotNetExists) { - $dotNetVersion = Find-RequiredSDK $dotnetCLIRequiredVersion - } + Write-Verbose -Verbose "Back from calling Find-Dotnet from Start-PSBootstrap" - if(!$dotNetExists -or $dotNetVersion -ne $dotnetCLIRequiredVersion -or $Force.IsPresent) { - if($Force.IsPresent) { - Write-Log -message "Installing dotnet due to -Force." - } - elseif(!$dotNetExists) { - Write-Log -message "dotnet not present. Installing dotnet." - } - else { - Write-Log -message "dotnet out of date ($dotNetVersion). Updating dotnet." + # Install dotnet-SDK + $dotNetExists = precheck 'dotnet' $null + $dotNetVersion = [string]::Empty + if($dotNetExists) { + $dotNetVersion = Find-RequiredSDK $dotnetCLIRequiredVersion } - $DotnetArguments = @{ Channel=$Channel; Version=$Version; NoSudo=$NoSudo } + if(!$dotNetExists -or $dotNetVersion -ne $dotnetCLIRequiredVersion -or $Force.IsPresent) { + if($Force.IsPresent) { + Write-Log -message "Installing dotnet due to -Force." + } + elseif(!$dotNetExists) { + Write-Log -message "dotnet not present. Installing dotnet." + } + else { + Write-Log -message "dotnet out of date ($dotNetVersion). Updating dotnet." + } - if ($dotnetAzureFeed) { - $null = $DotnetArguments.Add("AzureFeed", $dotnetAzureFeed) - $null = $DotnetArguments.Add("FeedCredential", $dotnetAzureFeedSecret) - } + $DotnetArguments = @{ Channel=$Channel; Version=$Version; NoSudo=$NoSudo } - Install-Dotnet @DotnetArguments - } - else { - Write-Log -message "dotnet is already installed. Skipping installation." + if ($dotnetAzureFeed) { + $null = $DotnetArguments.Add("AzureFeed", $dotnetAzureFeed) + $null = $DotnetArguments.Add("FeedCredential", $dotnetAzureFeedSecret) + } + + Install-Dotnet @DotnetArguments + } + 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)) { @@ -2290,6 +2459,20 @@ 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" + } + + 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 @@ -2564,7 +2747,13 @@ function script:Write-Log ) if ($isError) { - Write-Host -Foreground Red $message + if ($env:GITHUB_WORKFLOW) { + # https://github.com/actions/toolkit/issues/193#issuecomment-605394935 + $escapedMessage = $message -replace "`n", "%0A" -replace "`r" + Write-Host "::error::${escapedMessage}" + } else { + Write-Host -Foreground Red $message + } } else { @@ -2573,6 +2762,59 @@ function script:Write-Log #reset colors for older package to at return to default after error message on a compilation error [console]::ResetColor() } + +function script:Write-LogGroup { + param + ( + [Parameter(Position = 0, Mandatory)] + [ValidateNotNullOrEmpty()] + [string[]] $Message, + [Parameter(Mandatory)] + [string] $Title + ) + + + Write-LogGroupStart -Title $Title + + foreach ($line in $Message) { + Write-Log -Message $line + } + + Write-LogGroupEnd -Title $Title +} + +$script:logGroupColor = [System.ConsoleColor]::Cyan + +function script:Write-LogGroupStart { + param + ( + [Parameter(Mandatory)] + [string] $Title + ) + + if ($env:GITHUB_WORKFLOW) { + Write-Host "::group::${Title}" + } + else { + Write-Host -ForegroundColor $script:logGroupColor "=== BEGIN: $Title ===" + } +} + +function script:Write-LogGroupEnd { + param + ( + [Parameter(Mandatory)] + [string] $Title + ) + + if ($env:GITHUB_WORKFLOW) { + Write-Host "::endgroup::" + } + else { + Write-Host -ForegroundColor $script:logGroupColor "==== END: $Title ====" + } +} + function script:precheck([string]$command, [string]$missedMessage) { $c = Get-Command $command -ErrorAction Ignore if (-not $c) { @@ -3384,58 +3626,167 @@ function New-TestPackage [System.IO.Compression.ZipFile]::CreateFromDirectory($packageRoot, $packagePath) } -function New-NugetConfigFile -{ +class NugetPackageSource { + [string] $Url + [string] $Name +} + +function New-NugetPackageSource { param( - [Parameter(Mandatory=$true)] [string] $NugetFeedUrl, - [Parameter(Mandatory=$true)] [string] $FeedName, - [Parameter(Mandatory=$true)] [string] $UserName, - [Parameter(Mandatory=$true)] [string] $ClearTextPAT, - [Parameter(Mandatory=$true)] [string] $Destination + [Parameter(Mandatory = $true)] [string]$Url, + [Parameter(Mandatory = $true)] [string] $Name ) - $nugetConfigTemplate = @' + return [NugetPackageSource] @{Url = $Url; Name = $Name } +} + +$script:NuGetEndpointCredentials = [System.Collections.Generic.Dictionary[String,System.Object]]::new() + +function New-NugetConfigFile { + param( + [Parameter(Mandatory = $true, ParameterSetName ='user')] + [Parameter(Mandatory = $true, ParameterSetName ='nouser')] + [NugetPackageSource[]] $NugetPackageSource, + + [Parameter(Mandatory = $true)] [string] $Destination, + + [Parameter(Mandatory = $true, ParameterSetName = 'user')] + [string] $UserName, + + [Parameter(Mandatory = $true, ParameterSetName = 'user')] + [string] $ClearTextPAT + ) + + $nugetConfigHeaderTemplate = @' +'@ + + $nugetPackageSourceTemplate = @' +'@ + $nugetPackageSourceFooterTemplate = @' +'@ + $nugetCredentialsTemplate = @' <[FEEDNAME]> +'@ + $nugetConfigFooterTemplate = @' '@ + $content = $nugetConfigHeaderTemplate + + $feedNamePostfix = '' + if ($UserName) { + $feedNamePostfix += '-' + $UserName.Replace('@', '-').Replace('.', '-') + } + + [NugetPackageSource]$source = $null + $newLine = [Environment]::NewLine + foreach ($source in $NugetPackageSource) { + $content += $newLine + $nugetPackageSourceTemplate.Replace('[FEED]', $source.Url).Replace('[FEEDNAME]', $source.Name + $feedNamePostfix) + } + + $content += $newLine + $nugetPackageSourceFooterTemplate + + if ($UserName -or $ClearTextPAT) { + foreach ($source in $NugetPackageSource) { + if (!$script:NuGetEndpointCredentials.ContainsKey($source.Url)) { + $script:NuGetEndpointCredentials.Add($source.Url, @{ + endpoint = $source.Url + username = $UserName + password = $ClearTextPAT + }) + } + } + } - $content = $nugetConfigTemplate.Replace('[FEED]', $NugetFeedUrl).Replace('[FEEDNAME]', $FeedName).Replace('[USERNAME]', $UserName).Replace('[PASSWORD]', $ClearTextPAT) + $content += $newLine + $nugetConfigFooterTemplate Set-Content -Path (Join-Path $Destination 'nuget.config') -Value $content -Force + + # Set the nuget.config file to be skipped by git + push-location $Destination + try { + git update-index --skip-worktree (Join-Path $Destination 'nuget.config') + } finally { + pop-location + } +} + +function Clear-PipelineNugetAuthentication { + $script:NuGetEndpointCredentials.Clear() +} + +function Set-PipelineNugetAuthentication { + $endpointcredentials = @() + + foreach ($key in $script:NuGetEndpointCredentials.Keys) { + $endpointcredentials += $script:NuGetEndpointCredentials[$key] + } + + $json = @{ + endpointCredentials = $endpointcredentials + } | convertto-json -Compress + Set-PipelineVariable -Name 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' -Value $json } function Set-CorrectLocale { + Write-LogGroupStart -Title "Set-CorrectLocale" + if (-not $IsLinux) { + Write-LogGroupEnd -Title "Set-CorrectLocale" return } $environment = Get-EnvironmentInformation - if ($environment.IsUbuntu -and $environment.IsUbuntu20) - { + if ($environment.IsUbuntu16 -or $environment.IsUbuntu18) { + Write-Verbose -Message "Don't set locale before Ubuntu 20" -Verbose + Write-LogGroupEnd -Title "Set-CorrectLocale" + Write-Locale + return + } + + if ($environment.IsUbuntu) { + Write-Log -Message "Setting locale to en_US.UTF-8" $env:LC_ALL = 'en_US.UTF-8' $env:LANG = 'en_US.UTF-8' sudo locale-gen $env:LANG - sudo update-locale + if ($environment.IsUbuntu20) { + Write-Log -Message "Updating locale for Ubuntu 20" + sudo update-locale + } else { + Write-Log -Message "Updating locale for Ubuntu 22 and newer" + sudo update-locale LANG=$env:LANG LC_ALL=$env:LC_ALL + } + } + + Write-LogGroupEnd -Title "Set-CorrectLocale" + Write-Locale + +} + +function Write-Locale { + if (-not $IsLinux -and -not $IsMacOS) { + Write-Verbose -Message "only supported on Linux and macOS" -Verbose + return } # Output the locale to log it - locale + $localOutput = & locale + Write-LogGroup -Title "Capture Locale" -Message $localOutput } function Install-AzCopy { @@ -3531,3 +3882,39 @@ function Clear-NativeDependencies $deps | ConvertTo-Json -Depth 20 | Set-Content "$PublishFolder/pwsh.deps.json" -Force } + + +function Update-DotNetSdkVersion { + $globalJsonPath = "$PSScriptRoot/global.json" + $globalJson = get-content $globalJsonPath | convertfrom-json + $oldVersion = $globalJson.sdk.version + $versionParts = $oldVersion -split '\.' + $channel = $versionParts[0], $versionParts[1] -join '.' + Write-Verbose "channel: $channel" -Verbose + $azure_feed = 'https://dotnetcli.azureedge.net/dotnet' + $version_file_url = "$azure_feed/Sdk/$channel/latest.version" + $version = Invoke-RestMethod $version_file_url + Write-Verbose "updating from: $oldVersion to: $version" -Verbose + $globalJson.sdk.version = $version + $globalJson | convertto-json | out-file $globalJsonPath + $dotnetRuntimeMetaPath = "$psscriptroot\DotnetRuntimeMetadata.json" + $dotnetRuntimeMeta = get-content $dotnetRuntimeMetaPath | convertfrom-json + $dotnetRuntimeMeta.sdk.sdkImageVersion = $version + $dotnetRuntimeMeta | ConvertTo-Json | Out-File $dotnetRuntimeMetaPath +} + +function Set-PipelineVariable { + param( + [parameter(Mandatory)] + [string] $Name, + [parameter(Mandatory)] + [string] $Value + ) + + $vstsCommandString = "vso[task.setvariable variable=$Name]$Value" + Write-Verbose -Verbose -Message ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + # also set in the current session + Set-Item -Path "env:$Name" -Value $Value +} diff --git a/demos/Apache/Apache/Apache.psm1 b/demos/Apache/Apache/Apache.psm1 deleted file mode 100644 index 5f980f26bae..00000000000 --- a/demos/Apache/Apache/Apache.psm1 +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#Region utility functions - -$global:sudocmd = "sudo" - -Function GetApacheCmd{ - if (Test-Path "/usr/sbin/apache2ctl"){ - $cmd = "/usr/sbin/apache2ctl" - }elseif(Test-Path "/usr/sbin/httpd"){ - $cmd = "/usr/sbin/httpd" - }else{ - Write-Error "Unable to find httpd or apache2ctl program. Unable to continue" - exit -1 - } - $cmd -} - -Function GetApacheVHostDir{ - if (Test-Path "/etc/httpd/conf.d"){ - Return "/etc/httpd/conf.d/" - } - if (Test-Path "/etc/apache2/sites-enabled"){ - Return "/etc/apache2/sites-enabled" - } -} - -Function CleanInputString([string]$inputStr){ - $outputStr = $inputStr.Trim().Replace('`n','').Replace('\n','') - $outputStr -} - -#EndRegion utility functions - -#Region Class specifications - -Class ApacheModule{ - [string]$ModuleName - - ApacheModule([string]$aModule){ - $this.ModuleName = $aModule - } -} - -Class ApacheVirtualHost{ - [string]$ServerName - [string]$DocumentRoot - [string]$VirtualHostIPAddress = "*" - [string[]]$ServerAliases - [int]$VirtualHostPort = "80" - [string]$ServerAdmin - [string]$CustomLogPath - [string]$ErrorLogPath - [string]$ConfigurationFile - - #region class constructors - ApacheVirtualHost([string]$ServerName, [string]$ConfFile, [string]$VirtualHostIPAddress,[int]$VirtualHostPort){ - $this.ServerName = $ServerName - $this.ConfigurationFile = $ConfFile - $this.VirtualHostIPAddress = $VirtualHostIPAddress - $this.VirtualHostPort = $VirtualHostPort - } - - #Full specification - ApacheVirtualHost([string]$ServerName, [string]$DocumentRoot, [string[]]$ServerAliases, [string]$ServerAdmin, [string]$CustomLogPath, [string]$ErrorLogPath, [string]$VirtualHostIPAddress, [int]$VirtualHostPort, [string]$ConfigurationFile){ - $this.ServerName = $ServerName - $this.DocumentRoot = $DocumentRoot - $this.ServerAliases = $ServerAliases - $this.ServerAdmin = $ServerAdmin - $this.CustomLogPath = $CustomLogPath - $this.ErrorLogPath = $ErrorLogPath - $this.VirtualHostIPAddress = $VirtualHostIPAddress - $this.VirtualHostPort = $VirtualHostPort - $this.ConfigurationFile = $ConfigurationFile - } - - #Default Port and IP - #endregion - - #region class methods - Save($ConfigurationFile){ - if (!(Test-Path $this.DocumentRoot)){ New-Item -Type Directory $this.DocumentRoot } - - $VHostsDirectory = GetApacheVHostDir - if (!(Test-Path $VHostsDirectory)){ - Write-Error "Specified virtual hosts directory does not exist: $VHostsDirectory" - exit 1 - } - $VHostIPAddress = $this.VirtualHostIPAddress - [string]$VhostPort = $this.VirtualHostPort - $VHostDef = "`n" - $vHostDef += "DocumentRoot " + $this.DocumentRoot + "`n" - ForEach ($Alias in $this.ServerAliases){ - if ($Alias.trim() -ne ""){ - $vHostDef += "ServerAlias " + $Alias + "`n" - } - } - $vHostDef += "ServerName " + $this.ServerName +"`n" - if ($this.ServerAdmin.Length -gt 1){$vHostDef += "ServerAdmin " + $this.ServerAdmin +"`n"} - if ($this.CustomLogPath -like "*/*"){$vHostDef += "CustomLog " + $this.CustomLogPath +"`n"} - if ($this.ErrorLogPath -like "*/*"){$vHostDef += "ErrorLog " + $this.ErrorLogpath +"`n"} - $vHostDef += "" - $filName = $ConfigurationFile - $VhostDef | Out-File "/tmp/${filName}" -Force -Encoding:ascii - & $global:sudocmd "mv" "/tmp/${filName}" "${VhostsDirectory}/${filName}" - Write-Information "Restarting Apache HTTP Server" - Restart-ApacheHTTPServer - } - - #endregion -} - -#EndRegion Class Specifications - -Function New-ApacheVHost { - [CmdletBinding()] - param( - [parameter (Mandatory = $true)][string]$ServerName, - [parameter (Mandatory = $true)][string]$DocumentRoot, - [string]$VirtualHostIPAddress, - [string[]]$ServerAliases, - [int]$VirtualHostPort, - [string]$ServerAdmin, - [string]$CustomLogPath, - [string]$ErrorLogPath - ) - - $NewConfFile = $VHostsDirectory + "/" + $ServerName + ".conf" - if(!($VirtualHostIPAddress)){$VirtualHostIPAddress = "*"} - if(!($VirtualHostPort)){$VirtualHostPort = "80"} - $newVHost = [ApacheVirtualHost]::new("$ServerName","$DocumentRoot","$ServerAliases","$ServerAdmin","$CustomLogPath","$ErrorLogPath","$VirtualHostIPAddress",$VirtualHostPort,"$NewConfFile") - $newVHost.Save("$ServerName.conf") -} - -Function GetVHostProps([string]$ConfFile,[string]$ServerName,[string]$Listener){ - $confContents = Get-Content $ConfFile - [boolean]$Match = $false - $DocumentRoot = "" - $CustomLogPath = "" - $ErrorLogPath = "" - $ServerAdmin = "" - ForEach ($confline in $confContents){ - if ($confLine -like "*"){ - $Match = $false - } - } - } - @{"DocumentRoot" = "$DocumentRoot"; "CustomLogPath" = "$CustomLogPath"; "ErrorLogPath" = "$ErrorLogPath"; "ServerAdmin" = $ServerAdmin} - -} - -Function Get-ApacheVHost{ - $cmd = GetApacheCmd - - $Vhosts = @() - $res = & $global:sudocmd $cmd -t -D DUMP_VHOSTS - - ForEach ($line in $res){ - $ServerName = $null - if ($line -like "*:*.conf*"){ - $RMatch = $line -match "(?.*:[0-9]*)(?.*)\((?.*)\)" - $ListenAddress = $Matches.Listen.trim() - $ServerName = $Matches.ServerName.trim() - $ConfFile = $Matches.ConfFile.trim().split(":")[0].Replace('(','') - }else{ - if ($line.trim().split()[0] -like "*:*"){ - $ListenAddress = $line.trim().split()[0] - }elseif($line -like "*.conf*"){ - if ($line -like "*default*"){ - $ServerName = "_Default" - $ConfFile = $line.trim().split()[3].split(":")[0].Replace('(','') - }elseif($line -like "*namevhost*"){ - $ServerName = $line.trim().split()[3] - $ConfFile = $line.trim().split()[4].split(":")[0].Replace('(','') - } - } - } - - if ($null -ne $ServerName){ - $vHost = [ApacheVirtualHost]::New($ServerName, $ConfFile, $ListenAddress.Split(":")[0],$ListenAddress.Split(":")[1]) - $ExtProps = GetVHostProps $ConfFile $ServerName $ListenAddress - $vHost.DocumentRoot = $ExtProps.DocumentRoot - #Custom log requires additional handling. NYI - #$vHost.CustomLogPath = $ExtProps.CustomLogPath - $vHost.ErrorLogPath = $ExtProps.ErrorLogPath - $vHost.ServerAdmin = $ExtProps.ServerAdmin - $Vhosts += $vHost - } - } - - Return $Vhosts - } - -Function Restart-ApacheHTTPServer{ - [CmdletBinding()] - Param( - [switch]$Graceful - ) - - if ($null -eq $Graceful){$Graceful = $false} - $cmd = GetApacheCmd - if ($Graceful){ - & $global:sudocmd $cmd -k graceful - }else{ - & $global:sudocmd $cmd -k restart - } - -} - -Function Get-ApacheModule{ - $cmd = GetApacheCmd - - $ApacheModules = @() - - $Results = & $global:sudocmd $cmd -M |grep -v Loaded - - Foreach ($mod in $Results){ - $modInst = [ApacheModule]::new($mod.trim()) - $ApacheModules += ($modInst) - } - - $ApacheModules - -} diff --git a/demos/Apache/apache-demo.ps1 b/demos/Apache/apache-demo.ps1 deleted file mode 100644 index 299ce0cc0de..00000000000 --- a/demos/Apache/apache-demo.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/Apache/Apache.psm1 - -#list Apache Modules -Write-Host -Foreground Blue "Get installed Apache Modules like *proxy* and Sort by name" -Get-ApacheModule | Where-Object {$_.ModuleName -like "*proxy*"} | Sort-Object ModuleName | Out-Host - -#Graceful restart of Apache -Write-Host -Foreground Blue "Restart Apache Server gracefully" -Restart-ApacheHTTPServer -Graceful | Out-Host - -#Enumerate current virtual hosts (web sites) -Write-Host -Foreground Blue "Enumerate configured Apache Virtual Hosts" -Get-ApacheVHost |Out-Host - -#Add a new virtual host -Write-Host -Foreground Yellow "Create a new Apache Virtual Host" -New-ApacheVHost -ServerName "mytestserver" -DocumentRoot /var/www/html/mytestserver -VirtualHostIPAddress * -VirtualHostPort 8090 | Out-Host - -#Enumerate new set of virtual hosts -Write-Host -Foreground Blue "Enumerate Apache Virtual Hosts Again" -Get-ApacheVHost |Out-Host - -#Cleanup -Write-Host -Foreground Blue "Remove demo virtual host" -if (Test-Path "/etc/httpd/conf.d"){ - & sudo rm "/etc/httpd/conf.d/mytestserver.conf" -} -if (Test-Path "/etc/apache2/sites-enabled"){ - & sudo rm "/etc/apache2/sites-enabled/mytestserver.conf" -} diff --git a/demos/Apache/readme.md b/demos/Apache/readme.md deleted file mode 100644 index 30e36b3811a..00000000000 --- a/demos/Apache/readme.md +++ /dev/null @@ -1,18 +0,0 @@ -## Apache Management Demo - -This demo shows management of Apache HTTP Server with PowerShell cmdlets implemented in a script module. - -- **Get-ApacheVHost**: Enumerate configured Apache Virtual Host (website) instances as objects. -- **Get-ApacheModule**: Enumerate loaded Apache modules -- **Restart-ApacheHTTPserver**: Restart the Apache web server -- **New-ApacheVHost**: Create a new Apache Virtual Host (website) based on supplied parameters - - -## Prerequisites ## -- Install PowerShell -- Install Apache packages - - `sudo apt-get install apache2` - - `sudo yum install httpd` - - -Note: Management of Apache requires privileges. The user must have authorization to elevate with sudo. You will be prompted for a sudo password when running the demo. \ No newline at end of file diff --git a/demos/Azure/Azure-Demo.ps1 b/demos/Azure/Azure-Demo.ps1 deleted file mode 100644 index 22b316686a7..00000000000 --- a/demos/Azure/Azure-Demo.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -### The techniques used in this demo are documented at -### https://azure.microsoft.com/documentation/articles/powershell-azure-resource-manager/ - -### Import AzureRM.Profile.NetCore.Preview and AzureRM.Resources.NetCore.Preview modules. -### AzureRM.NetCore.Preview is a wrapper module that pulls in these modules -### -### Because of issue https://github.com/PowerShell/PowerShell/issues/1618, -### currently you will not be able to use "Install-Module AzureRM.NetCore.Preview" from -### PowerShellGallery. You can use the following workaround until the issue is fixed: -### -### Install-Package -Name AzureRM.NetCore.Preview -Source https://www.powershellgallery.com/api/v2 -ProviderName NuGet -ExcludeVersion -Destination -### -### Ensure $env:PSModulePath is updated with the location you used to install. -Import-Module AzureRM.NetCore.Preview - -### Supply your Azure Credentials -Login-AzureRmAccount - -### Specify a name for Azure Resource Group -$resourceGroupName = "PSAzDemo" + (New-Guid | ForEach-Object guid) -replace "-","" -$resourceGroupName - -### Create a new Azure Resource Group -New-AzureRmResourceGroup -Name $resourceGroupName -Location "West US" - -### Deploy an Ubuntu 14.04 VM using Resource Manager cmdlets -### Template is available at -### http://armviz.io/#/?load=https:%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-vm-simple-linux%2Fazuredeploy.json -$dnsLabelPrefix = $resourceGroupName | ForEach-Object tolower -$dnsLabelPrefix - -#[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Demo/doc secret.")] -$password = ConvertTo-SecureString -String "PowerShellRocks!" -AsPlainText -Force -New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile ./Compute-Linux.json -adminUserName psuser -adminPassword $password -dnsLabelPrefix $dnsLabelPrefix - -### Monitor the status of the deployment -Get-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName - -### Discover the resources we created by the previous deployment -Find-AzureRmResource -ResourceGroupName $resourceGroupName | Select-Object Name,ResourceType,Location - -### Get the state of the VM we created -### Notice: The VM is in running state -Get-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName -ODataQuery '$expand=instanceView' | ForEach-Object properties | ForEach-Object instanceview | ForEach-Object statuses - -### Discover the operations we can perform on the compute resource -### Notice: Operations like "Power Off Virtual Machine", "Start Virtual Machine", "Create Snapshot", "Delete Snapshot", "Delete Virtual Machine" -Get-AzureRmProviderOperation -OperationSearchString Microsoft.Compute/* | Select-Object OperationName,Operation - -### Power Off the Virtual Machine we created -Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Compute/virtualMachines -ResourceName MyUbuntuVM -Action poweroff - -### Check the VM state again. It should be stopped now. -Get-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName -ODataQuery '$expand=instanceView' | ForEach-Object properties | ForEach-Object instanceview | ForEach-Object statuses - -### As you know, you may still be incurring charges even if the VM is in stopped state -### Deallocate the resource to avoid this charge -Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Compute/virtualMachines -ResourceName MyUbuntuVM -Action deallocate - -### The following command removes the Virtual Machine -Remove-AzureRmResource -ResourceName MyUbuntuVM -ResourceType Microsoft.Compute/virtualMachines -ResourceGroupName $resourceGroupName - -### Look at the resources that still exists -Find-AzureRmResource -ResourceGroupName $resourceGroupName | Select-Object Name,ResourceType,Location - -### Remove the resource group and its resources -Remove-AzureRmResourceGroup -Name $resourceGroupName diff --git a/demos/Azure/Compute-Linux.json b/demos/Azure/Compute-Linux.json deleted file mode 100644 index a0e9e27b85e..00000000000 --- a/demos/Azure/Compute-Linux.json +++ /dev/null @@ -1,200 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminUsername": { - "type": "string", - "metadata": { - "description": "User name for the Virtual Machine." - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Password for the Virtual Machine." - } - }, - "dnsLabelPrefix": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - "ubuntuOSVersion": { - "type": "string", - "defaultValue": "14.04.2-LTS", - "allowedValues": [ - "12.04.5-LTS", - "14.04.2-LTS", - "15.10", - "16.04.0-LTS" - ], - "metadata": { - "description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version. Allowed values: 12.04.5-LTS, 14.04.2-LTS, 15.10, 16.04.0-LTS." - } - } - }, - "variables": { - "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'salinuxvm')]", - "dataDisk1VhdName": "datadisk1", - "imagePublisher": "Canonical", - "imageOffer": "UbuntuServer", - "OSDiskName": "osdiskforlinuxsimple", - "nicName": "myVMNic", - "addressPrefix": "10.0.0.0/16", - "subnetName": "Subnet", - "subnetPrefix": "10.0.0.0/24", - "storageAccountType": "Standard_LRS", - "publicIPAddressName": "myPublicIP", - "publicIPAddressType": "Dynamic", - "vmStorageAccountContainerName": "vhds", - "vmName": "MyUbuntuVM", - "vmSize": "Standard_D1", - "virtualNetworkName": "MyVNET", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", - "apiVersion": "2015-06-15" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('storageAccountName')]", - "apiVersion": "2016-01-01", - "location": "[resourceGroup().location]", - "sku": { - "name": "[variables('storageAccountType')]" - }, - "kind": "Storage", - "properties": {} - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[variables('publicIPAddressName')]", - "location": "[resourceGroup().location]", - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]", - "dnsSettings": { - "domainNameLabel": "[parameters('dnsLabelPrefix')]" - } - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[resourceGroup().location]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetPrefix')]" - } - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/networkInterfaces", - "name": "[variables('nicName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - } - }, - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Compute/virtualMachines", - "name": "[variables('vmName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[variables('vmSize')]" - }, - "osProfile": { - "computerName": "[variables('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[parameters('ubuntuOSVersion')]", - "version": "latest" - }, - "osDisk": { - "name": "osdisk", - "vhd": { - "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob, variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - }, - "dataDisks": [ - { - "name": "datadisk1", - "diskSizeGB": "100", - "lun": 0, - "vhd": { - "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob, variables('vmStorageAccountContainerName'),'/',variables('dataDisk1VhdName'),'.vhd')]" - }, - "createOption": "Empty" - } - ] - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "true", - "storageUri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), variables('apiVersion')).primaryEndpoints.blob)]" - } - } - } - } - ], - "outputs": { - "hostname": { - "type": "string", - "value": "[concat(parameters('dnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]" - }, - "sshCommand": { - "type": "string", - "value": "[concat('ssh ', parameters('adminUsername'), '@', parameters('dnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]" - } - } -} diff --git a/demos/Azure/README.md b/demos/Azure/README.md deleted file mode 100644 index d2c8155f6f4..00000000000 --- a/demos/Azure/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## Demo: Managing Azure using PowerShell - -This demo (Azure-Demo.ps1) shows management of Azure Compute resource using Azure Resource Management (ARM) cmdlets. - -## Prerequisites ## -- Install the latest PowerShell Core. -- Install AzureRM.NetCore.Preview, AzureRM.Profile.NetCore.Preview and AzureRM.Resources.NetCore.Preview modules to a local directory. - - The instructions for downloading these modules are in Azure-Demo.ps1 file. - - You have to use the command "Install-Package -Name AzureRM.NetCore.Preview -Source https://www.powershellgallery.com/api/v2 -ProviderName NuGet -ExcludeVersion -Destination " - - diff --git a/demos/DSC/dsc-demo.ps1 b/demos/DSC/dsc-demo.ps1 deleted file mode 100644 index 3abd642a3b4..00000000000 --- a/demos/DSC/dsc-demo.ps1 +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#Get Distro type and set distro-specific variables -$OSname = Get-Content "/etc/os-release" |Select-String -Pattern "^Name=" -$OSName = $OSName.tostring().split("=")[1].Replace('"','') -if ($OSName -like "Ubuntu*"){ - $distro = "Ubuntu" - $ApachePackages = @("apache2","php5","libapache2-mod-php5") - $ServiceName = "apache2" - $VHostDir = "/etc/apache2/sites-enabled" - $PackageManager = "apt" -}elseif (($OSName -like "CentOS*") -or ($OSName -like "Red Hat*") -or ($OSname -like "Oracle*")){ - $distro = "Fedora" - $ApachePackages = @("httpd","mod_ssl","php","php-mysql") - $ServiceName = "httpd" - $VHostDir = "/etc/httpd/conf.d" - $PackageManager = "yum" -}else{ - Write-Error "Unknown Linux operating system. Cannot continue." -} - -#Get Service Controller -if ((Test-Path "/bin/systemctl") -or (Test-Path "/usr/bin/systemctl")){ - $ServiceCtl = "SystemD" -}else{ - $ServiceCtl = "init" -} - -#Get FQDN -$hostname = & hostname --fqdn - -Write-Host -ForegroundColor Blue "Compile a DSC MOF for the Apache Server configuration" -Configuration ApacheServer{ - Node localhost{ - - ForEach ($Package in $ApachePackages){ - nxPackage $Package{ - Ensure = "Present" - Name = $Package - PackageManager = $PackageManager - } - } - - nxFile vHostDirectory{ - DestinationPath = $VhostDir - Type = "Directory" - Ensure = "Present" - Owner = "root" - Mode = "744" - } - - #Ensure default content does not exist - nxFile DefVHost{ - DestinationPath = "${VhostDir}/000-default.conf" - Ensure = "Absent" - } - - nxFile Welcome.conf{ - DestinationPath = "${VhostDir}/welcome.conf" - Ensure = "Absent" - } - - nxFile UserDir.conf{ - DestinationPath = "${VhostDir}/userdir.conf" - Ensure = "Absent" - } - - #Ensure website is defined - nxFile DefaultSiteDir{ - DestinationPath = "/var/www/html/defaultsite" - Type = "Directory" - Owner = "root" - Mode = "744" - Ensure = "Present" - } - - nxFile DefaultSite.conf{ - Destinationpath = "${VhostDir}/defaultsite.conf" - Owner = "root" - Mode = "744" - Ensure = "Present" - Contents = @" - -DocumentRoot /var/www/html/defaultsite -ServerName $hostname - - -"@ - DependsOn = "[nxFile]DefaultSiteDir" - } - - nxFile TestPhp{ - DestinationPath = "/var/www/html/defaultsite/test.php" - Ensure = "Present" - Owner = "root" - Mode = "744" - Contents = @' - - -'@ - } - - #Configure Apache Service - nxService ApacheService{ - Name = "$ServiceName" - Enabled = $true - State = "running" - Controller = $ServiceCtl - DependsOn = "[nxFile]DefaultSite.conf" - } - - } -} - -ApacheServer -OutputPath "/tmp" - -Pause -Write-Host -ForegroundColor Blue "Apply the configuration locally" -& sudo /opt/microsoft/dsc/Scripts/StartDscConfiguration.py -configurationmof /tmp/localhost.mof | Out-Host - -Pause -Write-Host -ForegroundColor Blue "Get the current configuration" -& sudo /opt/microsoft/dsc/Scripts/GetDscConfiguration.py | Out-Host diff --git a/demos/DSC/readme.md b/demos/DSC/readme.md deleted file mode 100644 index 3a13cc6f2fe..00000000000 --- a/demos/DSC/readme.md +++ /dev/null @@ -1,15 +0,0 @@ -# DSC MOF Compilation Demo - -[PowerShell Desired State Configuration](https://learn.microsoft.com/powershell/dsc/overview) is a declarative configuration platform for Windows and Linux. -DSC configurations can be authored in PowerShell and compiled into the resultant MOF document. - -This demo shows use of PowerShell to author a DSC configuration to set the configuration of an Apache web server. PowerShell scripting is used to assess distribution and version-specific properties, -such as the service controller and repo manager tools, for use in the configuration. - -## Prerequisites - -- PowerShell >= 6.0.0-alpha.8 [https://github.com/PowerShell/PowerShell/releases](https://github.com/PowerShell/PowerShell/releases) -- OMI: >= 1.1.0 [https://www.github.com/microsoft/omi/releases](https://www.github.com/microsoft/omi/releases) -- Desired State Configuration for Linux >= 1.1.1-278 [https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases](https://github.com/Microsoft/PowerShell-DSC-for-Linux/releases) - -> Note: applying the DSC configuration requires privileges. The user must have sudo authorization capabilities. You will be prompted for a sudo password when running the demo. diff --git a/demos/Docker-PowerShell/Docker-PowerShell.ps1 b/demos/Docker-PowerShell/Docker-PowerShell.ps1 deleted file mode 100644 index 18eb844fd32..00000000000 --- a/demos/Docker-PowerShell/Docker-PowerShell.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# This is a short example of the Docker-PowerShell module. The same cmdlets may be used to manage both local & remote machines, including both Windows & Linux hosts -# The only difference between them is the example container image is pulled & run. - -# Import the Docker module -# It's available at https://github.com/Microsoft/Docker-PowerShell -Import-Module Docker - -# Pull the 'hello-world' image from Docker Hub -Pull-ContainerImage hello-world # Linux -# Pull-ContainerImage patricklang/hello-world # Windows - -# Now run it -Run-ContainerImage hello-world # Linux -# Run-ContainerImage patricklang/hello-world # Windows - -# Make some room on the screen -cls - -# List all containers that have exited -Get-Container | Where-Object State -EQ "exited" - -# That found the right one, so go ahead and remove it -Get-Container | Where-Object State -EQ "exited" | Remove-Container - -# Now remove the container image -Remove-ContainerImage hello-world - -# And list the container images left on the container host -Get-ContainerImage diff --git a/demos/README.md b/demos/README.md deleted file mode 100644 index 53882c047c6..00000000000 --- a/demos/README.md +++ /dev/null @@ -1,4 +0,0 @@ -This folder contains demos primarily targeted for Linux systems. -Each demo showcases how to use PowerShell to be more productive by -leveraging objects and how it can integrate with existing Linux -scripts and/or commands. diff --git a/demos/SystemD/SystemD/SystemD.psm1 b/demos/SystemD/SystemD/SystemD.psm1 deleted file mode 100644 index d1bf0d8e890..00000000000 --- a/demos/SystemD/SystemD/SystemD.psm1 +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Function Get-SystemDJournal { - [CmdletBinding()] - param ( - [Alias("args")][string]$journalctlParameters - ) - $sudocmd = "sudo" - $cmd = "journalctl" - $Result = & $sudocmd $cmd $journalctlParameters -o json --no-pager - Try - { - $JSONResult = $Result|ConvertFrom-Json - $JSONResult - } - Catch - { - $Result - } -} diff --git a/demos/SystemD/journalctl-demo.ps1 b/demos/SystemD/journalctl-demo.ps1 deleted file mode 100644 index 2597bdc3b66..00000000000 --- a/demos/SystemD/journalctl-demo.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/SystemD/SystemD.psm1 - -#list recent journal events -Write-Host -Foreground Blue "Get recent SystemD journal messages" -Get-SystemDJournal -args "-xe" |Out-Host - -#Drill into SystemD unit messages -Write-Host -Foreground Blue "Get recent SystemD journal messages for services and return Unit, Message" -Get-SystemDJournal -args "-xe" | Where-Object {$_._SYSTEMD_UNIT -like "*.service"} | Format-Table _SYSTEMD_UNIT, MESSAGE | Select-Object -First 10 | Out-Host diff --git a/demos/SystemD/readme.md b/demos/SystemD/readme.md deleted file mode 100644 index 87580efbae3..00000000000 --- a/demos/SystemD/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -## SystemD: journalctl demo - -This demo shows use of a PowerShell script module to wrap a native tool (journalctl) so that the output is structured for filtering and presentation control. `journalctl` is expressed as a cmdlet: Get-SystemDJournal, and the JSON output of journalctl is converted to a PowerShell object. - -## Prerequisites ## -- Requires a SystemD-based operating system (Red Hat or CentOS 7, Ubuntu 16.04) -- Install PowerShell - - -Note: Accessing the SystemD journal requires privileges. The user must have authorization to elevate with sudo. You will be prompted for a sudo password when running the demo. \ No newline at end of file diff --git a/demos/WindowsPowerShellModules/README.md b/demos/WindowsPowerShellModules/README.md deleted file mode 100644 index 3cf63bd947e..00000000000 --- a/demos/WindowsPowerShellModules/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Using Windows PowerShell modules with PowerShell Core - -## Windows PowerShell vs PowerShell Core - -Existing Windows PowerShell users are familiar with the large number of modules available, however, they are not necessarily compatible with PowerShell Core. -More information regarding compatibility is in a [blog post](https://devblogs.microsoft.com/powershell/powershell-6-0-roadmap-coreclr-backwards-compatibility-and-more/). - -Windows PowerShell 5.1 is based on .Net Framework 4.6.1, while PowerShell Core is based on .Net Core 2.x. -Although both adhere to .Net Standard 2.0 and can be compatible, some modules may be using APIs or cmdlets not supported on CoreCLR or using APIs from Windows PowerShell that have been deprecated and removed from PowerShell Core (for example, PSSnapins). - -## Importing a Windows PowerShell module - -Since compatibility cannot be ensured, PowerShell Core, by default, does not look in the Windows PowerShell module path to find those modules. -However, advanced users can explicitly enable PowerShell Core to include the Windows PowerShell module path and attempt to import those modules. - -First, install the [WindowsPSModulePath](https://www.powershellgallery.com/packages/WindowsPSModulePath) module from the PowerShellGallery: - -```powershell -Install-Module WindowsPSModulePath -Scope CurrentUser -``` - -Then run `Add-WindowsPSModulePath` cmdlet to add the Windows PowerShell module path to your PowerShell Core module path: - -```powershell -Add-WindowsPSModulePath -``` - -Note that this is only effective in the current PowerShell session. -If you want to persist this, you can add `Add-WindowsPSModulePath` to your profile: - -```powershell -"Add-WindowsPSModulePath" >> $profile -``` - -Once the module path has been updated, you can list available modules: - -```powershell -Get-Module -ListAvailable -``` - -Note that PowerShell Core is not aware which Windows PowerShell modules will work and which will not so all are listed. -We plan to improve this experience in the future. -You can now import a Windows PowerShell module or just execute a known cmdlet and allow auto-module loading to take care of importing the module: - -```powershell -Get-VM -# this will automatically load the Hyper-V module -``` - -Most of the cmdlets based on CDXML will work just fine, as well as some C# based cmdlets that happen to be .NET Standard 2.0 compatible (for example, Hyper-V module) but the Active Directory module, for example, won't work. - -## How you can help - -Provide comments on Windows PowerShell modules that work or don't work in our [tracking issue](https://github.com/PowerShell/PowerShell/issues/4062). diff --git a/demos/crontab/CronTab/CronTab.ps1xml b/demos/crontab/CronTab/CronTab.ps1xml deleted file mode 100644 index 4246b1f62af..00000000000 --- a/demos/crontab/CronTab/CronTab.ps1xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - Default - - CronJob - - - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - 10 - Left - - - - Left - - - - - - - Minute - - - Hour - - - DayOfMonth - - - Month - - - DayOfWeek - - - Command - - - - - - - - \ No newline at end of file diff --git a/demos/crontab/CronTab/CronTab.psd1 b/demos/crontab/CronTab/CronTab.psd1 deleted file mode 100755 index aabc48e572e..00000000000 --- a/demos/crontab/CronTab/CronTab.psd1 +++ /dev/null @@ -1,61 +0,0 @@ -@{ - -# Script module or binary module file associated with this manifest. -RootModule = 'CronTab.psm1' - -# Version number of this module. -ModuleVersion = '0.1.0.0' - -# Supported PSEditions -CompatiblePSEditions = @('Core') - -# ID used to uniquely identify this module -GUID = '508bb97f-de2e-482e-aae2-01caec0be8c7' - -# Author of this module -Author = 'PowerShell' - -# Company or vendor of this module -CompanyName = 'Microsoft Corporation' - -# Copyright statement for this module -Copyright = 'Copyright (c) Microsoft Corporation.' - -# Description of the functionality provided by this module -Description = 'Sample module for managing CronTab' - -# Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = 'CronTab.ps1xml' - -# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'New-CronJob','Remove-CronJob','Get-CronJob','Get-CronTabUser' - -# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. -PrivateData = @{ - - PSData = @{ - - # Tags applied to this module. These help with module discovery in online galleries. - # Tags = @() - - # A URL to the license for this module. - # LicenseUri = '' - - # A URL to the main website for this project. - # ProjectUri = '' - - # A URL to an icon representing this module. - # IconUri = '' - - # ReleaseNotes of this module - # ReleaseNotes = '' - - } # End of PSData hashtable - -} # End of PrivateData hashtable - -# HelpInfo URI of this module -# HelpInfoURI = '' - -} - diff --git a/demos/crontab/CronTab/CronTab.psm1 b/demos/crontab/CronTab/CronTab.psm1 deleted file mode 100644 index 4cb88e586b9..00000000000 --- a/demos/crontab/CronTab/CronTab.psm1 +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -using namespace System.Collections.Generic -using namespace System.Management.Automation - -$crontabcmd = "/usr/bin/crontab" - -class CronJob { - [string] $Minute - [string] $Hour - [string] $DayOfMonth - [string] $Month - [string] $DayOfWeek - [string] $Command - - [string] ToString() - { - return "{0} {1} {2} {3} {4} {5}" -f - $this.Minute, $this.Hour, $this.DayOfMonth, $this.Month, $this.DayOfWeek, $this.Command - } -} - -# Internal helper functions - -function Get-CronTab ([String] $user) { - $crontab = Invoke-CronTab -user $user -arguments "-l" -noThrow - if ($crontab -is [ErrorRecord]) { - if ($crontab.Exception.Message.StartsWith("no crontab for ")) { - $crontab = @() - } - else { - throw $crontab.Exception - } - } - [string[]] $crontab -} - -function ConvertTo-CronJob ([String] $crontab) { - $split = $crontab -split " ", 6 - $cronjob = [CronJob]@{ - Minute = $split[0]; - Hour = $split[1]; - DayOfMonth= $split[2]; - Month =$split[3]; - DayOfWeek = $split[4]; - Command = $split[5] - } - $cronjob -} - -function Invoke-CronTab ([String] $user, [String[]] $arguments, [Switch] $noThrow) { - If ($user -ne [String]::Empty) { - $arguments = Write-Output "-u" $UserName $arguments - } - - Write-Verbose "Running: $crontabcmd $arguments" - $output = & $crontabcmd @arguments 2>&1 - if ($LASTEXITCODE -ne 0 -and -not $noThrow) { - $e = New-Object System.InvalidOperationException -ArgumentList $output.Exception.Message - throw $e - } else { - $output - } -} - -function Import-CronTab ([String] $user, [String[]] $crontab) { - $temp = New-TemporaryFile - [String]::Join([Environment]::NewLine,$crontab) | Set-Content $temp.FullName - Invoke-CronTab -user $user $temp.FullName - Remove-Item $temp -} - -# Public functions - -function Remove-CronJob { -<# -.SYNOPSIS - Removes the exactly matching cron job from the cron table - -.DESCRIPTION - Removes the exactly matching cron job from the cron table - -.EXAMPLE - Get-CronJob | Where-Object {%_.Command -like 'foo *'} | Remove-CronJob - -.RETURNVALUE - None - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table - -.PARAMETER Job - Cron job object returned from Get-CronJob - -.PARAMETER Force - Don't prompt when removing the cron job -#> - [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="High")] - param ( - [ArgumentCompleter( { $wordToComplete = $args[2]; Get-CronTabUser | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object } )] - [Alias("u")] - [Parameter(Mandatory=$false)] - [String] - $UserName, - - [Alias("j")] - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] - [CronJob] - $Job, - - [Switch] - $Force - ) - process { - - [string[]] $crontab = Get-CronTab -user $UserName - $newcrontab = [List[string]]::new() - $found = $false - - $JobAsString = $Job.ToString() - foreach ($line in $crontab) { - if ($JobAsString -ceq $line) { - $found = $true - } else { - $newcrontab.Add($line) - } - } - - if (-not $found) { - $e = New-Object System.Exception -ArgumentList "Job not found" - throw $e - } - if ($Force -or $PSCmdlet.ShouldProcess($Job.Command,"Remove")) { - Import-CronTab -user $UserName -crontab $newcrontab - } - } -} - -function New-CronJob { -<# -.SYNOPSIS - Create a new cron job -.DESCRIPTION - Create a new job in the cron table. Date and time parameters can be specified - as ranges such as 10-30, as a list: 5,6,7, or combined 1-5,10-15. An asterisk - means 'first through last' (the entire allowed range). Step values can be used - with ranges or with an asterisk. Every 2 hours can be specified as either - 0-23/2 or */2. -.EXAMPLE - New-CronJob -Minute 10-30 -Hour 10-20/2 -DayOfMonth */2 -Command "/bin/bash -c 'echo hello' > ~/hello" - -.RETURNVALUE - If successful, an object representing the cron job is returned - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table - -.PARAMETER Minute - Valid values are 0 to 59. If not specified, defaults to *. - -.PARAMETER Hour - Valid values are 0-23. If not specified, defaults to *. - -.PARAMETER DayOfMonth - Valid values are 1-31. If not specified, defaults to *. - -.PARAMETER Month - Valid values are 1-12. If not specified, defaults to *. - -.PARAMETER DayOfWeek - Valid values are 0-7. 0 and 7 are both Sunday. If not specified, defaults to *. - -.PARAMETER Command - Command to execute at the scheduled time and day. -#> - [CmdletBinding()] - param ( - [ArgumentCompleter( { $wordToComplete = $args[2]; Get-CronTabUser | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object } )] - [Alias("u")] - [Parameter(Mandatory=$false)] - [String] - $UserName, - - [Alias("mi")][Parameter(Position=1)][String[]] $Minute = "*", - [Alias("h")][Parameter(Position=2)][String[]] $Hour = "*", - [Alias("dm")][Parameter(Position=3)][String[]] $DayOfMonth = "*", - [Alias("mo")][Parameter(Position=4)][String[]] $Month = "*", - [Alias("dw")][Parameter(Position=5)][String[]] $DayOfWeek = "*", - [Alias("c")][Parameter(Mandatory=$true,Position=6)][String] $Command - ) - process { - # TODO: validate parameters, note that different versions of crontab support different capabilities - $line = "{0} {1} {2} {3} {4} {5}" -f [String]::Join(",",$Minute), [String]::Join(",",$Hour), - [String]::Join(",",$DayOfMonth), [String]::Join(",",$Month), [String]::Join(",",$DayOfWeek), $Command - [string[]] $crontab = Get-CronTab -user $UserName - $crontab += $line - Import-CronTab -User $UserName -crontab $crontab - ConvertTo-CronJob -crontab $line - } -} - -function Get-CronJob { -<# -.SYNOPSIS - Returns the current cron jobs from the cron table - -.DESCRIPTION - Returns the current cron jobs from the cron table - -.EXAMPLE - Get-CronJob -UserName Steve - -.RETURNVALUE - CronJob objects - -.PARAMETER UserName - Optional parameter to specify a specific user's cron table -#> - [CmdletBinding()] - [OutputType([CronJob])] - param ( - [Alias("u")][Parameter(Mandatory=$false)][String] $UserName - ) - process { - $crontab = Get-CronTab -user $UserName - ForEach ($line in $crontab) { - if ($line.Trim().Length -gt 0) - { - ConvertTo-CronJob -crontab $line - } - } - } -} - -function Get-CronTabUser { -<# -.SYNOPSIS - Returns the users allowed to use crontab -#> - [CmdletBinding()] - [OutputType([String])] - param() - - $allow = '/etc/cron.allow' - if (Test-Path $allow) - { - Get-Content $allow - } - else - { - $users = Get-Content /etc/passwd | ForEach-Object { ($_ -split ':')[0] } - $deny = '/etc/cron.deny' - if (Test-Path $deny) - { - $denyUsers = Get-Content $deny - $users | Where-Object { $denyUsers -notcontains $_ } - } - else - { - $users - } - } -} diff --git a/demos/crontab/README.md b/demos/crontab/README.md deleted file mode 100644 index bdfb16dbb06..00000000000 --- a/demos/crontab/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## CronTab demo - -This demo shows examining, creating, and removing cron jobs via crontab. - -Output of Get-CronJob is a strongly typed object with properties like DayOfWeek or Command. -Remove-CronJob prompts before removing the job unless you specify -Force. - -Tab completion of -UserName is supported, e.g. - -Get-CronJob -u - -NYI: no way to run crontab with sudo if necessary -NYI: ignoring shell variables or comments -NYI: New-CronJob -Description "..." (save in comments" -NYI: @reboot,@daily,@hourly,etc diff --git a/demos/crontab/crontab.ps1 b/demos/crontab/crontab.ps1 deleted file mode 100644 index 3d0ee0741ea..00000000000 --- a/demos/crontab/crontab.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Import-Module $PSScriptRoot/CronTab/CronTab.psd1 - -Write-Host -Foreground Yellow "Get the existing cron jobs" -Get-CronJob | Out-Host - -Write-Host -Foreground Yellow "New cron job to clean out tmp every day at 1am" -New-CronJob -Command 'rm -rf /tmp/*; #demo' -Hour 1 | Out-Host - -Write-Host -Foreground Yellow "Add some more jobs" -New-CronJob -Command 'python -c ~/scripts/backup_users; #demo' -Hour 2 -DayOfWeek 1-5 | Out-Host -New-CronJob -Command 'powershell -c "cd ~/src/PowerShell; ipmo ./build.psm1; Start-PSBuild"; #demo' -Hour 2 -DayOfWeek * | Out-Host - -Write-Host -Foreground Yellow "Show in bash that the new cron job exists" -crontab -l - -Write-Host -Foreground Yellow "Get jobs that run every day" -Get-CronJob | Where-Object { $_.DayOfWeek -eq '*' -or $_.DayOfWeek -eq '1-7' } | Out-Host - -Write-Host -Foreground Yellow "Remove one cron job, with prompting to confirm" -Get-CronJob | Where-Object { $_.Command -match '^powershell.*' } | Remove-CronJob | Out-Host - -Write-Host -Foreground Yellow "And the other job remains" -Get-CronJob | Out-Host - -Write-Host -Foreground Yellow "Remove remaining demo jobs without prompting" -Get-CronJob | Where-Object { $_.Command -match '#demo'} | Remove-CronJob -Force - -Write-Host -Foreground Yellow "Show in bash that cron should be clean" -crontab -l diff --git a/demos/dsc.ps1 b/demos/dsc.ps1 deleted file mode 100644 index c59be643edc..00000000000 --- a/demos/dsc.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# DSC MOF Compilation -# DSC Configuration() script that: -# Defines base configuration users, groups, settings -# Uses PS function to set package configuration (ensure=Present) for an array of packages -# Probes for the existence of a package (Apache or MySQL) and conditionally configures the workload. I.e., if Apache is installed, configure Apache settings - -# Demo execution: -# Show the .ps1 -# Run the .ps1 to generate a MOF -# Apply the MOF locally with Start-DSCConfiguration -# Show the newly configured state diff --git a/demos/powershellget/PowerShellGet.ps1 b/demos/powershellget/PowerShellGet.ps1 deleted file mode 100644 index e93216851da..00000000000 --- a/demos/powershellget/PowerShellGet.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#region find, install, update, uninstall the PowerShell scripts from an online repository. -# Value: equivalent of pypi - -# List of PowerShellGet commands -Get-Command -Module PowerShellGet - -# Discover PowerShell Scripts -Find-Script -Find-Script -Name Start-Demo - -# Save scripts to a specified location -Save-Script Start-Demo -Repository PSGallery -Path /tmp -Get-ChildItem -Path /tmp/Start-Demo.ps1 - -# Install a script to the common scripts location -Find-Script -Name Start-Demo -Repository PSGallery | Install-Script -Get-InstalledScript - -# Install another script to show the update functionality -Install-Script Fabrikam-Script -RequiredVersion 1.0 -Get-InstalledScript -Get-InstalledScript Fabrikam-Script | Format-List * - -# Update the installed scripts -Update-Script -WhatIf -Update-Script -Get-InstalledScript - -# Uninstall a script file -Uninstall-Script Fabrikam-Script -Verbose - -#endregion - -#region Using PowerShellGet find and install modules - -# Value: equivalent of pypi -# Look for all the modules we'll be demoing today -Find-Module -Tag 'PowerShellCore_Demo' - -# Save module to specified location -Save-Module -Tag 'PowerShellCore_Demo' -Path /tmp - -# Pipe this to Install-Module to install them -Find-Module -Tag 'PowerShellCore_Demo' | Install-Module -Verbose -Get-InstalledModule - -# Update all installed modules -Update-Module - -#endregion - -#region Using PowerShellGet with tags - -# Look for all the scripts we'll be demoing today -Find-Script -Tag 'PowerShellCore_Demo' - -# Pipe this to Install-Script to install them -Find-Script -Tag 'PowerShellCore_Demo' | Install-Script -Verbose -Get-InstalledScript - -#endregion - -#region Working with PowerShellGet repositories - -# List available PS repositories -Get-PSRepository - -# Register a new private feed -Register-PSRepository -Name "myPrivateGallery" –SourceLocation "https://www.myget.org/F/powershellgetdemo/api/v2" -InstallationPolicy Trusted - -# Change the trust level for a repositories -Set-PSRepository -Name "myPrivateGallery" -InstallationPolicy "Untrusted" - -# Remove a private feed -Unregister-PSRepository -Name "myPrivateGallery" - -#endregion diff --git a/demos/powershellget/README.md b/demos/powershellget/README.md deleted file mode 100644 index f225610169b..00000000000 --- a/demos/powershellget/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## PowerShellGet demo - -PowerShellGet is a PowerShell module with the commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts. - -This demo shows discovering, installing, updating, uninstalling the PowerShell scripts from an online repository. diff --git a/demos/python/README.md b/demos/python/README.md deleted file mode 100644 index d2d1486e2fe..00000000000 --- a/demos/python/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# PowerShell/Python Interoperation Demo - -The `demo_script.ps1` file in this directory walks through a -demonstration of basic interoperation between PowerShell and Python -including how to use JSON to exchange structured objects between -Python and PowerShell. - -The other files in this directory are referenced by `demo_script.ps1`. diff --git a/demos/python/class1.ps1 b/demos/python/class1.ps1 deleted file mode 100644 index b74c0c8d5d6..00000000000 --- a/demos/python/class1.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# Wrap Python script in such a way to make it easy to -# consume from PowerShell -# -# The variable $PSScriptRoot points to the directory -# from which the script was executed. This allows -# picking up the Python script from the same directory -# - -& $PSScriptRoot/class1.py | ConvertFrom-Json - diff --git a/demos/python/class1.py b/demos/python/class1.py deleted file mode 100755 index ad923449455..00000000000 --- a/demos/python/class1.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python3 - -import json - -# Define a class with a method that returns JSON -class returnsjson: - def __init__(self): - the_object = self - def method1(self): - return json.dumps(['foo', - { - 'bar': ('baz', None, 1.0, 2), - 'buz': ('foo1', 'foo2', 'foo3') - }, - 'alpha', - 1,2,3]) - -c = returnsjson() -print(c.method1()) diff --git a/demos/python/demo_script.ps1 b/demos/python/demo_script.ps1 deleted file mode 100644 index af2067642a1..00000000000 --- a/demos/python/demo_script.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# Demo simple interoperation between PowerShell and Python - -# Basic execution of a Python script fragment -python -c "print('Hi!')" - -# Capture output in a variable -$data = python -c "print('Hi!')" - -# And show the data -$data - -# Use in expressions -5 + (python -c "print(2 + 3)") + 7 - -# Create a Python script using a PowerShell here-string, no extension -@" -#!/usr/bin/python3 -print('Hi!') -"@ | Out-File -Encoding ascii hi - -# Make it executable -chmod +x hi - -# Run it - shows that PowerShell really is a shell -./hi - -# A more complex script that outputs JSON -cat class1.py - -# Run the script -./class1.py - -# Capture the data as structured objects (arrays and hashtables) -$data = ./class1.py | ConvertFrom-Json - -# look at the first element of the returned array -$data[0] - -# Look at the second -$data[1] - -# Get a specific element from the data -$data[1].buz[1] - -# Finally wrap it all up so it looks like a simple PowerShell command -cat class1.ps1 - -# And run it, treating the output as structured data. -(./class1)[1].buz[1] - -# Finally a PowerShell script with in-line Python -cat inline_python.ps1 - -# and run it -./inline_python - -#################################### -# cleanup -rm hi diff --git a/demos/python/inline_python.ps1 b/demos/python/inline_python.ps1 deleted file mode 100644 index 71b65215f74..00000000000 --- a/demos/python/inline_python.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# -# An example showing inline Python code in a PowerShell script -# - -"Hello from PowerShell!" - -# Inline Python code in a "here string" which allows for a multi-line script -python3 -c @" -print(' Hello from Python!') -print(' Python and PowerShell get along great!') -"@ - -# Back to PowerShell... -"Back to PowerShell." -"Bye now!" - diff --git a/demos/rest/README.md b/demos/rest/README.md deleted file mode 100644 index 03bb103889e..00000000000 --- a/demos/rest/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## REST demo - -This demo shows how to interact with the GitHub API using the Invoke-WebRequest cmdlet. - -rest.ps1: -Invoke-WebRequest and ConvertFrom-Json cmdlets are used to get the issues of a repo. -The issues are processed as objects to find the most commented on issues. diff --git a/demos/rest/rest.ps1 b/demos/rest/rest.ps1 deleted file mode 100644 index f40b49b6538..00000000000 --- a/demos/rest/rest.ps1 +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -#----------------- - -function Get-Issue -{ - param([string]$UserName, - [string]$Repo, - [ValidateRange(1,100)][int]$PerPage = 100) - - $body = @{ - per_page = $PerPage - } - - $uri = "https://api.github.com/repos/$UserName/$Repo/issues" - while ($uri) - { - $response = Invoke-WebRequest -Uri $uri -Body $body - $response.Content | ConvertFrom-Json | Write-Output - - $uri = $null - foreach ($link in $response.Headers.Link -split ',') - { - if ($link -match '\s*<(.*)>;\s+rel="next"') - { - $uri = $Matches[1] - } - } - } -} - -$issues = Get-Issue -UserName lzybkr -Repo PSReadline - -$issues.Count - -$issues | Sort-Object -Descending comments | Select-Object -First 15 | ft number,comments,title - -foreach ($issue in $issues) -{ - if ($issue.labels.name -contains 'bug' -and $issue.labels.name -contains 'vi mode') - { - "{0} is a vi mode bug" -f $issue.url - } -} diff --git a/docs/building/linux.md b/docs/building/linux.md index 87fce81843d..d1ec01bd206 100644 --- a/docs/building/linux.md +++ b/docs/building/linux.md @@ -12,7 +12,7 @@ The build module works on a best-effort basis for other distributions. Using Git requires it to be set up correctly; refer to the [Working with the PowerShell Repository](../git/README.md), -[README](../../README.md), and [Contributing Guidelines](../../.github/CONTRIBUTING.md). +[Readme](../../README.md), and [Contributing Guidelines](../../.github/CONTRIBUTING.md). **This guide assumes that you have recursively cloned the PowerShell repository and `cd`ed into it.** @@ -63,7 +63,7 @@ If you have followed the toolchain setup section above, you should have PowerShe ```powershell Import-Module ./build.psm1 -Start-PSBuild +Start-PSBuild -UseNuGetOrg ``` Congratulations! If everything went right, PowerShell is now built. @@ -72,4 +72,4 @@ The `Start-PSBuild` script will output the location of the executable: `./src/powershell-unix/bin/Debug/net6.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`, and our xUnit tests with `Start-PSxUnit`. +You can run our cross-platform Pester tests with `Start-PSPester -UseNuGetOrg`, and our xUnit tests with `Start-PSxUnit`. diff --git a/docs/building/macos.md b/docs/building/macos.md index 63f1b4c9f82..4f15e3fb547 100644 --- a/docs/building/macos.md +++ b/docs/building/macos.md @@ -34,6 +34,6 @@ We cannot do this for you in the build module due to #[847][]. ## Build using our module -Start a PowerShell session by running `pwsh`, and then use `Start-PSBuild` from the module. +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`. diff --git a/docs/building/windows-core.md b/docs/building/windows-core.md index af3ac86f1de..8e87e7b4ba4 100644 --- a/docs/building/windows-core.md +++ b/docs/building/windows-core.md @@ -11,7 +11,7 @@ R2, though they should work anywhere the dependencies work. ### Git Setup Using Git requires it to be setup correctly; refer to the -[README](../../README.md) and +[Readme](../../README.md) and [Contributing Guidelines](../../.github/CONTRIBUTING.md). This guide assumes that you have recursively cloned the PowerShell repository and `cd`ed into it. @@ -56,7 +56,7 @@ We maintain a [PowerShell module](../../build.psm1) with the function `Start-PSB ```powershell Import-Module ./build.psm1 -Start-PSBuild +Start-PSBuild -Clean -PSModuleRestore -UseNuGetOrg ``` 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`. @@ -77,7 +77,7 @@ You can run our cross-platform Pester tests with `Start-PSPester`. ```powershell Import-Module ./build.psm1 -Start-PSPester +Start-PSPester -UseNuGetOrg ``` ## Building in Visual Studio diff --git a/docs/cmdlet-example/visual-studio-simple-example.md b/docs/cmdlet-example/visual-studio-simple-example.md index b4a20ba138c..37244f25705 100644 --- a/docs/cmdlet-example/visual-studio-simple-example.md +++ b/docs/cmdlet-example/visual-studio-simple-example.md @@ -131,5 +131,5 @@ It should find `PowerShellStandard.Library` package, select it and it will show ![StdImage61](./Images/Std61.png) On PowerShell Core on Linux: ![StdImage62](./Images/Std62.png) -On Windows PowerShell on Windows (this requires [.NET Framework 4.7.1](https://github.com/Microsoft/dotnet-framework-early-access/blob/master/instructions.md)): +On Windows PowerShell on Windows (this requires [.NET Framework 4.7.1](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net471) ![StdImage63](./Images/Std63.png) diff --git a/docs/git/README.md b/docs/git/README.md index 817e4930f6c..46b5eee4c62 100644 --- a/docs/git/README.md +++ b/docs/git/README.md @@ -13,9 +13,9 @@ git clone https://github.com/PowerShell/PowerShell.git --branch=master * Checkout a new local branch from `master` for every change you want to make (bugfix, feature). * Use lowercase-with-dashes for naming. * Follow [Linus' recommendations][Linus] about history. - - "People can (and probably should) rebase their _private_ trees (their own work). That's a _cleanup_. But never other peoples code. That's a 'destroy history'... - You must never EVER destroy other peoples history. You must not rebase commits other people did. - Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours." + * "People can (and probably should) rebase their _private_ trees (their own work). That's a _cleanup_. But never other peoples code. That's a 'destroy history'... + You must never EVER destroy other peoples history. You must not rebase commits other people did. + Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours." ### Understand branches @@ -23,12 +23,12 @@ git clone https://github.com/PowerShell/PowerShell.git --branch=master It could be unstable. * Send your pull requests to **master**. -### Sync your local repo +### Sync your local repository Use **git rebase** instead of **git merge** and **git pull**, when you're updating your feature-branch. ```sh -# fetch updates all remote branch references in the repo +# fetch updates all remote branch references in the repository # --all : tells it to do it for all remotes (handy, when you use your fork) # -p : tells it to remove obsolete remote branch references (when they are removed from remote) git fetch --all -p @@ -42,11 +42,9 @@ git rebase origin/master Covering all possible git scenarios is behind the scope of the current document. Git has excellent documentation and lots of materials available online. -We are leaving few links here: +We are leaving a few links here: -[Git pretty flowchart](http://justinhileman.info/article/git-pretty/): what to do, when your local repo became a mess. - -[Linus]:https://wincent.com/wiki/git_rebase%3A_you're_doing_it_wrong +[Linus]:https://web.archive.org/web/20230522041845/https://wincent.com/wiki/git_rebase%3A_you're_doing_it_wrong ## Tags @@ -57,12 +55,12 @@ you will find it via **tags**. * Find the tag that corresponds to the release. * Use `git checkout ` to get this version. -**Note:** [checking out a tag][tag] will move the repo to a [DETACHED HEAD][HEAD] state. +**Note:** [checking out a tag][tag] will move the repository to a [DETACHED HEAD][HEAD] state. [tag]:https://git-scm.com/book/en/v2/Git-Basics-Tagging#Checking-out-Tags [HEAD]:https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit -If you want to make changes, based on tag's version (i.e. a hotfix), +If you want to make changes, based on tag's version (i.e. a hotfix), checkout a new branch from this DETACHED HEAD state. ```sh diff --git a/docs/host-powershell/sample/NuGet.config b/docs/host-powershell/sample/NuGet.config.md similarity index 70% rename from docs/host-powershell/sample/NuGet.config rename to docs/host-powershell/sample/NuGet.config.md index b3ce3cb82a5..bf2b4c3f688 100644 --- a/docs/host-powershell/sample/NuGet.config +++ b/docs/host-powershell/sample/NuGet.config.md @@ -1,3 +1,8 @@ +# Nuget.config creation + +Create a filed called `nuget.config` at this location with this content: + +```xml @@ -8,3 +13,4 @@ +``` diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index a44ae5ee604..3562962e68f 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -21,20 +21,15 @@ This is to help track the release preparation work. - Sign the MSI packages and DEB/RPM packages. - Install and verify the packages. 1. Update documentation, scripts and Dockerfiles - - Summarize the change log for the release. It should be reviewed by PM(s) to make it more user-friendly. - - Update [CHANGELOG.md](../../CHANGELOG.md) with the finalized change log draft. + - Summarize the changelog for the release. It should be reviewed by PM(s) to make it more user-friendly. + - Update [CHANGELOG.md](../../CHANGELOG.md) with the finalized changelog draft. - Update other documents and scripts to use the new package names and links. 1. Verify the release Dockerfiles. 1. [Create NuGet packages](#nuget-packages) and publish them to [powershell-core feed][ps-core-feed]. 1. [Create the release tag](#release-tag) and push the tag to `PowerShell/PowerShell` repository. -1. Create the draft and publish the release in Github. +1. Create the draft and publish the release in GitHub. 1. Merge the `release-` branch to `master` in `powershell/powershell` and delete the `release-` branch. 1. Publish Linux packages to Microsoft YUM/APT repositories. -1. Trigger the release docker builds for Linux and Windows container images. - - Linux: push a branch named `docker` to `powershell/powershell` repository to trigger the build at [powershell docker hub](https://hub.docker.com/r/microsoft/powershell/builds/). - Delete the `docker` branch once the builds succeed. - - Windows: queue a new build in `PowerShell Windows Docker Build` on VSTS. -1. Verify the generated docker container images. 1. [Update the homebrew formula](#homebrew) for the macOS package. This task usually will be taken care of by the community, so we can wait for one day or two and see if the homebrew formula has already been updated, @@ -77,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 @@ -104,7 +106,7 @@ this package will contain actual PowerShell bits (i.e. it is not a meta-package). These bits are installed to `/opt/microsoft/powershell/6.0.0-alpha.8/`, where the version will change with each update -(and is the pre-release version). +(and is the prerelease version). On macOS, the prefix is `/usr/local`, instead of `/opt/microsoft` because it is derived from BSD. @@ -136,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 @@ -173,7 +175,7 @@ Start-PSPackage -Type zip -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' ## NuGet Packages -The NuGet packages for hosting PowerShell for Windows and non-Windows are being built in our release build pipeline. +The NuGet packages for hosting PowerShell for Windows and non-Windows are being built-in our release build pipeline. The assemblies from the individual Windows and Linux builds are consumed and packed into NuGet packages. These are then released to [powershell-core feed][ps-core-feed]. @@ -190,7 +192,7 @@ we create an [annotated tag][tag] that names the release. An annotated tag has a message (like a commit), and is *not* the same as a lightweight tag. Create one with `git tag -a v6.0.0-alpha.7 -m `, -and use the release change logs as the message. +and use the release changelogs as the message. Our convention is to prepend the `v` to the semantic version. The summary (first line) of the annotated tag message should be the full release title, e.g. 'v6.0.0-alpha.7 release of PowerShellCore'. diff --git a/global.json b/global.json index 3ecc5db745d..d23a6248a8d 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.100-rc.2.23502.2" + "version": "8.0.415" } } diff --git a/nuget.config b/nuget.config index 5137d0c33d6..388a65572dd 100644 --- a/nuget.config +++ b/nuget.config @@ -2,8 +2,7 @@ - - + diff --git a/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj b/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj new file mode 100644 index 00000000000..ecd26b49918 --- /dev/null +++ b/src/GlobalTools/PowerShell.Windows.x64/PowerShell.Windows.x64.csproj @@ -0,0 +1,33 @@ + + + + Exe + net8.0 + enable + enable + true + win-x64 + pwsh + $(PackageVersion) + true + ../../signing/visualstudiopublic.snk + + + + + + Modules\%(RecursiveDir)\%(FileName)%(Extension) + PreserveNewest + PreserveNewest + + + + + + + + + + + + diff --git a/src/GlobalTools/PowerShell.Windows.x64/Powershell_64.png b/src/GlobalTools/PowerShell.Windows.x64/Powershell_64.png new file mode 100644 index 00000000000..2a656ffc3c8 Binary files /dev/null and b/src/GlobalTools/PowerShell.Windows.x64/Powershell_64.png differ diff --git a/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs b/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs index 13dfe839b9d..32c68e961c6 100644 --- a/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs +++ b/src/Microsoft.Management.UI.Internal/commandHelpers/ShowCommandHelper.cs @@ -489,37 +489,6 @@ private static string GetSerializedCommandScript() @"Remove-Item -Path 'function:\PSGetSerializedShowCommandInfo' -Force"); } - /// - /// Gets the command to be run to in order to import a module and refresh the command data. - /// - /// Module we want to import. - /// Boolean flag determining whether Show-Command is queried in the local or remote runspace scenario. - /// Boolean flag to indicate that it is the second attempt to query Show-Command data. - /// The command to be run to in order to import a module and refresh the command data. - internal static string GetImportModuleCommand(string module, bool isRemoteRunspace = false, bool isFirstChance = true) - { - string scriptBase = "Import-Module " + ShowCommandHelper.SingleQuote(module); - - if (isRemoteRunspace) - { - if (isFirstChance) - { - scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + @" -ShowCommandInfo )"; - } - else - { - scriptBase += GetSerializedCommandScript(); - } - } - else - { - scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + ")"; - } - - scriptBase += ShowCommandHelper.GetGetModuleSuffix(); - return scriptBase; - } - /// /// Gets the command to be run in order to show help for a command. /// 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 1e7f70bc8f8..c7d5b40609a 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 0d6c585478d..17667cdbaff 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,8 @@ - + + diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs index 4e83eda905f..a9d8772a5fc 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs @@ -87,7 +87,7 @@ protected override void ProcessRecord() return; } - if (TotalCount == 0 || Tail == 0) + if (TotalCount == 0) { // Don't read anything return; @@ -118,7 +118,7 @@ protected override void ProcessRecord() // as reading forwards. So we read forwards in this case. // If Tail is positive, we seek the right position. Or, if the seek failed // because of an unsupported encoding, we scan forward to get the tail content. - if (Tail > 0) + if (Tail >= 0) { bool seekSuccess = false; diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index c5df76c0445..37c08bfd0e3 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -1926,6 +1926,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 @@ -2126,6 +2127,27 @@ protected override void BeginProcessing() jobAssigned = jobObject.AssignProcessToJobObject(processInfo.Process); } + // Since the process wasn't spawned by .NET, we need to trigger .NET to get a lock on the handle of the process. + // Otherwise, accessing properties like `ExitCode` will throw the following exception: + // "Process was not started by this object, so requested information cannot be determined." + // Fetching the process handle will trigger the `Process` object to update its internal state by calling `SetProcessHandle`, + // the result is discarded as it's not used later in this code. + try + { + _ = process.Handle; + } + catch (Win32Exception e) + { + // If the caller was not an admin and the process was started with another user's credentials .NET + // won't be able to retrieve the process handle. As this is not a critical failure we treat this as + // a warning. + if (PassThru) + { + string msg = StringUtil.Format(ProcessResources.FailedToCreateProcessObject, e.Message); + WriteDebug(msg); + } + } + // Resume the process now that is has been set up. processInfo.Resume(); #endif diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx index 65513e55f5f..1e1baf3cafe 100644 --- a/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx +++ b/src/Microsoft.PowerShell.Commands.Management/resources/ProcessResources.resx @@ -189,6 +189,9 @@ This command cannot be run completely because the system cannot find all the information required. + + Failed to retrieve the new process handle: "{0}". The Process object outputted may have some properties and methods that do not work properly. + This command cannot be run due to error 1783. The possible cause of this error can be using of a non-existing user "{0}". Please give a valid user and run your command again. 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 a23b657f61e..a620b8c1233 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -7,6 +7,8 @@ + + @@ -32,10 +34,10 @@ - - - - + + + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index 4ac0f4f3199..b21737f380a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -684,6 +684,7 @@ private void LoadAssemblies(IEnumerable assemblies) { // CoreCLR doesn't allow re-load TPA assemblies with different API (i.e. we load them by name and now want to load by path). // LoadAssemblyHelper helps us avoid re-loading them, if they already loaded. + // codeql[cs/dll-injection-remote] - This is expected PowerShell behavior and integral to the purpose of the class. It allows users to load any C# dependencies they need for their PowerShell application and add other types they require. Assembly assembly = LoadAssemblyHelper(assemblyName) ?? Assembly.LoadFrom(ResolveAssemblyName(assemblyName, false)); if (PassThru) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs index 51f8f0a6011..1f527258939 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs @@ -153,7 +153,7 @@ private static string BuildName(List propValues) foreach (object item in propertyValueItems) { - sb.Append(CultureInfo.InvariantCulture, $"{item}, "); + sb.Append(CultureInfo.CurrentCulture, $"{item}, "); } sb = sb.Length > length ? sb.Remove(sb.Length - 2, 2) : sb; @@ -161,7 +161,7 @@ private static string BuildName(List propValues) } else { - sb.Append(CultureInfo.InvariantCulture, $"{propValuePropertyValue}, "); + sb.Append(CultureInfo.CurrentCulture, $"{propValuePropertyValue}, "); } } } 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 95b25e4e4d5..fa99fe03374 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 @@ -634,7 +634,7 @@ protected override void ProcessRecord() response.ReasonPhrase); HttpResponseException httpEx = new(message, response); - ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); string detailMsg = string.Empty; try { @@ -675,7 +675,7 @@ protected override void ProcessRecord() // (and still writing out the result), users can debug actual HTTP redirect problems. if (_maximumRedirection == 0 && IsRedirectCode(response.StatusCode)) { - ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded); WriteError(er); } @@ -687,7 +687,7 @@ protected override void ProcessRecord() } catch (HttpRequestException ex) { - ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request); + ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, RedactAuthorizationHeader(request)); if (ex.InnerException is not null) { er.ErrorDetails = new ErrorDetails(ex.InnerException.Message); @@ -1172,7 +1172,7 @@ internal virtual void FillRequestStream(HttpRequestMessage request) { WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = ContentType; } - else if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put) + else if (request.Method == HttpMethod.Post) { // Win8:545310 Invoke-WebRequest does not properly set MIME type for POST WebSession.ContentHeaders.TryGetValue(HttpKnownHeaderNames.ContentType, out string contentType); @@ -1296,6 +1296,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM _cancelToken = new CancellationTokenSource(); try { + // 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(); } catch (TaskCanceledException ex) @@ -1525,6 +1526,27 @@ private string GetBearerAuthorizationHeader() return string.Create(CultureInfo.InvariantCulture, $"Bearer {new NetworkCredential(string.Empty, Token).Password}"); } + private static HttpRequestMessage RedactAuthorizationHeader(HttpRequestMessage request) + { + if (request.Headers is not null && request.Headers.Authorization is not null && request.Headers.Authorization.Parameter is not null) + { + // redact the auth parameter, but leave the last 4 characters for developers to validate + // the right token was sent + var authParameter = request.Headers.Authorization.Parameter; + var redactLength = authParameter.Length - 4; + if (redactLength < 0) + { + redactLength = authParameter.Length; + } + + request.Headers.Authorization = new AuthenticationHeaderValue( + request.Headers.Authorization.Scheme, + string.Concat("****", authParameter.Substring(redactLength).AsSpan())); + } + + return request; + } + private void ProcessAuthentication() { if (Authentication == WebAuthenticationType.Basic) @@ -1575,9 +1597,8 @@ internal void SetRequestContent(HttpRequestMessage request, string content) ArgumentNullException.ThrowIfNull(content); Encoding encoding = null; - string contentType = WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType]; - if (contentType is not null) + if (WebSession.ContentHeaders.TryGetValue(HttpKnownHeaderNames.ContentType, out string contentType) && contentType is not null) { // If Content-Type contains the encoding format (as CharSet), use this encoding format // to encode the Body of the WebRequest sent to the server. Default Encoding format @@ -1772,6 +1793,7 @@ private static StringContent GetMultipartStringContent(object fieldName, object ContentDispositionHeaderValue contentDisposition = new("form-data"); contentDisposition.Name = LanguagePrimitives.ConvertTo(fieldName); + // codeql[cs/information-exposure-through-exception] - PowerShell is an on-premise product, meaning local users would already have access to the binaries and stack traces. Therefore, the information would not be exposed in the same way it would be for an ASP .NET service. StringContent result = new(LanguagePrimitives.ConvertTo(fieldValue)); result.Headers.ContentDisposition = contentDisposition; 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 d03debf3fc0..52ff515b0b2 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -265,7 +265,7 @@ internal static async Task ReadAsync(this Stream stream, Memory buffe { if (readTimeout == Timeout.InfiniteTimeSpan) { - return await stream.ReadAsync(buffer, cancellationToken); + return await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); } using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); @@ -292,7 +292,7 @@ internal static async Task CopyToAsync(this Stream source, Stream destination, T if (perReadTimeout == Timeout.InfiniteTimeSpan) { // No timeout - use fast path - await source.CopyToAsync(destination, cancellationToken); + await source.CopyToAsync(destination, cancellationToken).ConfigureAwait(false); return; } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs index 30106d9a1e7..893b6fbb464 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs @@ -203,35 +203,35 @@ 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,6 +241,8 @@ internal enum ParameterBitmap : long EPBypass = 0x0000002000000000, // ExecutionPolicy bypass EPUndefined = 0x0000004000000000, // ExecutionPolicy undefined EPIncorrect = 0x0000008000000000, // ExecutionPolicy incorrect + // V2 Socket Server Mode + V2SocketServerMode = 0x0000100000000000, // -V2SocketServerMode | -v2so } internal ParameterBitmap ParametersUsed = 0; @@ -597,6 +599,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 +945,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; @@ -1167,6 +1204,35 @@ 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 { @@ -1521,6 +1587,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; @@ -1553,6 +1622,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 3a9ab8e7f45..b3cc69ddf12 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -186,7 +186,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); @@ -230,6 +249,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); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx index decca21bb00..33445ceebd2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx @@ -222,4 +222,10 @@ Valid formats are: The specified arguments must not contain null elements. + + 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 ce124ec084c..9bc06e0d42f 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx @@ -182,4 +182,10 @@ The current session does not support debugging; execution will continue. Run as Administrator + + 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/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 3c00ae295b8..2307d1565ac 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.GlobalTool.Shim/GlobalToolShim.cs b/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs index c8e95628687..356cde68152 100644 --- a/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs +++ b/src/Microsoft.PowerShell.GlobalTool.Shim/GlobalToolShim.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; @@ -30,9 +31,10 @@ public static int Main(string[] args) string platformFolder = isWindows ? WinFolderName : UnixFolderName; - string argsString = args.Length > 0 ? string.Join(" ", args) : null; + var arguments = new List(args.Length + 1); var pwshPath = Path.Combine(currentPath, platformFolder, PwshDllName); - string processArgs = string.IsNullOrEmpty(argsString) ? $"\"{pwshPath}\"" : $"\"{pwshPath}\" {argsString}"; + arguments.Add(pwshPath); + arguments.AddRange(args); if (File.Exists(pwshPath)) { @@ -41,7 +43,7 @@ public static int Main(string[] args) e.Cancel = true; }; - var process = System.Diagnostics.Process.Start("dotnet", processArgs); + var process = System.Diagnostics.Process.Start("dotnet", arguments); process.WaitForExit(); return process.ExitCode; } diff --git a/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json index 8ba6dc2eba9..4a5e3e367ec 100644 --- a/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json +++ b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json @@ -1,4 +1,4 @@ -// This is required to roll forward to runtime 3.x when 2.x is not installed +// This is required to roll forward to supported minor.patch versions of the runtime. { - "rollForwardOnNoCandidateFx": 2 + "rollForwardOnNoCandidateFx": 1 } diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 749e916eab5..16f8d2a1e59 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,12 +16,18 @@ + + - + + + + - - - + + + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 084ba8e2ffe..9b450e12347 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,10 +7,11 @@ + - + diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 80a1b7e2022..dfac06cb64a 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,9 +13,9 @@ - + - + diff --git a/src/Modules/nuget.config b/src/Modules/nuget.config index b0fc73009da..388a65572dd 100644 --- a/src/Modules/nuget.config +++ b/src/Modules/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs index 0aba1eddfe4..6be8d3c595e 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs @@ -36,16 +36,19 @@ internal sealed partial class PowerShellAssemblyLoadContext /// /// Initialize a singleton of PowerShellAssemblyLoadContext. /// - internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths) + internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths, bool throwOnReentry) { lock (s_syncObj) { - if (Instance != null) + if (Instance is null) + { + Instance = new PowerShellAssemblyLoadContext(basePaths); + } + else if (throwOnReentry) { throw new InvalidOperationException(SingletonAlreadyInitialized); } - Instance = new PowerShellAssemblyLoadContext(basePaths); return Instance; } } @@ -581,7 +584,8 @@ public static void SetPowerShellAssemblyLoadContext([MarshalAs(UnmanagedType.LPW { ArgumentException.ThrowIfNullOrEmpty(basePaths); - PowerShellAssemblyLoadContext.InitializeSingleton(basePaths); + // Disallow calling this method from native code for more than once. + PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, throwOnReentry: true); } } 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 182af55d641..8bc6b1971cf 100644 --- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs +++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs @@ -946,14 +946,29 @@ private static IEnumerable ViewsOf_System_Management_Autom $isFirstElement = $true foreach ($value in $prop.Value) { $null = $output.Append($newline) - if (!$isFirstElement) { - $null = $output.Append($newline) + $valueIndent = ' ' * ($newIndent + 2) + + if ($value -is [Type]) { + # Just show the typename instead of it as an object + $null = $output.Append(""${prefix}${valueIndent}[$($value.ToString())]"") + } + elseif ($value -is [string] -or $value.GetType().IsPrimitive) { + $null = $output.Append(""${prefix}${valueIndent}${value}"") + } + else { + if (!$isFirstElement) { + $null = $output.Append($newline) + } + $null = $output.Append((Show-ErrorRecord $value $newIndent ($depth + 1))) } - $null = $output.Append((Show-ErrorRecord $value $newIndent ($depth + 1))) $isFirstElement = $false } } } + elseif ($prop.Value -is [Type]) { + # Just show the typename instead of it as an object + $null = $output.Append(""[$($prop.Value.ToString())]"") + } # Anything else, we convert to string. # ToString() can throw so we use LanguagePrimitives.TryConvertTo() to hide a convert error else { diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index 64ed5bad6cf..0ddc307b646 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -173,7 +173,10 @@ private TableHeaderInfo GenerateTableHeaderInfoFromDataBaseInfo(PSObject so) ci.alignment = colHeader.alignment; if (colHeader.label != null) { - ci.HeaderMatchesProperty = so.Properties[colHeader.label.text] is not null; + if (colHeader.label.text != string.Empty) + { + ci.HeaderMatchesProperty = so.Properties[colHeader.label.text] is not null; + } ci.label = this.dataBaseInfo.db.displayResourceManagerCache.GetTextTokenString(colHeader.label); } diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 4cc9ed73321..828bd16a907 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -10,10 +10,13 @@ 11.0 true true + RS1035 - + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 1568b76ee0e..bec5516cb6b 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -19,9 +19,7 @@ - + @@ -30,25 +28,28 @@ - + - - - - + + + + + + + - - - - - + + + + + - - + + - + diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 357ce126ab5..a06df801e68 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -4892,12 +4892,15 @@ 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 (i == homeIndex) { _ = sb.Append('~'); i += homePath.Length - 1; continue; } +#endif EscapeCharIfNeeded(sb, path, i, stringType, literalPath, useSingleQuoteEscapeRules, ref quotesAreNeeded); _ = sb.Append(path[i]); diff --git a/src/System.Management.Automation/engine/ExecutionContext.cs b/src/System.Management.Automation/engine/ExecutionContext.cs index 56f64c1a5c2..e0e078346e9 100644 --- a/src/System.Management.Automation/engine/ExecutionContext.cs +++ b/src/System.Management.Automation/engine/ExecutionContext.cs @@ -1385,6 +1385,7 @@ private static Assembly LoadAssembly(string name, string filePath, out Exception { try { + // codeql[cs/dll-injection-remote] - The dll is loaded during the initial state setup, which is expected behavior. This allows users hosting PowerShell to load additional C# types to enable their specific scenarios. loadedAssembly = Assembly.LoadFrom(filePath); return loadedAssembly; } diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs index bf7742526f1..fcdaeb65d3c 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs @@ -13,8 +13,8 @@ internal static unsafe partial class Windows { private static bool s_WNetApiNotAvailable; - [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW")] - internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength); + [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW", StringMarshalling = StringMarshalling.Utf16)] + internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength); internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) { @@ -33,11 +33,8 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) bufferSize = 3; #endif - // TODO: change ushort with char after LibraryImport will support 'ref char' - // without applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' - // to the assembly. - ReadOnlySpan driveName = stackalloc ushort[] { drive, ':', '\0' }; - Span uncBuffer = stackalloc ushort[(int)bufferSize]; + ReadOnlySpan driveName = stackalloc char[] { drive, ':', '\0' }; + Span uncBuffer = stackalloc char[(int)bufferSize]; int errorCode = ERROR_NO_NETWORK; try @@ -52,26 +49,28 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice((int)bufferSize).ToString(); + // exclude null terminator + uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString(); } else if (errorCode == ERROR_MORE_DATA) { - ushort[]? rentedArray = null; + char[]? rentedArray = null; try { - uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize); + uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize); errorCode = WNetGetConnection(driveName, uncBuffer, ref bufferSize); if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice((int)bufferSize).ToString(); + // exclude null terminator + uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString(); } } finally { if (rentedArray is not null) { - ArrayPool.Shared.Return(rentedArray); + ArrayPool.Shared.Return(rentedArray); } } } diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs index ac78e5e80d5..87a6dcb7804 100644 --- a/src/System.Management.Automation/engine/LanguagePrimitives.cs +++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs @@ -3986,44 +3986,46 @@ internal object Convert(object valueToConvert, // - It's in FullLanguage but not because it's part of a parameter binding that is transitioning from ConstrainedLanguage to FullLanguage // When this is invoked from a parameter binding in transition from ConstrainedLanguage environment to FullLanguage command, we disallow // the property conversion because it's dangerous. - if (ecFromTLS == null || (ecFromTLS.LanguageMode == PSLanguageMode.FullLanguage && !ecFromTLS.LanguageModeTransitionInParameterBinding)) + bool canProceedWithConversion = ecFromTLS == null || (ecFromTLS.LanguageMode == PSLanguageMode.FullLanguage && !ecFromTLS.LanguageModeTransitionInParameterBinding); + if (!canProceedWithConversion) { - result = _constructor(); - var psobject = valueToConvert as PSObject; - if (psobject != null) - { - // Use PSObject properties to perform conversion. - SetObjectProperties(result, psobject, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, formatProvider, recursion, ignoreUnknownMembers); - } - else + if (SystemPolicy.GetSystemLockdownPolicy() != SystemEnforcementMode.Audit) { - // Use provided property dictionary to perform conversion. - // The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2 - IDictionary properties = valueToConvert as IDictionary; - SetObjectProperties(result, properties, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: false); + throw InterpreterError.NewInterpreterException( + valueToConvert, + typeof(RuntimeException), + errorPosition: null, + "HashtableToObjectConversionNotSupportedInDataSection", + ParserStrings.HashtableToObjectConversionNotSupportedInDataSection, + resultType.ToString()); } - typeConversion.WriteLine("Constructor result: \"{0}\".", result); - } - else - { - if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit) - { - SystemPolicy.LogWDACAuditMessage( + // When in audit mode, we report but don't enforce, so we will proceed with the conversion. + SystemPolicy.LogWDACAuditMessage( context: ecFromTLS, title: ExtendedTypeSystem.WDACHashTypeLogTitle, message: StringUtil.Format(ExtendedTypeSystem.WDACHashTypeLogMessage, resultType.FullName), fqid: "LanguageHashtableConversionNotAllowed", dropIntoDebugger: true); - } - else - { - RuntimeException rte = InterpreterError.NewInterpreterException(valueToConvert, typeof(RuntimeException), null, - "HashtableToObjectConversionNotSupportedInDataSection", ParserStrings.HashtableToObjectConversionNotSupportedInDataSection, resultType.ToString()); - throw rte; - } } + result = _constructor(); + var psobject = valueToConvert as PSObject; + if (psobject != null) + { + // Use PSObject properties to perform conversion. + SetObjectProperties(result, psobject, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, formatProvider, recursion, ignoreUnknownMembers); + } + else + { + // Use provided property dictionary to perform conversion. + // The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2 + IDictionary properties = valueToConvert as IDictionary; + SetObjectProperties(result, properties, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: false); + } + + typeConversion.WriteLine("Constructor result: \"{0}\".", result); + return result; } catch (TargetInvocationException ex) diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 48b68574f54..72810cbbd79 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -4439,31 +4439,14 @@ private bool GetListOfFilesFromData( if (listOfStrings != null) { - var psHome = Utils.DefaultPowerShellAppBase; - string alternateDirToCheck = null; - if (moduleBase.StartsWith(psHome, StringComparison.OrdinalIgnoreCase)) - { - // alternateDirToCheck is an ugly hack for how Microsoft.PowerShell.Diagnostics and - // Microsoft.WSMan.Management refer to the ps1xml that was in $PSHOME but removed. - alternateDirToCheck = moduleBase + "\\..\\.."; - } - list = new List(); foreach (string s in listOfStrings) { try { string fixedFileName = FixFileNameWithoutLoadingAssembly(moduleBase, s, extension); - var dir = Path.GetDirectoryName(fixedFileName); - if (string.Equals(psHome, dir, StringComparison.OrdinalIgnoreCase) || - (alternateDirToCheck != null && string.Equals(alternateDirToCheck, dir, StringComparison.OrdinalIgnoreCase))) - { - // The ps1xml file no longer exists in $PSHOME. Downstream, we expect a resolved path, - // which we can't really do b/c the file doesn't exist. - fixedFileName = psHome + "\\" + Path.GetFileName(s); - } - else if (verifyFilesExist && !File.Exists(fixedFileName)) + if (verifyFilesExist && !File.Exists(fixedFileName)) { string message = StringUtil.Format(SessionStateStrings.PathNotFound, fixedFileName); throw new FileNotFoundException(message, fixedFileName); @@ -4663,7 +4646,8 @@ private string FixFileName(string moduleName, string moduleBase, string fileName } // Try to get the resolved fully qualified path to the file. - // Note that, the 'IsRooted' method also returns true for relative paths, in which case we need to check for 'combinedPath' as well. + // We only use the combinedPath to resolve the file path, as that combines the file specified with the moduleBase path + // and ensures that the file is found relative only to the moduleBase not current working directory path. // * For example, the 'Microsoft.WSMan.Management.psd1' in Windows PowerShell defines 'FormatsToProcess="..\..\WSMan.format.ps1xml"'. // * For such a module, we will have the following input when reaching this method: // - moduleBase = 'C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Microsoft.WSMan.Management' @@ -4672,9 +4656,7 @@ private string FixFileName(string moduleName, string moduleBase, string fileName // The 'Microsoft.WSMan.Management' module in PowerShell was updated to not use the relative path for 'FormatsToProcess' entry, // but it's safer to keep the original behavior to avoid unexpected breaking changes. string combinedPath = Path.Combine(moduleBase, fileName); - string resolvedPath = IsRooted(fileName) - ? ResolveRootedFilePath(fileName, Context) ?? ResolveRootedFilePath(combinedPath, Context) - : ResolveRootedFilePath(combinedPath, Context); + string resolvedPath = ResolveRootedFilePath(combinedPath, Context); // Return the path if successfully resolved. if (resolvedPath is not null) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 85b675a9ae9..0291cf32c25 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -658,6 +658,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; } } @@ -815,12 +817,6 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) { if (blocking) { - if (_stdOutByteTransfer is not null) - { - _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); - return null; - } - // If adding was completed and collection is empty (IsCompleted == true) // there is no need to do a blocking Take(), we should just return. if (!_nativeProcessOutputQueue.IsCompleted) @@ -842,17 +838,9 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) return null; } - else - { - if (_stdOutByteTransfer is not null) - { - return null; - } - ProcessOutputObject record = null; - _nativeProcessOutputQueue.TryTake(out record); - return record; - } + _nativeProcessOutputQueue.TryTake(out ProcessOutputObject record); + return record; } /// @@ -860,21 +848,38 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) /// private void ConsumeAvailableNativeProcessOutput(bool blocking) { - if (!_isRunningInBackground) + if (_isRunningInBackground) { - if (_nativeProcess.StartInfo.RedirectStandardOutput || _nativeProcess.StartInfo.RedirectStandardError) + return; + } + + bool stdOutRedirected = _nativeProcess.StartInfo.RedirectStandardOutput; + bool stdErrRedirected = _nativeProcess.StartInfo.RedirectStandardError; + if (stdOutRedirected && _stdOutByteTransfer is not null) + { + if (blocking) { - ProcessOutputObject record; - while ((record = DequeueProcessOutput(blocking)) != null) - { - if (this.Command.Context.CurrentPipelineStopping) - { - this.StopProcessing(); - return; - } + _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); + } - ProcessOutputRecord(record); + if (!stdErrRedirected) + { + return; + } + } + + if (stdOutRedirected || stdErrRedirected) + { + ProcessOutputObject record; + while ((record = DequeueProcessOutput(blocking)) != null) + { + if (this.Command.Context.CurrentPipelineStopping) + { + this.StopProcessing(); + return; } + + ProcessOutputRecord(record); } } } @@ -887,7 +892,7 @@ internal override void Complete() if (!_isRunningInBackground) { // Wait for input writer to finish. - if (!UpstreamIsNativeCommand) + if (!UpstreamIsNativeCommand || _nativeProcess.StartInfo.RedirectStandardError) { _inputWriter.Done(); } @@ -1394,6 +1399,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 }; @@ -1463,6 +1469,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; } } @@ -1772,7 +1779,7 @@ public ProcessOutputHandler( // we incrementing refCount on the same thread and before running any processing // so it's safe to do it without Interlocked. - if (process.StartInfo.RedirectStandardOutput) + if (process.StartInfo.RedirectStandardOutput && stdOutDestination is null) { _refCount++; } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index e31cf2f81ad..1ad23a40cc6 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1256,7 +1256,8 @@ internal static bool PathIsDevicePath(string path) #if UNIX return false; #else - return path.StartsWith(@"\\.\") || path.StartsWith(@"\\?\"); + // device paths can be network paths, we would need windows to parse it. + return path.StartsWith(@"\\.\") || path.StartsWith(@"\\?\") || path.StartsWith(@"\\;"); #endif } @@ -1523,6 +1524,23 @@ internal static string DisplayHumanReadableFileSize(long bytes) _ => $"0 Bytes", }; } + + /// + /// Returns true if the current session is restricted (JEA or similar sessions) + /// + /// ExecutionContext. + /// 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; + } } } diff --git a/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs b/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs index 23daa3c8713..0969d7b08c6 100644 --- a/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs +++ b/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs @@ -25,6 +25,28 @@ internal abstract class RunspaceBase : Runspace { #region constructors + /// + /// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already. + /// If powershell is hosted by a native host such as DSC, then PS ALC may be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A. + /// + /// + /// We do this both here and during the initialization of the 'ClrFacade' type. + /// This is because we want to make sure the assembly/library resolvers are: + /// 1. registered before any script/cmdlet can run. + /// 2. registered before 'ClrFacade' gets used for assembly related operations. + /// + /// The 'ClrFacade' type may be used without a Runspace created, for example, by calling type conversion methods in the 'LanguagePrimitive' type. + /// And at the mean time, script or cmdlet may run without the 'ClrFacade' type initialized. + /// That's why we attempt to create the singleton of 'PowerShellAssemblyLoadContext' at both places. + /// + static RunspaceBase() + { + if (PowerShellAssemblyLoadContext.Instance is null) + { + PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty, throwOnReentry: false); + } + } + /// /// Construct an instance of an Runspace using a custom /// implementation of PSHost. diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index 3fac9de74f6..e8ee8191a07 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -1565,7 +1565,15 @@ private static Attribute NewOutputTypeAttribute(AttributeAst ast) if (args[0] is Type) { - result = new OutputTypeAttribute(LanguagePrimitives.ConvertTo(args)); + // We avoid `ConvertTo(args)` here as CLM would throw due to `Type[]` + // being a "non-core" type. NOTE: This doesn't apply to `string[]`. + Type[] types = new Type[args.Length]; + for (int i = 0; i < args.Length; i++) + { + types[i] = LanguagePrimitives.ConvertTo(args[i]); + } + + result = new OutputTypeAttribute(types); } else { @@ -2278,25 +2286,26 @@ private Expression CaptureAstResults( switch (context) { case CaptureAstContext.AssignmentWithResultPreservation: - result = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, resultList); - - // PipelineResult might get skipped in some circumstances due to an early return or a FlowControlException thrown out, in which case - // we write to the oldPipe. This can happen in cases like: - // $(1;2;return 3) - finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, oldPipe, resultList)); - break; case CaptureAstContext.AssignmentWithoutResultPreservation: result = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, resultList); // Clear the temporary pipe in case of exception, if we are not required to preserve the results - var catchExprs = new List + if (context == CaptureAstContext.AssignmentWithoutResultPreservation) { - Expression.Call(CachedReflectionInfo.PipelineOps_ClearPipe, resultList), - Expression.Rethrow(), - Expression.Constant(null, typeof(object)) - }; + var catchExprs = new List + { + Expression.Call(CachedReflectionInfo.PipelineOps_ClearPipe, resultList), + Expression.Rethrow(), + Expression.Constant(null, typeof(object)) + }; - catches.Add(Expression.Catch(typeof(RuntimeException), Expression.Block(typeof(object), catchExprs))); + catches.Add(Expression.Catch(typeof(RuntimeException), Expression.Block(typeof(object), catchExprs))); + } + + // PipelineResult might get skipped in some circumstances due to an early return or a FlowControlException thrown out, + // in which case we write to the oldPipe. This can happen in cases like: + // $(1;2;return 3) + finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, oldPipe, resultList)); break; case CaptureAstContext.Condition: result = DynamicExpression.Dynamic(PSPipelineResultToBoolBinder.Get(), typeof(bool), resultList); diff --git a/src/System.Management.Automation/engine/parser/PSType.cs b/src/System.Management.Automation/engine/parser/PSType.cs index d01a22c305d..2fe7190f38d 100644 --- a/src/System.Management.Automation/engine/parser/PSType.cs +++ b/src/System.Management.Automation/engine/parser/PSType.cs @@ -276,7 +276,7 @@ private sealed class DefineTypeHelper internal readonly TypeBuilder _staticHelpersTypeBuilder; private readonly Dictionary _definedProperties; private readonly Dictionary>> _definedMethods; - private HashSet> _interfaceProperties; + private HashSet> _abstractProperties; internal readonly List<(string fieldName, IParameterMetadataProvider bodyAst, bool isStatic)> _fieldsToInitForMemberFunctions; private bool _baseClassHasDefaultCtor; @@ -446,9 +446,9 @@ private Type GetBaseTypes(Parser parser, TypeDefinitionAst typeDefinitionAst, ou private bool ShouldImplementProperty(string name, Type type) { - if (_interfaceProperties == null) + if (_abstractProperties == null) { - _interfaceProperties = new HashSet>(); + _abstractProperties = new HashSet>(); var allInterfaces = new HashSet(); // TypeBuilder.GetInterfaces() returns only the interfaces that was explicitly passed to its constructor. @@ -467,12 +467,23 @@ private bool ShouldImplementProperty(string name, Type type) { foreach (var property in interfaceType.GetProperties()) { - _interfaceProperties.Add(Tuple.Create(property.Name, property.PropertyType)); + _abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType)); + } + } + + if (_typeBuilder.BaseType.IsAbstract) + { + foreach (var property in _typeBuilder.BaseType.GetProperties()) + { + if (property.GetAccessors().Any(m => m.IsAbstract)) + { + _abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType)); + } } } } - return _interfaceProperties.Contains(Tuple.Create(name, type)); + return _abstractProperties.Contains(Tuple.Create(name, type)); } public void DefineMembers() diff --git a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs index 1e1ff771ac5..05c6f0f5f1e 100644 --- a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs +++ b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs @@ -1983,8 +1983,19 @@ private void InferTypeFrom(VariableExpressionAst variableExpressionAst, List 0) { - parent = switchErrorStatement.Conditions[0]; + if (switchErrorStatement.Conditions[0].Extent.EndOffset < variableExpressionAst.Extent.StartOffset) + { + parent = switchErrorStatement.Conditions[0]; + break; + } + else + { + // $_ is inside the condition that is being declared, eg: Get-Process | Sort-Object -Property {switch ($_.Proc + parent = switchErrorStatement.Parent; + continue; + } } + break; } else if (parent is ScriptBlockExpressionAst) diff --git a/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs b/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs index b3bfbe9a0d9..f76b836885a 100644 --- a/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs +++ b/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs @@ -5,6 +5,7 @@ using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; using System.Management.Automation.Runspaces.Internal; +using System.Management.Automation.Security; using Dbg = System.Management.Automation.Diagnostics; @@ -94,7 +95,22 @@ private PSCommand ParsePsCommandUsingScriptBlock(string line, bool? useLocalScop // to be parsed and evaluated on the remote session (not in the current local session). RemoteRunspace remoteRunspace = _runspaceRef.Value as RemoteRunspace; bool isConfiguredLoopback = remoteRunspace != null && remoteRunspace.IsConfiguredLoopBack; - bool isTrustedInput = !isConfiguredLoopback && (localRunspace.ExecutionContext.LanguageMode == PSLanguageMode.FullLanguage); + + bool inFullLanguage = context.LanguageMode == PSLanguageMode.FullLanguage; + if (context.LanguageMode == PSLanguageMode.ConstrainedLanguage + && SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit) + { + // In audit mode, report but don't enforce. + inFullLanguage = true; + SystemPolicy.LogWDACAuditMessage( + context: context, + title: RemotingErrorIdStrings.WDACGetPowerShellLogTitle, + message: RemotingErrorIdStrings.WDACGetPowerShellLogMessage, + fqid: "GetPowerShellMayFail", + dropIntoDebugger: true); + } + + bool isTrustedInput = !isConfiguredLoopback && inFullLanguage; // Create PowerShell from ScriptBlock. ScriptBlock scriptBlock = ScriptBlock.Create(context, line); @@ -350,7 +366,7 @@ internal void Override(RemoteRunspace remoteRunspace, object syncObject, out boo /// private void HandleHostCall(object sender, RemoteDataEventArgs eventArgs) { - System.Management.Automation.Runspaces.Internal.ClientRemotePowerShell.ExitHandler(sender, eventArgs); + ClientRemotePowerShell.ExitHandler(sender, eventArgs); } #region Robust Connection Support diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index c633fd9fe5c..3c38a3b5bdc 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -2278,7 +2278,7 @@ private System.Management.Automation.PowerShell GetPowerShellForPSv3OrLater(stri // Semantic checks on the using statement have already validated that there are no arbitrary expressions, // so we'll allow these expressions in everything but NoLanguage mode. - bool allowUsingExpressions = (Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage); + bool allowUsingExpressions = Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage; object[] usingValuesInArray = null; IDictionary usingValuesInDict = null; @@ -2428,7 +2428,7 @@ private List GetUsingVariableValues(List paramUsi // GetExpressionValue ensures that it only does variable access when supplied a VariableExpressionAst. // So, this is still safe to use in ConstrainedLanguage and will not result in arbitrary code // execution. - bool allowVariableAccess = (Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage); + bool allowVariableAccess = Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage; foreach (var varAst in paramUsingVars) { diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index 7fae8118310..d62805d7e89 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,8 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) listenSocket.Listen(1); HyperVSocket = listenSocket.Accept(); + ValidateToken(HyperVSocket, token, tokenCreationTime, MAX_TOKEN_LIFE_MINUTES * 60); + Stream = new NetworkStream(HyperVSocket, true); // Create reader/writer streams. @@ -257,8 +275,13 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) // if (listenSocket != null) { - try { listenSocket.Dispose(); } - catch (ObjectDisposedException) { } + try + { + listenSocket.Dispose(); + } + catch (ObjectDisposedException) + { + } } } catch (Exception e) @@ -272,8 +295,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 +310,6 @@ public RemoteSessionHyperVSocketServer(bool LoopbackMode) null); } } - #endregion #region IDisposable @@ -333,6 +359,107 @@ 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. + /// 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(); + + // 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); + + // Final check if we got the token before the timeout + 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); + + socket.ReceiveTimeout = 0; // Disable the timeout after successful validation + socket.SendTimeout = 0; + } } internal sealed class RemoteSessionHyperVSocketClient : IDisposable @@ -340,7 +467,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 +489,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 +507,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 +524,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 +567,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 +588,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 +653,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 +755,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 +811,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 +819,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/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 9c221f01dbb..d18eb249cb7 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2230,6 +2230,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/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/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index e3ea3d0b44b..c50c9498ba8 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -5524,7 +5524,7 @@ internal static DynamicMetaObject EnsureAllowedInLanguageMode(DynamicMetaObject return target.ThrowRuntimeError(args, moreTests, errorID, resourceString); } - string targetName = (targetValue as Type)?.FullName; + string targetName = (targetValue as Type)?.FullName ?? targetValue?.GetType().FullName; SystemPolicy.LogWDACAuditMessage( context: context, title: ParameterBinderStrings.WDACBinderInvocationLogTitle, @@ -6935,20 +6935,6 @@ internal static DynamicMetaObject InvokeDotNetMethod( expr = Expression.Block(expr, ExpressionCache.AutomationNullConstant); } - // Expression block runs two expressions in order: - // - Log method invocation to AMSI Notifications (can throw PSSecurityException) - // - Invoke method - string targetName = methodInfo.ReflectedType?.FullName ?? string.Empty; - expr = Expression.Block( - Expression.Call( - CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, - Expression.Constant(targetName), - Expression.Constant(name), - Expression.NewArrayInit( - typeof(object), - args.Select(static e => e.Expression.Cast(typeof(object))))), - expr); - // If we're calling SteppablePipeline.{Begin|Process|End}, we don't want // to wrap exceptions - this is very much a special case to help error // propagation and ensure errors are attributed to the correct code (the @@ -7111,6 +7097,7 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, invocationType != MethodInvocationType.NonVirtual; var parameters = mi.GetParameters(); var argExprs = new Expression[parameters.Length]; + var argsToLog = new List(Math.Max(parameters.Length, args.Length)); for (int i = 0; i < parameters.Length; ++i) { @@ -7135,16 +7122,21 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, if (expandParameters) { - argExprs[i] = Expression.NewArrayInit( - paramElementType, - args.Skip(i).Select( - a => a.CastOrConvertMethodArgument( + IEnumerable elements = args + .Skip(i) + .Select(a => + a.CastOrConvertMethodArgument( paramElementType, paramName, mi.Name, allowCastingToByRefLikeType: false, temps, - initTemps))); + initTemps)) + .ToList(); + + argExprs[i] = Expression.NewArrayInit(paramElementType, elements); + // User specified the element arguments, so we log them instead of the compiler-created array. + argsToLog.AddRange(elements); } else { @@ -7155,13 +7147,18 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, allowCastingToByRefLikeType: false, temps, initTemps); + argExprs[i] = arg; + argsToLog.Add(arg); } } else if (i >= args.Length) { - Diagnostics.Assert(parameters[i].IsOptional, + // We don't log the default value for an optional parameter, as it's not specified by the user. + Diagnostics.Assert( + parameters[i].IsOptional, "if there are too few arguments, FindBestMethod should only succeed if parameters are optional"); + var argValue = parameters[i].DefaultValue; if (argValue == null) { @@ -7192,17 +7189,25 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, var psRefValue = Expression.Property(args[i].Expression.Cast(typeof(PSReference)), CachedReflectionInfo.PSReference_Value); initTemps.Add(Expression.Assign(temp, psRefValue.Convert(temp.Type))); copyOutTemps.Add(Expression.Assign(psRefValue, temp.Cast(typeof(object)))); + argExprs[i] = temp; + argsToLog.Add(temp); } else { - argExprs[i] = args[i].CastOrConvertMethodArgument( + var convertedArg = args[i].CastOrConvertMethodArgument( parameterType, paramName, mi.Name, allowCastingToByRefLikeType, temps, initTemps); + + argExprs[i] = convertedArg; + // If the converted arg is a byref-like type, then we log the original arg. + argsToLog.Add(convertedArg.Type.IsByRefLike + ? args[i].Expression + : convertedArg); } } } @@ -7248,6 +7253,12 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, } } + // We need to add one expression to log the .NET invocation before actually invoking: + // - Log method invocation to AMSI Notifications (can throw PSSecurityException) + // - Invoke method + string targetName = mi.ReflectedType?.FullName ?? string.Empty; + string methodName = mi.Name is ".ctor" ? "new" : mi.Name; + if (temps.Count > 0) { if (call.Type != typeof(void) && copyOutTemps.Count > 0) @@ -7258,8 +7269,13 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target, copyOutTemps.Add(retValue); } + AddMemberInvocationLogging(initTemps, targetName, methodName, argsToLog); call = Expression.Block(call.Type, temps, initTemps.Append(call).Concat(copyOutTemps)); } + else + { + call = AddMemberInvocationLogging(call, targetName, methodName, argsToLog); + } return call; } @@ -7551,6 +7567,55 @@ internal static void InvalidateCache() } } +#nullable enable + private static Expression AddMemberInvocationLogging( + Expression expr, + string targetName, + string name, + List args) + { +#if UNIX + // For efficiency this is a no-op on non-Windows platforms. + return expr; +#else + Expression[] invocationArgs = new Expression[args.Count]; + for (int i = 0; i < args.Count; i++) + { + invocationArgs[i] = args[i].Cast(typeof(object)); + } + + return Expression.Block( + Expression.Call( + CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, + Expression.Constant(targetName), + Expression.Constant(name), + Expression.NewArrayInit(typeof(object), invocationArgs)), + expr); +#endif + } + + private static void AddMemberInvocationLogging( + List exprs, + string targetName, + string name, + List args) + { +#if !UNIX + Expression[] invocationArgs = new Expression[args.Count]; + for (int i = 0; i < args.Count; i++) + { + invocationArgs[i] = args[i].Cast(typeof(object)); + } + + exprs.Add(Expression.Call( + CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation, + Expression.Constant(targetName), + Expression.Constant(name), + Expression.NewArrayInit(typeof(object), invocationArgs))); +#endif + } +#nullable disable + #endregion } diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index eb3100ea512..8452c27b989 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -714,6 +714,18 @@ internal static SteppablePipeline GetSteppablePipeline(PipelineAst pipelineAst, // of invoking it. So the trustworthiness is defined by the trustworthiness of the // script block's language mode. bool isTrusted = scriptBlock.LanguageMode == PSLanguageMode.FullLanguage; + if (scriptBlock.LanguageMode == PSLanguageMode.ConstrainedLanguage + && SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit) + { + // In audit mode, report but don't enforce. + isTrusted = true; + SystemPolicy.LogWDACAuditMessage( + context: context, + title: ParserStrings.WDACGetSteppablePipelineLogTitle, + message: ParserStrings.WDACGetSteppablePipelineLogMessage, + fqid: "GetSteppablePipelineMayFail", + dropIntoDebugger: true); + } foreach (var commandAst in pipelineAst.PipelineElements.Cast()) { @@ -729,7 +741,7 @@ internal static SteppablePipeline GetSteppablePipeline(PipelineAst pipelineAst, var exprAst = (ExpressionAst)commandElement; var argument = Compiler.GetExpressionValue(exprAst, isTrusted, context); - var splatting = (exprAst is VariableExpressionAst && ((VariableExpressionAst)exprAst).Splatted); + var splatting = exprAst is VariableExpressionAst && ((VariableExpressionAst)exprAst).Splatted; commandParameters.Add(CommandParameterInternal.CreateArgument(argument, exprAst, splatting)); } @@ -797,8 +809,8 @@ private static CommandParameterInternal GetCommandParameter(CommandParameterAst } object argumentValue = Compiler.GetExpressionValue(argumentAst, isTrusted, context); - bool spaceAfterParameter = (errorPos.EndLineNumber != argumentAst.Extent.StartLineNumber || - errorPos.EndColumnNumber != argumentAst.Extent.StartColumnNumber); + bool spaceAfterParameter = errorPos.EndLineNumber != argumentAst.Extent.StartLineNumber || + errorPos.EndColumnNumber != argumentAst.Extent.StartColumnNumber; return CommandParameterInternal.CreateParameterWithArgument(commandParameterAst, commandParameterAst.ParameterName, errorPos.Text, argumentAst, argumentValue, spaceAfterParameter); diff --git a/src/System.Management.Automation/help/HelpCommands.cs b/src/System.Management.Automation/help/HelpCommands.cs index af79758dcb3..1b451637a5d 100644 --- a/src/System.Management.Automation/help/HelpCommands.cs +++ b/src/System.Management.Automation/help/HelpCommands.cs @@ -255,6 +255,17 @@ protected override void BeginProcessing() /// protected override void ProcessRecord() { +#if !UNIX + string fileSystemPath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(this.Name); + string normalizedName = FileSystemProvider.NormalizePath(fileSystemPath); + // In a restricted session, do not allow help on network paths or device paths, because device paths can be used to bypass the restrictions. + if (Utils.IsSessionRestricted(this.Context) && (FileSystemProvider.PathIsNetworkPath(normalizedName) || Utils.PathIsDevicePath(normalizedName))) { + Exception e = new ArgumentException(HelpErrors.NoNetworkCommands, "Name"); + ErrorRecord errorRecord = new ErrorRecord(e, "CommandNameNotAllowed", ErrorCategory.InvalidArgument, null); + this.ThrowTerminatingError(errorRecord); + } +#endif + HelpSystem helpSystem = this.Context.HelpSystem; try { @@ -504,7 +515,7 @@ private void GetAndWriteParameterInfo(HelpInfo helpInfo) } /// - /// Validates input parameters. + /// Validates input parameters. /// /// Category specified by the user. /// 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? diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 7236a6f3891..f4f432d478a 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -105,7 +105,7 @@ public FileSystemProvider() /// /// The path with all / normalized to \ /// - private static string NormalizePath(string path) + internal static string NormalizePath(string path) { return GetCorrectCasedPath(path.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator)); } @@ -1080,6 +1080,21 @@ protected override bool IsValidPath(string path) } } + // .NET introduced a change where invalid characters are accepted https://learn.microsoft.com/en-us/dotnet/core/compatibility/2.1#path-apis-dont-throw-an-exception-for-invalid-characters + // We need to check for invalid characters ourselves. `Path.GetInvalidFileNameChars()` is a supserset of `Path.GetInvalidPathChars()` + + // Remove drive root first + string pathWithoutDriveRoot = path.Substring(Path.GetPathRoot(path).Length); + char[] invalidFileChars = Path.GetInvalidFileNameChars(); + + foreach (string segment in pathWithoutDriveRoot.Split(Path.DirectorySeparatorChar)) + { + if (segment.IndexOfAny(invalidFileChars) != -1) + { + return false; + } + } + return true; } @@ -1309,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; diff --git a/src/System.Management.Automation/resources/HelpErrors.resx b/src/System.Management.Automation/resources/HelpErrors.resx index 851e457cf27..27634de2995 100644 --- a/src/System.Management.Automation/resources/HelpErrors.resx +++ b/src/System.Management.Automation/resources/HelpErrors.resx @@ -187,4 +187,7 @@ To update these Help topics, start PowerShell by using the "Run as Administrator ForwardHelpTargetName cannot refer to the function itself. + + Cannot get help from a network location when in a restricted session. + diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 5631525cacc..a45a5165b03 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -1361,4 +1361,10 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent The ForEach keyword will fail '{0}' iteration item method invocation when run in Constrained Language mode. + + Expression Evaluation May Fail + + + Creating a steppable pipeline from a script block may require evaluating some expressions within the script block. The expression evaluation will silently fail and return 'null' in Constrained Language mode, unless the expression represents a constant value. + diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index f65d536f639..05f12b0c29b 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1714,4 +1714,19 @@ SSH client process terminated before connection could be established. The session configuration file contains an unknown configuration option: {0}. + + Expression Evaluation May Fail + + + Creating a PowerShell object from a script block may require evaluating some expressions within the script block. The expression evaluation will silently fail and return 'null' in Constrained Language mode, unless the expression represents a constant value. + + + 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/src/System.Management.Automation/security/wldpNativeMethods.cs b/src/System.Management.Automation/security/wldpNativeMethods.cs index a95a78dbdbe..ab49f927614 100644 --- a/src/System.Management.Automation/security/wldpNativeMethods.cs +++ b/src/System.Management.Automation/security/wldpNativeMethods.cs @@ -6,8 +6,10 @@ // #if !UNIX +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Management.Automation.Internal; +using System.Management.Automation.Runspaces; using System.Management.Automation.Tracing; using System.Runtime.InteropServices; @@ -91,9 +93,8 @@ internal static void LogWDACAuditMessage( string messageToWrite = message; // Augment the log message with current script information from the script debugger, if available. - context ??= System.Management.Automation.Runspaces.LocalPipeline.GetExecutionContextFromTLS(); + context ??= LocalPipeline.GetExecutionContextFromTLS(); bool debuggerAvailable = context is not null && - context._debugger is not null && context._debugger is ScriptDebugger; if (debuggerAvailable) @@ -108,10 +109,9 @@ context._debugger is not null && PSEtwLog.LogWDACAuditEvent(title, messageToWrite, fqid); // We drop into the debugger only if requested and we are running in the interactive host session runspace (Id == 1). - if (debuggerAvailable && - dropIntoDebugger is true && + if (debuggerAvailable && dropIntoDebugger && context._debugger.DebugMode.HasFlag(DebugModes.LocalScript) && - System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Id == 1 && + Runspace.DefaultRunspace?.Id == 1 && context.DebugPreferenceVariable.HasFlag(ActionPreference.Break) && context.InternalHost?.UI is not null) { @@ -149,7 +149,7 @@ public static SystemEnforcementMode GetSystemLockdownPolicy() { lock (s_systemLockdownPolicyLock) { - s_systemLockdownPolicy = GetDebugLockdownPolicy(path: null); + s_systemLockdownPolicy = GetDebugLockdownPolicy(path: null, out _); } } @@ -173,93 +173,89 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( System.IO.FileStream fileStream) { SafeHandle fileHandle = fileStream.SafeFileHandle; - var systemLockdownPolicy = SystemPolicy.GetSystemLockdownPolicy(); + SystemEnforcementMode systemLockdownPolicy = GetSystemLockdownPolicy(); // First check latest WDAC APIs if available. - // Revert to legacy APIs if system policy is in AUDIT mode or debug hook is in effect. - Exception errorException = null; - if (s_wldpCanExecuteAvailable && systemLockdownPolicy == SystemEnforcementMode.Enforce) + if (systemLockdownPolicy is SystemEnforcementMode.Enforce + && s_wldpCanExecuteAvailable + && TryGetWldpCanExecuteFileResult(filePath, fileHandle, out SystemScriptFileEnforcement wldpFilePolicy)) { - try - { - string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath); - string auditMsg = $"PowerShell ExternalScriptInfo reading file: {fileName}"; + return GetLockdownPolicy(filePath, fileHandle, wldpFilePolicy); + } - int hr = WldpNativeMethods.WldpCanExecuteFile( - host: PowerShellHost, - options: WLDP_EXECUTION_EVALUATION_OPTIONS.WLDP_EXECUTION_EVALUATION_OPTION_NONE, - fileHandle: fileHandle.DangerousGetHandle(), - auditInfo: auditMsg, - result: out WLDP_EXECUTION_POLICY canExecuteResult); + // Failed to invoke WldpCanExecuteFile, revert to legacy APIs. + if (systemLockdownPolicy is SystemEnforcementMode.None) + { + return SystemScriptFileEnforcement.None; + } - PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult); + // WldpCanExecuteFile was invoked successfully so we can skip running + // legacy WDAC APIs. AppLocker must still be checked in case it is more + // strict than the current WDAC policy. + return GetLockdownPolicy(filePath, fileHandle, canExecuteResult: null); + } - if (hr >= 0) - { - switch (canExecuteResult) - { - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_ALLOWED: - return SystemScriptFileEnforcement.Allow; + private static SystemScriptFileEnforcement ConvertToModernFileEnforcement(SystemEnforcementMode legacyMode) + { + return legacyMode switch + { + SystemEnforcementMode.None => SystemScriptFileEnforcement.Allow, + SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit, + SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained, + _ => SystemScriptFileEnforcement.Block, + }; + } - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_BLOCKED: - return SystemScriptFileEnforcement.Block; + private static bool TryGetWldpCanExecuteFileResult(string filePath, SafeHandle fileHandle, out SystemScriptFileEnforcement result) + { + try + { + string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath); + string auditMsg = $"PowerShell ExternalScriptInfo reading file: {fileName}"; - case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_REQUIRE_SANDBOX: - return SystemScriptFileEnforcement.AllowConstrained; + int hr = WldpNativeMethods.WldpCanExecuteFile( + host: PowerShellHost, + options: WLDP_EXECUTION_EVALUATION_OPTIONS.WLDP_EXECUTION_EVALUATION_OPTION_NONE, + fileHandle: fileHandle.DangerousGetHandle(), + auditInfo: auditMsg, + result: out WLDP_EXECUTION_POLICY canExecuteResult); - default: - // Fall through to legacy system policy checks. - System.Diagnostics.Debug.Assert(false, $"Unknown execution policy returned from WldCanExecute: {canExecuteResult}"); - break; - } - } + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult); - // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks. - } - catch (DllNotFoundException ex) - { - // Fall back to legacy system policy checks. - s_wldpCanExecuteAvailable = false; - errorException = ex; - } - catch (EntryPointNotFoundException ex) + if (hr >= 0) { - // Fall back to legacy system policy checks. - s_wldpCanExecuteAvailable = false; - errorException = ex; + switch (canExecuteResult) + { + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_ALLOWED: + result = SystemScriptFileEnforcement.Allow; + return true; + + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_BLOCKED: + result = SystemScriptFileEnforcement.Block; + return true; + + case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_REQUIRE_SANDBOX: + result = SystemScriptFileEnforcement.AllowConstrained; + return true; + + default: + // Fall through to legacy system policy checks. + Debug.Assert(false, $"Unknown policy result returned from WldCanExecute: {canExecuteResult}"); + break; + } } - if (errorException != null) - { - PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, errorException.HResult, 0); - } + // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks. } - - // Original (legacy) WDAC and AppLocker system checks. - if (systemLockdownPolicy == SystemEnforcementMode.None) + catch (Exception ex) when (ex is DllNotFoundException or EntryPointNotFoundException) { - return SystemScriptFileEnforcement.None; + // Fall back to legacy system policy checks. + s_wldpCanExecuteAvailable = false; + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, ex.HResult, 0); } - // Check policy for file. - switch (SystemPolicy.GetLockdownPolicy(filePath, fileHandle)) - { - case SystemEnforcementMode.Enforce: - // File is not allowed by policy enforcement and must run in CL mode. - return SystemScriptFileEnforcement.AllowConstrained; - - case SystemEnforcementMode.Audit: - // File is allowed but would be run in CL mode if policy was enforced and not audit. - return SystemScriptFileEnforcement.AllowConstrainedAudit; - - case SystemEnforcementMode.None: - // No restrictions, file will run in FL mode. - return SystemScriptFileEnforcement.Allow; - - default: - System.Diagnostics.Debug.Assert(false, "GetFilePolicyEnforcement: Unknown SystemEnforcementMode."); - return SystemScriptFileEnforcement.Block; - } + result = default; + return false; } /// @@ -268,9 +264,32 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( /// An EnforcementMode that describes policy. public static SystemEnforcementMode GetLockdownPolicy(string path, SafeHandle handle) { + SystemScriptFileEnforcement modernMode = GetLockdownPolicy(path, handle, canExecuteResult: null); + Debug.Assert( + modernMode is not SystemScriptFileEnforcement.Block, + "Block should never be converted to legacy file enforcement."); + + return modernMode switch + { + SystemScriptFileEnforcement.Block => SystemEnforcementMode.Enforce, + SystemScriptFileEnforcement.AllowConstrained => SystemEnforcementMode.Enforce, + SystemScriptFileEnforcement.AllowConstrainedAudit => SystemEnforcementMode.Audit, + SystemScriptFileEnforcement.Allow => SystemEnforcementMode.None, + SystemScriptFileEnforcement.None => SystemEnforcementMode.None, + _ => throw new ArgumentOutOfRangeException(nameof(modernMode)), + }; + } + + private static SystemScriptFileEnforcement GetLockdownPolicy( + string path, + SafeHandle handle, + SystemScriptFileEnforcement? canExecuteResult) + { + SystemScriptFileEnforcement wldpFilePolicy = canExecuteResult + ?? ConvertToModernFileEnforcement(GetWldpPolicy(path, handle)); + // Check the WLDP File policy via API - var wldpFilePolicy = GetWldpPolicy(path, handle); - if (wldpFilePolicy == SystemEnforcementMode.Enforce) + if (wldpFilePolicy is SystemScriptFileEnforcement.Block or SystemScriptFileEnforcement.AllowConstrained) { return wldpFilePolicy; } @@ -282,29 +301,28 @@ public static SystemEnforcementMode GetLockdownPolicy(string path, SafeHandle ha var appLockerFilePolicy = GetAppLockerPolicy(path, handle); if (appLockerFilePolicy == SystemEnforcementMode.Enforce) { - return appLockerFilePolicy; + return ConvertToModernFileEnforcement(appLockerFilePolicy); } // At this point, LockdownPolicy = Audit or Allowed. // If there was a WLDP policy, but WLDP didn't block it, // then it was explicitly allowed. Therefore, return the result for the file. - SystemEnforcementMode systemWldpPolicy = s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None); - if ((systemWldpPolicy == SystemEnforcementMode.Audit) || - (systemWldpPolicy == SystemEnforcementMode.Enforce)) + if (s_cachedWldpSystemPolicy is SystemEnforcementMode.Audit or SystemEnforcementMode.Enforce + || wldpFilePolicy is SystemScriptFileEnforcement.AllowConstrainedAudit) { return wldpFilePolicy; } // If there was a system-wide AppLocker policy, but AppLocker didn't block it, // then return AppLocker's status. - if (s_cachedSaferSystemPolicy.GetValueOrDefault(SaferPolicy.Allowed) == - SaferPolicy.Disallowed) + if (s_cachedSaferSystemPolicy is SaferPolicy.Disallowed) { - return appLockerFilePolicy; + return ConvertToModernFileEnforcement(appLockerFilePolicy); } // If it's not set to 'Enforce' by the platform, allow debug overrides - return GetDebugLockdownPolicy(path); + GetDebugLockdownPolicy(path, out SystemScriptFileEnforcement debugPolicy); + return debugPolicy; } [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", @@ -559,7 +577,7 @@ private static SaferPolicy TestSaferPolicy(string testPathScript, string testPat return result; } - private static SystemEnforcementMode GetDebugLockdownPolicy(string path) + private static SystemEnforcementMode GetDebugLockdownPolicy(string path, out SystemScriptFileEnforcement modernEnforcement) { s_allowDebugOverridePolicy = true; @@ -570,10 +588,19 @@ private static SystemEnforcementMode GetDebugLockdownPolicy(string path) // check so that we can actually put it in the filename during testing. if (path.Contains("System32", StringComparison.OrdinalIgnoreCase)) { + modernEnforcement = SystemScriptFileEnforcement.Allow; return SystemEnforcementMode.None; } // No explicit debug allowance for the file, so return the system policy if there is one. + modernEnforcement = s_systemLockdownPolicy switch + { + SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained, + SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit, + SystemEnforcementMode.None => SystemScriptFileEnforcement.None, + _ => SystemScriptFileEnforcement.None, + }; + return s_systemLockdownPolicy.GetValueOrDefault(SystemEnforcementMode.None); } @@ -583,10 +610,13 @@ private static SystemEnforcementMode GetDebugLockdownPolicy(string path) if (result != null) { pdwLockdownState = LanguagePrimitives.ConvertTo(result); - return GetLockdownPolicyForResult(pdwLockdownState); + SystemEnforcementMode policy = GetLockdownPolicyForResult(pdwLockdownState); + modernEnforcement = ConvertToModernFileEnforcement(policy); + return policy; } // If the system-wide debug policy had no preference, then there is no enforcement. + modernEnforcement = SystemScriptFileEnforcement.None; return SystemEnforcementMode.None; } diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index aa997734353..058c33a68bf 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -22,13 +22,23 @@ internal static class ClrFacade { /// /// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already. - /// If powershell is hosted by a native host such as DSC, then PS ALC might be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A. + /// If powershell is hosted by a native host such as DSC, then PS ALC may be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A. /// + /// + /// We do this both here and during the initialization of the 'RunspaceBase' type. + /// This is because we want to make sure the assembly/library resolvers are: + /// 1. registered before any script/cmdlet can run. + /// 2. registered before 'ClrFacade' gets used for assembly related operations. + /// + /// The 'ClrFacade' type may be used without a Runspace created, for example, by calling type conversion methods in the 'LanguagePrimitive' type. + /// And at the mean time, script or cmdlet may run without the 'ClrFacade' type initialized. + /// That's why we attempt to create the singleton of 'PowerShellAssemblyLoadContext' at both places. + /// static ClrFacade() { - if (PowerShellAssemblyLoadContext.Instance == null) + if (PowerShellAssemblyLoadContext.Instance is null) { - PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty); + PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty, throwOnReentry: false); } } diff --git a/src/System.Management.Automation/utils/tracing/PSEtwLog.cs b/src/System.Management.Automation/utils/tracing/PSEtwLog.cs index 6ec720566d5..45f8f39eea9 100644 --- a/src/System.Management.Automation/utils/tracing/PSEtwLog.cs +++ b/src/System.Management.Automation/utils/tracing/PSEtwLog.cs @@ -141,7 +141,7 @@ internal static void LogWDACQueryEvent( int querySuccess, int queryResult) { - provider.LogWDACQueryEvent(queryName, fileName, querySuccess, queryResult); + provider.LogWDACQueryEvent(queryName, fileName ?? string.Empty, querySuccess, queryResult); } /// diff --git a/src/powershell-unix/runtimeconfig.template.json b/src/powershell-unix/runtimeconfig.template.json index a3075303ad5..4a5e3e367ec 100644 --- a/src/powershell-unix/runtimeconfig.template.json +++ b/src/powershell-unix/runtimeconfig.template.json @@ -1,3 +1,4 @@ +// This is required to roll forward to supported minor.patch versions of the runtime. { - "rollForwardOnNoCandidateFx": 2 + "rollForwardOnNoCandidateFx": 1 } diff --git a/src/powershell-win-core/runtimeconfig.template.json b/src/powershell-win-core/runtimeconfig.template.json index a3075303ad5..4a5e3e367ec 100644 --- a/src/powershell-win-core/runtimeconfig.template.json +++ b/src/powershell-win-core/runtimeconfig.template.json @@ -1,3 +1,4 @@ +// This is required to roll forward to supported minor.patch versions of the runtime. { - "rollForwardOnNoCandidateFx": 2 + "rollForwardOnNoCandidateFx": 1 } diff --git a/test/docker/networktest/Dockerfile b/test/docker/networktest/Dockerfile index cac78654c86..d558b139246 100644 --- a/test/docker/networktest/Dockerfile +++ b/test/docker/networktest/Dockerfile @@ -1,5 +1,5 @@ # escape=` -FROM mcr.microsoft.com/windows/servercore:ltsc2022 +FROM mcr.microsoft.com/windows/servercore:ltsc2022@sha256:5d09ffa90d91a46e2fe7652b0a37cbf5217f34a819c3d71cbe635dae8226061b SHELL ["pwsh.exe","-command"] diff --git a/test/hosting/NuGet.Config b/test/hosting/NuGet.Config deleted file mode 100644 index 765346e5343..00000000000 --- a/test/hosting/NuGet.Config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 new file mode 100644 index 00000000000..b7320ff49b7 --- /dev/null +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -0,0 +1,246 @@ +# 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 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 + + $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" + } + } + + 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/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 new file mode 100644 index 00000000000..594a729fa77 --- /dev/null +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -0,0 +1,117 @@ +# 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 + + $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: + # ^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) + } + } + } + + 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" + } + } + + 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 + # 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) + } + } + } + + 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/test/packaging/macos/package-validation.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 new file mode 100644 index 00000000000..02b09fbb078 --- /dev/null +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -0,0 +1,185 @@ +# 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 + 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 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 = @{ + "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" + } + } + } +} diff --git a/test/packaging/windows/msi.tests.ps1 b/test/packaging/windows/msi.tests.ps1 index 93a56821003..14dc40a6ff2 100644 --- a/test/packaging/windows/msi.tests.ps1 +++ b/test/packaging/windows/msi.tests.ps1 @@ -115,6 +115,27 @@ Describe -Name "Windows MSI" -Fixture { $runtime = $env:PSMsiRuntime $muEnabled = Test-IsMuEnabled + if ($runtime -like '*x86*') { + $propertiesRegKeyParent = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\PowerShellCore" + } else { + $propertiesRegKeyParent = "HKLM:\SOFTWARE\Microsoft\PowerShellCore" + } + + if ($channel -eq "preview") { + $propertiesRegKeyName = "PreviewInstallerProperties" + } else { + $propertiesRegKeyName = "InstallerProperties" + } + + # Rename the registry key that contains the saved installer + # properties so that the tests don't overwrite them. + $propertiesRegKeyPath = Join-Path -Path $propertiesRegKeyParent -ChildPath $propertiesRegKeyName + $propertiesBackupRegKeyName = "BackupInstallerProperties" + $propertiesBackupRegKeyPath = Join-Path -Path $propertiesRegKeyParent -ChildPath $propertiesBackupRegKeyName + if (Test-Path -Path $propertiesRegKeyPath) { + Rename-Item -Path $propertiesRegKeyPath -NewName $propertiesBackupRegKeyName + } + # Get any existing powershell in the path $beforePath = @(([System.Environment]::GetEnvironmentVariable('PATH', 'MACHINE')) -split ';' | Where-Object {$_ -like '*files\powershell*'}) @@ -133,10 +154,17 @@ Describe -Name "Windows MSI" -Fixture { AfterAll { Set-StrictMode -Version 3.0 + + # Restore the original saved installer properties registry key. + Remove-Item -Path $propertiesRegKeyPath -ErrorAction SilentlyContinue + if (Test-Path -Path $propertiesBackupRegKeyPath) { + Rename-Item -Path $propertiesBackupRegKeyPath -NewName $propertiesRegKeyName + } } BeforeEach { $error.Clear() + Remove-Item -Path $propertiesRegKeyPath -ErrorAction SilentlyContinue } Context "Upgrade code" { diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 2a398dad179..2b802bf091f 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,13 @@ - - + + + + + + + diff --git a/test/perf/dotnet-tools/Reporting/Reporting.csproj b/test/perf/dotnet-tools/Reporting/Reporting.csproj index 70447cf5d73..6df1cfb5d87 100644 --- a/test/perf/dotnet-tools/Reporting/Reporting.csproj +++ b/test/perf/dotnet-tools/Reporting/Reporting.csproj @@ -6,7 +6,8 @@ - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index a8b48dde151..7ca3614485b 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -6,10 +6,14 @@ 11.0 + - - - + + + + + + diff --git a/test/perf/nuget.config b/test/perf/nuget.config deleted file mode 100644 index e8b7ac6770f..00000000000 --- a/test/perf/nuget.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index 0ca8978353d..5cba5f640fa 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -994,7 +994,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 diff --git a/test/powershell/Host/Logging.Tests.ps1 b/test/powershell/Host/Logging.Tests.ps1 index a3c7b78745e..53798dc1c3c 100644 --- a/test/powershell/Host/Logging.Tests.ps1 +++ b/test/powershell/Host/Logging.Tests.ps1 @@ -43,6 +43,29 @@ enum LogKeyword ManagedPlugin = 0x100 } +# mac log command can emit json, so just use that +# we need to deconstruct the eventmessage to get the event id +# we also need to filter out the non-default messages +function Get-MacOsSyslogItems { + param ([int]$processId, [string]$logId) + $logArgs = "show", "--process", "$processId", "--style", "json" + log $logArgs | + ConvertFrom-Json | + Where-Object { $_.category -eq "$logId" -and $_.messageType -eq "Default" } | + ForEach-Object { + $s = $_.eventMessage.IndexOf('[') + 1 + $e = $_.EventMessage.IndexOf(']') + $l = $e - $s + if ($l -gt 0) { + $eventId = $_.eventMessage.SubString($s, $l) + } + else { + $eventId = "unknown" + } + $_ | Add-Member -MemberType NoteProperty -Name EventId -Value $eventId -PassThru + } +} + <# .SYNOPSIS Creates a powershell.config.json file with syslog settings @@ -317,26 +340,19 @@ Path:.* } } - It 'Verifies basic logging with no customizations' -Skip:(!$IsSupportedEnvironment) { + It 'Verifies basic logging with no customizations' -Skip:(!$IsMacOS) { try { + $timeString = [DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss') $configFile = WriteLogSettings -LogId $logId + copy-item $configFile /tmp/pwshtest.config.json $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command '$PID' - - Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 3 | - Set-Content -Path $contentFile - $items = @(Get-PSOsLog -Path $contentFile -Id $logId -After $after -TotalCount 3 -Verbose) + $items = Get-MacOsSyslogItems -processId $testPid -logId $logId $items | Should -Not -Be $null $items.Count | Should -BeGreaterThan 2 - $items[0].EventId | Should -BeExactly 'Perftrack_ConsoleStartupStart:PowershellConsoleStartup.WinStart.Informational' - $items[1].EventId | Should -BeExactly 'NamedPipeIPC_ServerListenerStarted:NamedPipe.Open.Informational' - $items[2].EventId | Should -BeExactly 'Perftrack_ConsoleStartupStop:PowershellConsoleStartup.WinStop.Informational' - # if there are more items than expected... - if ($items.Count -gt 3) - { - # Force reporting of the first unexpected item to help diagnosis - $items[3] | Should -Be $null - } + $items.EventId | Should -Contain 'Perftrack_ConsoleStartupStart:PowershellConsoleStartup.WinStart.Informational' + $items.EventId | Should -Contain 'NamedPipeIPC_ServerListenerStarted:NamedPipe.Open.Informational' + $items.EventId | Should -Contain 'Perftrack_ConsoleStartupStop:PowershellConsoleStartup.WinStop.Informational' } catch { if (Test-Path $contentFile) { @@ -346,7 +362,7 @@ Path:.* } } - It 'Verifies scriptblock logging' -Skip:(!$IsSupportedEnvironment) { + It 'Verifies scriptblock logging' -Skip:(!$IsMacOS) { try { $script = @' $PID @@ -357,24 +373,23 @@ $PID $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName $script | Out-File -FilePath $testScriptPath -Force $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath - - Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 17 | - Set-Content -Path $contentFile - $items = @(Get-PSOsLog -Path $contentFile -Id $logId -After $after -Verbose) + $items = Get-MacOsSyslogItems -processId $testPid -logId $logId $items | Should -Not -Be $null $items.Count | Should -BeGreaterThan 2 $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'} $createdEvents.Count | Should -BeGreaterOrEqual 3 + $createdEvents | ConvertTo-Json | set-content /tmp/createdEvents.json + # Verify we log that we are executing a file - $createdEvents[0].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f ".*/$testFileName") + $createdEvents[0].EventMessage | Should -Match $testFileName # Verify we log that we are the script to create the scriptblock - $createdEvents[1].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f (Get-RegEx -SimpleMatch $Script)) + $createdEvents[1].EventMessage | Should -Match (Get-RegEx -SimpleMatch $Script) # Verify we log that we are executing the created scriptblock - $createdEvents[2].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f "Write\-Verbose 'testheader123' ;Write\-verbose 'after'") + $createdEvents[2].EventMessage | Should -Match "Write-Verbose 'testheader123' ;Write-verbose 'after'" } catch { if (Test-Path $contentFile) { @@ -384,35 +399,28 @@ $PID } } - It 'Verifies scriptblock logging with null character' -Skip:(!$IsSupportedEnvironment) { + It 'Verifies scriptblock logging with null character' -Skip:(!$IsMacOS) { try { $script = @' $PID & ([scriptblock]::create("Write-Verbose 'testheader123$([char]0x0000)' ;Write-verbose 'after'")) '@ $configFile = WriteLogSettings -ScriptBlockLogging -LogId $logId -LogLevel Verbose - $testFileName = 'test01.ps1' + $testFileName = 'test02.ps1' $testScriptPath = Join-Path -Path $TestDrive -ChildPath $testFileName $script | Out-File -FilePath $testScriptPath -Force - $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath + $testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath | Select-Object -First 1 - Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 17 | - Set-Content -Path $contentFile - $items = @(Get-PSOsLog -Path $contentFile -Id $logId -After $after -Verbose) + $items = Get-MacOsSyslogItems -processId $testPid -logId $logId + $items | convertto-json | set-content /tmp/items.json - $items | Should -Not -Be $null - $items.Count | Should -BeGreaterThan 2 $createdEvents = $items | Where-Object {$_.EventId -eq 'ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose'} - $createdEvents.Count | Should -BeGreaterOrEqual 3 # Verify we log that we are executing a file - $createdEvents[0].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f ".*/$testFileName") - - # Verify we log that we are the script to create the scriptblock - $createdEvents[1].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f (Get-RegEx -SimpleMatch $Script)) + $createdEvents[0].EventMessage | Should -Match $testFileName - # Verify we log that we are executing the created scriptblock - $createdEvents[2].Message | Should -Match ($scriptBlockCreatedRegExTemplate -f "Write\-Verbose 'testheader123␀' ;Write\-verbose 'after'") + # Verify we log the null in the message + $createdEvents[1].EventMessage | Should -Match "Write-Verbose 'testheader123\`$\(\[char\]0x0000\)' ;Write-verbose 'after'" } catch { if (Test-Path $contentFile) { @@ -422,25 +430,13 @@ $PID } } - # This is pending because it results in false postitives (-Skip:(!$IsSupportedEnvironment) ) - It 'Verifies logging level filtering works' -Pending { - try { - $configFile = WriteLogSettings -LogId $logId -LogLevel Warning - $testPid = & $powershell -NoLogo -NoProfile -SettingsFile $configFile -Command '$PID' - - Export-PSOsLog -After $after -LogPid $testPid | - Set-Content -Path $contentFile - # by default, powershell startup should only logs informational events. - # With Level = Warning, nothing should be logged. - $items = Get-PSOsLog -Path $contentFile -Id $logId -After $after -TotalCount 3 - $items | Should -Be $null - } - catch { - if (Test-Path $contentFile) { - Send-VstsLogFile -Path $contentFile - } - throw - } + # this is now specific to MacOS + It 'Verifies logging level filtering works' -skip:(!$IsMacOs) { + $configFile = WriteLogSettings -LogId $logId -LogLevel Warning + $testPid = & $powershell -NoLogo -NoProfile -SettingsFile $configFile -Command '$PID' + + $items = Get-MacOsSyslogItems -processId $testPid -logId $logId + $items | Should -Be $null -Because ("{0} Warning event logs were found" -f @($items).Count) } } diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index 613e673ceef..dec70a2c1ba 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -1227,12 +1227,16 @@ class InheritedClassTest : System.Attribute $res.CompletionMatches[0].CompletionText | Should -Be "`"$expectedPath`"" } - It "Should keep '~' in completiontext when it's used to refer to home in input" { + It "Should handle '~' in completiontext when it's used to refer to home in input" { $res = TabExpansion2 -inputScript "~$separator" # select the first answer which does not have a space in the completion (those completions look like & '3D Objects') $observedResult = $res.CompletionMatches.Where({$_.CompletionText.IndexOf("&") -eq -1})[0].CompletionText $completedText = $res.CompletionMatches.CompletionText -join "," - $observedResult | Should -BeLike "~$separator*" -Because "$completedText" + if ($IsWindows) { + $observedResult | Should -BeLike "$home$separator*" -Because "$completedText" + } else { + $observedResult | Should -BeLike "~$separator*" -Because "$completedText" + } } It "Should use '~' as relative filter text when not followed by separator" { @@ -1297,7 +1301,7 @@ class InheritedClassTest : System.Attribute Context "Cmdlet name completion" { BeforeAll { $testCases = @( - @{ inputStr = "get-c*item"; expected = "Get-ChildItem" } + @{ inputStr = "get-ch*item"; expected = "Get-ChildItem" } @{ inputStr = "set-alia?"; expected = "Set-Alias" } @{ inputStr = "s*-alias"; expected = "Set-Alias" } @{ inputStr = "se*-alias"; expected = "Set-Alias" } @@ -1693,6 +1697,11 @@ class InheritedClassTest : System.Attribute $res.CompletionMatches[0].CompletionText | Should -BeExactly 'Black' # 0 = NonPositive } + It 'Tab completion of $_ inside incomplete switch condition' { + $res = TabExpansion2 -inputScript 'Get-PSDrive | Sort-Object -Property {switch ($_.nam' + $res.CompletionMatches[0].CompletionText | Should -Be 'Name' + } + It "Test [CommandCompletion]::GetNextResult" { $inputStr = "Get-Command -Type Alias,c" $res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length @@ -1988,7 +1997,7 @@ dir -Recurse ` } It "Test complete module file name" { - $inputStr = "using module test" + $inputStr = "using module testm" $res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length $res.CompletionMatches | Should -HaveCount 1 $res.CompletionMatches[0].CompletionText | Should -BeExactly ".${separator}testModule.psm1" diff --git a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 index cf304d5918e..af013076029 100644 --- a/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 +++ b/test/powershell/Language/Classes/scripting.Classes.inheritance.tests.ps1 @@ -628,3 +628,47 @@ class Derived : Base $sb.Invoke() | Should -Be 200 } } + +Describe 'Base type has abstract properties' -Tags "CI" { + It 'can derive from `FileSystemInfo`' { + ## FileSystemInfo has 3 abstract members that a derived type needs to implement + ## - public abstract bool Exists { get; } + ## - public abstract string Name { get; } + ## - public abstract void Delete (); + + class myFileSystemInfo : System.IO.FileSystemInfo + { + [string] $Name + [bool] $Exists + + myFileSystemInfo([string]$path) + { + # ctor + $this.Name = $path + $this.Exists = $true + } + + [void] Delete() + { + } + } + + $myFile = [myFileSystemInfo]::new('Hello') + $myFile.Name | Should -Be 'Hello' + $myFile.Exists | Should -BeTrue + } + + It 'deriving from `FileSystemInfo` will fail when the abstract property `Exists` is not implemented' { + $script = [scriptblock]::Create('class WillFail : System.IO.FileSystemInfo { [string] $Name }') + $failure = $null + try { + & $script + } catch { + $failure = $_ + } + + $failure | Should -Not -BeNullOrEmpty + $failure.FullyQualifiedErrorId | Should -BeExactly "TypeCreationError" + $failure.Exception.Message | Should -BeLike "*'get_Exists'*" + } +} diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 index d166ca265c7..542f1724303 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 @@ -213,6 +213,12 @@ Describe "Native Command Processor" -tags "Feature" { Wait-UntilTrue -sb { (Get-Process mmc).Count -gt 0 } -TimeoutInMilliseconds 5000 -IntervalInMilliseconds 1000 | Should -BeTrue Get-Process mmc | Stop-Process } + + It 'Can redirect stdout and stderr to different files' { + testexe -stderrandout testing > $TestDrive/stdout.txt 2> $TestDrive/stderr.txt + Get-Content $TestDrive/stdout.txt | Should -Be testing + Get-Content $TestDrive/stderr.txt | Should -Be gnitset + } } Describe "Open a text file with NativeCommandProcessor" -tags @("Feature", "RequireAdminOnWindows") { diff --git a/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 b/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 index fff4993ffec..56bc16b2710 100644 --- a/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 +++ b/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 @@ -81,28 +81,6 @@ Describe "Scripting.Followup.Tests" -Tags "CI" { $result | Should -BeOfType 'System.Collections.Specialized.OrderedDictionary' } - It "Don't preserve result when no need to do so in case of flow-control exception" { - function TestFunc1([switch]$p) { - ## No need to preserve and flush the results from the IF statement to the outer - ## pipeline, because the results are supposed to be assigned to a variable. - if ($p) { - $null = if ($true) { "one"; return "two" } - } else { - $a = foreach ($a in 1) { "one"; return; } - } - } - - function TestFunc2 { - ## The results from the sub-expression need to be preserved and flushed to the outer pipeline. - $("1";return "2") - } - - TestFunc1 | Should -Be $null - TestFunc1 -p | Should -Be $null - - TestFunc2 | Should -Be @("1", "2") - } - It "'[NullString]::Value' should be treated as string type when resolving .NET method" { $testType = 'NullStringTest' -as [type] if (-not $testType) { @@ -146,4 +124,27 @@ public class NullStringTest { $result = & $powershell -noprofile -c '[System.Text.Encoding]::GetEncoding("IBM437").WebName' $result | Should -BeExactly "ibm437" } + + It 'Return statement on the right side of an assignment should write the retrun value to outer pipe' { + function TestFunc1 { + ## The return value are not assigned to the variable but should be written to the outer pipe. + $Global:mylhsvar = if ($true) { return "one" } + } + + function TestFunc2 { + ## The results from the sub-expression need to be preserved and flushed to the outer pipeline. + $("1";return "2") + } + + try { + $Global:mylhsvar = $null + TestFunc1 | Should -BeExactly "one" + TestFunc2 | Should -Be @("1", "2") + + $Global:mylhsvar | Should -Be $null + } + finally { + Remove-Variable -Name mylhsvar -Scope Global + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Error.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Error.Tests.ps1 new file mode 100644 index 00000000000..9bec24f302e --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Get-Error.Tests.ps1 @@ -0,0 +1,107 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Get-Error" -Tags "CI" { + It "Does not hang when serializing exception with array with type instances" { + $ps = [PowerShell]::Create() + $null = $ps.AddScript(@' + class GetErrorWithTypeArray : Exception { + [type[]]$Values + [type]$Type + + GetErrorWithTypeArray ([string]$Message) : base($Message) { + $this.Values = [type[]]@([string], [int]) + $this.Type = [bool] + } + } + try { throw [GetErrorWithTypeArray]::new("") } catch {} + Get-Error | Out-String +'@) + + $task = $ps.BeginInvoke() + if (-not $task.AsyncWaitHandle.WaitOne(5000)) { + $null = $ps.BeginStop($null, $null) + throw "Timed out waiting for Get-Error to serialize" + } + + $result = $ps.EndInvoke($task) + $result.Count | Should -Be 1 + $result[0] | Should -BeOfType ([string]) + + $formattedError = (@( + $result[0] -split "\r?\n" | ForEach-Object { + $_.TrimEnd() + } + ) -join ([Environment]::NewLine)).Trim() + + $formattedError | Should -Be @' +Exception : + Values : + [System.String] + [System.Int32] + Type : [System.Boolean] + HResult : -2146233088 +CategoryInfo : OperationStopped: (:) [], GetErrorWithTypeArray +InvocationInfo : + ScriptLineNumber : 10 + OffsetInLine : 19 + HistoryId : 1 + Line : try { throw [GetErrorWithTypeArray]::new("") } catch {} + + Statement : throw [GetErrorWithTypeArray]::new("") + PositionMessage : At line:10 char:19 + + try { throw [GetErrorWithTypeArray]::new("") } catch {} + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CommandOrigin : Internal +ScriptStackTrace : at , : line 10 +'@.Trim() + } + + It "Formats strings and primitive types in an array" { + $ps = [PowerShell]::Create() + $null = $ps.AddScript(@' + class GetErrorPrimitiveArray : Exception { + [object[]]$Values + + GetErrorPrimitiveArray ([string]$Message) : base($Message) { + $this.Values = @(1, "alpha", 0.5) + } + } + try { throw [GetErrorPrimitiveArray]::new("") } catch {} + Get-Error | Out-String +'@) + + $result = $ps.Invoke() + $result.Count | Should -Be 1 + $result[0] | Should -BeOfType ([string]) + + $formattedError = (@( + $result[0] -split "\r?\n" | ForEach-Object { + $_.TrimEnd() + } + ) -join ([Environment]::NewLine)).Trim() + + $formattedError | Should -Be @' +Exception : + Type : GetErrorPrimitiveArray + Values : + 1 + alpha + 0.5 + HResult : -2146233088 +CategoryInfo : OperationStopped: (:) [], GetErrorPrimitiveArray +InvocationInfo : + ScriptLineNumber : 8 + OffsetInLine : 19 + HistoryId : 1 + Line : try { throw [GetErrorPrimitiveArray]::new("") } catch {} + + Statement : throw [GetErrorPrimitiveArray]::new("") + PositionMessage : At line:8 char:19 + + try { throw [GetErrorPrimitiveArray]::new("") } catch {} + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CommandOrigin : Internal +ScriptStackTrace : at , : line 8 +'@.Trim() + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/ModuleConstraint.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/ModuleConstraint.Tests.ps1 index 34ddfd6fc53..d512b178fa7 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/ModuleConstraint.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/ModuleConstraint.Tests.ps1 @@ -210,6 +210,48 @@ Describe "Module loading with version constraints" -Tags "Feature" { Get-Module $moduleName | Remove-Module } + It "Loads the module files (ie .ps1xml) relative to module base only" { + # Create module base file structure + $testModule2Name = "TestModule2" + $testModule2Base = Join-Path $TestDrive -ChildPath "$($testModule2Name)Base" # $TestDrive/TestModule2Base + New-Item -Path $testModule2Base -ItemType Directory + $testModule2Path = Join-Path $testModule2Base -ChildPath $testModule2Name # $TestDrive/TestModule2Base/TestModule2 + New-Item -Path $testModule2Path -ItemType Directory + + $assetsFolderPath = Join-Path $PSScriptRoot -ChildPath "assets" + + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).psd1") -Destination $testModule2Path # $TestDrive/TestModule2Base/TestModule2/TestModule2.psd1 + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).psm1") -Destination $testModule2Path # $TestDrive/TestModule2Base/TestModule2/TestModule2.psm1 + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).Format.ps1xml") -Destination $testModule2Base # $TestDrive/TestModule2Base/TestModule2.Format.ps1xml + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).Types.ps1xml") -Destination $testModule2Base # $TestDrive/TestModule2Base/TestModule2.Types.ps1xml + + # Also create subfolder file structure within module base + $subFolder1 = Join-Path -Path $testModule2Base -ChildPath "subFolder1" # $TestDrive/TestModule2Base/subFolder1 + New-Item -Path $subFolder1 -ItemType Directory + $subFolder2 = Join-Path -Path $subFolder1 -ChildPath "subFolder2" # $TestDrive/TestModule2Base/subFolder1/subFolder2 + New-Item -Path $subFolder2 -ItemType Directory + $subFolder3 = Join-Path -Path $subFolder2 -ChildPath "subFolder3" # $TestDrive/TestModule2Base/subFolder1/subFolder2/subFolder3 + New-Item -Path $subFolder3 -ItemType Directory + + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).Format.ps1xml") -Destination $subFolder2 # $TestDrive/subFolder2/TestModule2.Format.ps1xml + Copy-Item -Path (Join-Path -Path $assetsFolderPath -ChildPath "$($testModule2Name).Types.ps1xml") -Destination $subFolder2 # $TestDrive/subFolder2/TestModule2.Types.ps1xml + + try { + Push-Location -Path $folder3 # $TestDrive/TestModule2Base/subFolder1/subFolder2/subFolder3 + $psd1Path = Join-Path -Path $testModule2Path -ChildPath "$($testModule2Name).psd1" + Import-Module $psd1Path + $filesLoaded = Get-MyFormatsAndTypesFilePath + $filesLoaded[0] | Should -BeLike "*${testModule2Path}*" + $filesLoaded[0] | Should -Not -BeLike "*${subFolder2}*" + $filesLoaded[1] | Should -BeLike "*${testModule2Path}*" + $filesLoaded[1] | Should -Not -BeLike "*${subFolder2}*" + } + finally { + Pop-Location + Remove-Module $testModule2Name + } + } + It "Loads the module by FullyQualifiedName from absolute path when ModuleVersion=, MaximumVersion=, RequiredVersion=, Guid=" -TestCases $guidSuccessCases { param($ModuleVersion, $MaximumVersion, $RequiredVersion, $Guid) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Format.ps1xml b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Format.ps1xml new file mode 100644 index 00000000000..9007d89341c --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Format.ps1xml @@ -0,0 +1,24 @@ + + + + TestModule2TypeTable + + TestModule2Type + + + + + + + + + + prop1 + prop2 + + + + + + + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Types.ps1xml b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Types.ps1xml new file mode 100644 index 00000000000..179aedc6eae --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.Types.ps1xml @@ -0,0 +1,13 @@ + + + TestModule2Type + + + ToString + + + + + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psd1 b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psd1 new file mode 100644 index 00000000000..53c5ed08888 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psd1 @@ -0,0 +1,127 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'TestModule2.psm1' + + # Version number of this module. + ModuleVersion = '0.0.1' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = '95943533-3149-4f26-99ab-ea3df84d28b2' + + # Author of this module + Author = 'PowerShellTesting' + + # Company or vendor of this module + CompanyName = 'Unknown' + + # Copyright statement for this module + Copyright = '(c) PowerShellTesting. All rights reserved.' + + # Description of the functionality provided by this module + # Description = '' + + # Minimum version of the PowerShell engine required by this module + # PowerShellVersion = '' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + TypesToProcess = @('../TestModule2.Types.ps1xml') + + # Format files (.ps1xml) to be loaded when importing this module + FormatsToProcess = '../TestModule2.Format.ps1xml' + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = '*' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + CmdletsToExport = '*' + + # Variables to export from this module + VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + AliasesToExport = '*' + + # DSC resources to export from this module + # DscResourcesToExport = @() + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' + + } + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psm1 new file mode 100644 index 00000000000..86a24046ebb --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/assets/TestModule2.psm1 @@ -0,0 +1,25 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +class TestModule2Type { + [string]$prop1 + [string]$prop2 + [string]$prop3 + [string]$prop4 + [string]$prop5 + [string]$prop6 +} + +function Get-MyFormatsAndTypesFilePath { + $Host.runspace.InitialSessionState.Types.FileName | ?{$_ -match "TestModule2"} + $Host.runspace.InitialSessionState.Formats.FileName | ?{$_ -match "TestModule2"} +} + +function get-mytype { + $module = [TestModule2Type]::new() + $module.prop1 = "p1" + $module.prop2 = "p2" + $module.prop3 = "p3" + $module.prop4 = "p4" + $module.prop5 = "p5" + $module +} 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/Get-Content.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Content.Tests.ps1 index 5e8e258b85a..02b6f79fbc4 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Content.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Content.Tests.ps1 @@ -283,6 +283,16 @@ Describe "Get-Content" -Tags "CI" { Get-Content -Path $testPath -Tail 0 | Should -BeNullOrEmpty } + It "Should wait for content when using -Tail 0 and -Wait" { + $testValues = @(1,2,3) + $Job = Start-Job -ScriptBlock {Get-Content -Path $using:testPath -Tail 0 -Wait} + Start-Sleep -Seconds 3 + Add-Content -Value $testValues -Path $testPath + Start-Sleep -Seconds 3 + Compare-Object -ReferenceObject $testValues -DifferenceObject ($Job | Receive-Job) | Should -BeNullOrEmpty + $Job | Remove-Job -Force + } + It "Should throw TailAndHeadCannotCoexist when both -Tail and -TotalCount are used" { { Get-Content -Path $testPath -Tail 1 -TotalCount 1 -ErrorAction Stop diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 index 77d76b6ec6a..3894b5a0257 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 @@ -17,6 +17,12 @@ Describe "Tests for New-PSDrive cmdlet." -Tag "CI","RequireAdminOnWindows" { { New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root $RemoteShare -Persist -ErrorAction Stop } | Should -Not -Throw } + It "Network drive initialization on pwsh startup DisplayRoot should have value of share" -Skip:(-not $IsWindows) { + $null = New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root $RemoteShare -Persist -ErrorAction Stop + $drive = pwsh -noprofile -outputformat XML -command "Get-PSDrive -Name $PSDriveName" + $drive.DisplayRoot | Should -Be $RemoteShare.TrimEnd('\') + } + It "Should throw exception if root is not a remote share." -Skip:(-not $IsWindows) { { New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root "TestDrive:\" -Persist -ErrorAction Stop } | Should -Throw -ErrorId 'DriveRootNotNetworkPath' } 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.Management/Start-Process.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 index 30bc1e676dc..50cde0bae6e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 @@ -115,6 +115,11 @@ Describe "Start-Process" -Tag "Feature","RequireAdminOnWindows" { { Start-Process -FilePath $pingCommand -NoNewWindow -WindowStyle Normal -ErrorAction Stop } | Should -Throw -ErrorId "InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand" } + It "ExitCode returns with -NoNewWindow, -PassThru and -Wait" { + $process = Start-Process -FilePath $pingCommand -ArgumentList $pingParam -NoNewWindow -PassThru -Wait -ErrorAction Stop + $process.ExitCode | Should -Be 0 + } + It "Should start cmd.exe with Verb 'open' and WindowStyle 'Minimized'" -Skip:(!$isFullWin) { $fileToWrite = Join-Path $TestDrive "VerbTest.txt" $process = Start-Process cmd.exe -ArgumentList "/c echo abc > $fileToWrite" -Verb open -WindowStyle Minimized -PassThru diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Path.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Path.Tests.ps1 index edad763fe71..a2619877f6d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Path.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Path.Tests.ps1 @@ -110,6 +110,48 @@ Describe "Test-Path" -Tags "CI" { Test-Path -Path $badPath -IsValid | Should -BeFalse } + It 'Windows paths should be valid: ' -skip:(!$IsWindows) -TestCases @( + @{ path = "C:\Program Files" } + @{ path = "C:\Program Files (x86)\" } + @{ path = "filesystem::z:\foo" } + @{ path = "filesystem::z:\foo\" } + @{ path = "variable::psversiontable" } + @{ path = "c:\windows\cmd.exe:test" } + ) { + param($path) + Test-Path -Path $path -IsValid | Should -BeTrue + } + + It 'Windows paths should be inavlid: ' -Skip:(!$IsWindows) -TestCases @( + @{ variant = "wildcard"; path = "C:\Program Files\foo*" } + @{ variant = "pipe symbol"; path = "C:\Program Files|p\foo" } + @{ variant = "null char"; path = "C:\Win`u{0000}dows\System32" } + ) { + param($path) + Test-Path -Path $path -IsValid | Should -BeFalse + } + + It 'Unix paths should be valid: ' -Skip:($IsWindows) -TestCases @( + @{ path = "/usr/bin" } + @{ path = "/usr/bin/" } + @{ path = "filesystem::/usr/bin" } + @{ path = "filesystem::/usr/bin/" } + @{ path = "variable::psversiontable" } + @{ path = "/usr/bi*n/test" } + @{ path = "/usr/bin/tes*t" } + ) { + param($path) + Test-Path -Path $path -IsValid | Should -BeTrue + } + + It 'Unix paths should be invalid: ' -Skip:($IsWindows) -TestCases @( + @{ variant = "null in path"; path = "/usr/bi`u{0000}n/test" } + @{ variant = "null in filename"; path = "/usr/bin/t`u{0000}est" } + ) { + param($path) + Test-Path -Path $path -IsValid | Should -BeFalse + } + It "Should return true on paths containing spaces when the path is surrounded in quotes" { Test-Path -Path "/totally a valid/path" -IsValid | Should -BeTrue } 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.PowerShell.Utility/Format-Table.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 index 78cfb88b613..34f2245909c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Format-Table.Tests.ps1 @@ -879,6 +879,55 @@ A Name B $numDecimals | Should -Be $expectedDecimals -Because $num } } + + It 'Works for empty column header label' { + $ps1xml = @' + + + + Test.Header.Empty + + Test.Format + + + + + + 4 + + + + + + + Prop + + + + + + + + +'@ + + $ps1xmlPath = Join-Path -Path $TestDrive -ChildPath 'empty.format.ps1xml' + Set-Content -Path $ps1xmlPath -Value $ps1xml + $object = [pscustomobject]@{Prop = '123'} + # run in own runspace so not affect global sessionstate + $ps = [powershell]::Create() + $ps.AddScript( { + param($ps1xmlPath, $object) + Update-FormatData -AppendPath $ps1xmlPath + $object.PSObject.TypeNames.Insert(0, 'Test.Format') + $object | Format-Table | Out-String + } ).AddArgument($ps1xmlPath).AddArgument($object) | Out-Null + $output = $ps.Invoke() + $expected = @" +Prop----123 +"@ + $output.Replace("`n","").Replace("`r","") | Should -BeExactly $expected + } } Describe 'Table color tests' -Tag 'CI' { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Group-Object.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Group-Object.Tests.ps1 index b1787bddad2..5811db60cfc 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Group-Object.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Group-Object.Tests.ps1 @@ -130,6 +130,14 @@ Describe "Group-Object" -Tags "CI" { $result[0].Name | Should -Be "" $result[0].Group | Should -Be '@{X=}' } + + It "Should handle format-like strings with curly braces like normal strings" { + $result = '{', '}', '{0}' | Group-Object + $result.Count | Should -Be 3 + $result[0].Name | Should -BeExactly '{' + $result[1].Name | Should -BeExactly '{0}' + $result[2].Name | Should -BeExactly '}' + } } Describe "Check 'Culture' parameter in order object cmdlets (Group-Object, Sort-Object, Compare-Object)" -Tags "CI" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index c9de4236960..922483e21d0 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -692,8 +692,9 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $uri = Get-WebListenerUrl -Test $method $body = GetTestData -contentType $contentType $command = "Invoke-WebRequest -Uri $uri -Body '$body' -Method $method -ContentType $contentType" + $commandNoContentType = "Invoke-WebRequest -Uri $uri -Body '$body' -Method $method" - It "Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Body [body data]" { + It "Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Body [body data]" { $result = ExecuteWebCommand -command $command ValidateResponse -response $result @@ -705,6 +706,29 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { # Validate that the response Content.data field is the same as what we sent. $jsonContent.data | Should -Be $body } + + It "Invoke-WebRequest -Uri $uri -Method $method -Body [body data]" { + + $result = ExecuteWebCommand -command $commandNoContentType + ValidateResponse -response $result + + # Validate response content + $jsonContent = $result.Output.Content | ConvertFrom-Json + $jsonContent.url | Should -Match $uri + if ($method -eq "POST") + { + $jsonContent.headers.'Content-Type' | Should -Match "application/x-www-form-urlencoded" + # Validate that the response Content.form field is the same as what we sent. + [string]$jsonContent.form | Should -Be ([string][PSCustomObject]@{$body.Split("=")[0] = [System.Object[]]}) + $jsonContent.data | Should -BeNullOrEmpty + } + else + { + # Validate that the response Content.data field is the same as what we sent. + $jsonContent.data | Should -Be $body + } + + } } } @@ -795,14 +819,9 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { ($result.Output.Content | ConvertFrom-Json).method | Should -Be "TEST" } - It "Validate Invoke-WebRequest default ContentType for CustomMethod " -TestCases @( - @{method = "POST"} - @{method = "PUT"} - ) { - param($method) - - $uri = Get-WebListenerUrl -Test $method - $command = "Invoke-WebRequest -Uri '$uri' -CustomMethod $method -Body 'testparam=testvalue'" + It "Validate Invoke-WebRequest default ContentType for CustomMethod POST" { + $uri = Get-WebListenerUrl -Test 'Post' + $command = "Invoke-WebRequest -Uri '$uri' -CustomMethod POST -Body 'testparam=testvalue'" $result = ExecuteWebCommand -command $command $jsonResult = $result.Output.Content | ConvertFrom-Json $jsonResult.form.testparam | Should -Be "testvalue" @@ -1966,6 +1985,19 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Headers.Authorization | Should -Match "^$AuthType " } + + It 'Invoke-WebRequest redacts Authorization header in ErrorRecord' { + $token = ConvertTo-SecureString -AsPlainText 'secret' + try { + Invoke-WebRequest -Authentication Bearer -Token $token -Uri https://localhost:443 + } + catch { + $errorText = Get-Error $_ | Out-String + } + + ($errorText | Select-String 'secret').Matches | Should -BeNullOrEmpty + ($errorText | Select-String '\*cret').Matches | Should -Not -BeNullOrEmpty + } } Context "Invoke-WebRequest -SslProtocol Test" { @@ -2744,6 +2776,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $uri = Get-WebListenerUrl -Test $method $body = GetTestData -contentType $contentType $command = "Invoke-RestMethod -Uri $uri -Body '$body' -Method $method -ContentType $contentType" + $commandNoContentType = "Invoke-RestMethod -Uri $uri -Body '$body' -Method $method" It "Invoke-RestMethod -Uri $uri -Method $method -ContentType $contentType -Body [body data]" { @@ -2756,6 +2789,27 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { # Validate that the response Content.data field is the same as what we sent. $result.Output.data | Should -Be $body } + + It "Invoke-RestMethod -Uri $uri -Method $method -Body [body data]" { + + $result = ExecuteWebCommand -command $commandNoContentType + + # Validate response + $result.Output.url | Should -Match $uri + + if ($method -eq "POST") + { + $result.Output.headers.'Content-Type' | Should -Match "application/x-www-form-urlencoded" + # Validate that the response Content.form field is the same as what we sent. + [string]$result.Output.form | Should -Be ([string][PSCustomObject]@{$body.Split("=")[0] = [System.Object[]]}) + $result.Output.data | Should -BeNullOrEmpty + } + else + { + # Validate that the response Content.data field is the same as what we sent. + $result.Output.data | Should -Be $body + } + } } } @@ -2845,13 +2899,9 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Output.method | Should -Be "TEST" } - It "Validate Invoke-RestMethod default ContentType for CustomMethod " -TestCases @( - @{method = "POST"} - @{method = "PUT"} - ) { - param($method) - $uri = Get-WebListenerUrl -Test $method - $command = "Invoke-RestMethod -Uri '$uri' -CustomMethod $method -Body 'testparam=testvalue'" + It "Validate Invoke-RestMethod default ContentType for CustomMethod POST" { + $uri = Get-WebListenerUrl -Test 'Post' + $command = "Invoke-RestMethod -Uri '$uri' -CustomMethod POST -Body 'testparam=testvalue'" $result = ExecuteWebCommand -command $command $result.Output.form.testparam | Should -Be "testvalue" $result.Output.Headers.'Content-Type' | Should -Be "application/x-www-form-urlencoded" @@ -3922,6 +3972,19 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Headers.Authorization | Should -Match "^$AuthType " } + + It 'Invoke-RestMethod redacts Authorization header in ErrorRecord' { + $token = ConvertTo-SecureString -AsPlainText 'secret' + try { + Invoke-RestMethod -Authentication Bearer -Token $token -Uri https://localhost:443 + } + catch { + $errorText = Get-Error $_ | Out-String + } + + ($errorText | Select-String 'secret').Matches | Should -BeNullOrEmpty + ($errorText | Select-String '\*cret').Matches | Should -Not -BeNullOrEmpty + } } Context "Invoke-RestMethod -SslProtocol Test" { @@ -4600,3 +4663,34 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support OperationTimeoutSecond RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 2 -WillTimeout -Arguments '-SkipCertificateCheck' } } + + +Describe "Invoke-RestMethod should run in the default synchronization context (threadpool)" -Tag "CI" { + BeforeAll { + $oldProgress = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + $WebListener = Start-WebListener + } + + AfterAll { + $ProgressPreference = $oldProgress + } + + It "Invoke-RestMethod works after constructing a WindowsForm object" -Skip:(!$IsWindows) { + $env:URI_TO_TEST = Get-WebListenerUrl -Test 'Get' + $irmResult = $null + try { + $pwsh = Join-Path $PSHOME "pwsh" + $irmResult = & $pwsh -NoProfile { + Add-Type -AssemblyName System.Windows.Forms + $null = New-Object System.Windows.Forms.Form + Invoke-RestMethod $env:URI_TO_TEST + } + } finally { + $env:URI_TO_TEST = $null + } + + # Simply making it this far is good enough to ensure we didn't hit a deadlock + $irmResult | Should -Not -BeNullOrEmpty + } +} 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/Modules/PowerShellGet/PowerShellGet.Tests.ps1 b/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 index fb5d632765c..1fd935b22dd 100644 --- a/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 +++ b/test/powershell/Modules/PowerShellGet/PowerShellGet.Tests.ps1 @@ -145,15 +145,10 @@ Describe "PowerShellGet - Module tests" -tags "Feature" { It "Should install a module correctly to the required location with default CurrentUser scope" { Install-Module -Name $TestModule -Repository $RepositoryName - $installedModuleInfo = Get-InstalledModule -Name $TestModule - - $installedModuleInfo | Should -Not -BeNullOrEmpty - $installedModuleInfo.Name | Should -Be $TestModule - $installedModuleInfo.InstalledLocation.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase) | Should -BeTrue - - $module = Get-Module $TestModule -ListAvailable + $module = Get-Module -Name $TestModule -ListAvailable + $module | Should -Not -BeNullOrEmpty $module.Name | Should -Be $TestModule - $module.ModuleBase | Should -Be $installedModuleInfo.InstalledLocation + $module.ModuleBase.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase) | Should -BeTrue } AfterAll { 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/Basic/RegisterAssemblyResolverEarly.ps1 b/test/powershell/engine/Basic/RegisterAssemblyResolverEarly.ps1 new file mode 100644 index 00000000000..fbd745b3e1d --- /dev/null +++ b/test/powershell/engine/Basic/RegisterAssemblyResolverEarly.ps1 @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Assembly resolvers should be registered early at startup" -Tags "CI" { + + ## The PKI module requires loading an assembly from GAC, and thus depends on the PowerShell assembly resolver to work. + It "Can load the PKI module with 'pwsh -ExecutionPolicy bypass -NoProfile -c `"Import-Module PKI`"'" -Skip:(!$IsWindows) { + ## Use 'Bypass' execution policy so that it doesn't trigger 'AuthorizationManager' which would trigger 'ClrFacade' initialization. + ## We want to make sure even if 'ClrFacade' is not hit during startup, the resolvers are still registered early enough. + $out = pwsh -ExecutionPolicy bypass -NoProfile -c "Import-Module PKI; Get-Module | % name" + $out | Should -BeExactly "PKI" + } +} diff --git a/test/powershell/engine/Help/HelpSystem.OnlineHelp.Tests.ps1 b/test/powershell/engine/Help/HelpSystem.OnlineHelp.Tests.ps1 index b56effc8626..3e06c51f6cd 100644 --- a/test/powershell/engine/Help/HelpSystem.OnlineHelp.Tests.ps1 +++ b/test/powershell/engine/Help/HelpSystem.OnlineHelp.Tests.ps1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +Import-Module HelpersCommon + Describe 'Online help tests for PowerShell Cmdlets' -Tags "Feature" { # The csv files (V2Cmdlets.csv and V3Cmdlets.csv) contain a list of cmdlets and expected HelpURIs. @@ -61,3 +63,18 @@ Describe 'Get-Help -Online is not supported on Nano Server and IoT' -Tags "CI" { { Get-Help Get-Help -Online } | Should -Throw -ErrorId "InvalidOperation,Microsoft.PowerShell.Commands.GetHelpCommand" } } + +Describe 'Get-Help should throw on network paths' -Tags "CI" { + BeforeAll { + $script:skipTest = -not $IsWindows + } + + It "Get-Help should throw not on " -Skip:$skipTest -TestCases (Get-HelpNetworkTestCases -PositiveCases) { + param( + $Command, + $ExpectedError + ) + + { Get-Help -Name $Command } | Should -Not -Throw + } +} diff --git a/test/powershell/engine/Module/IsolatedModule.Tests.ps1 b/test/powershell/engine/Module/IsolatedModule.Tests.ps1 index 5d1289271de..f9e70044755 100644 --- a/test/powershell/engine/Module/IsolatedModule.Tests.ps1 +++ b/test/powershell/engine/Module/IsolatedModule.Tests.ps1 @@ -3,6 +3,9 @@ Describe "Isolated module scenario - load the whole module in custom ALC" -Tag 'CI' { It "Loading 'IsolatedModule' should work as expected" { + + Set-ItResult -Pending -Because "The test is failing as we cannot depend on Newtonsoft.Json v10.0.0 as it has security vulnerabilities." + ## The 'IsolatedModule' module can be found at '\test\tools\Modules'. ## The module assemblies are created and deployed by '\test\tools\TestAlc'. ## The module defines its own custom ALC and has its module structure organized in a special way that allows the module to be loaded in that custom ALC. 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 8efe61de357..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() @@ -106,7 +109,6 @@ Describe "JEA session Transcript script test" -Tag @("Feature", 'RequireAdminOnW Unregister-PSSessionConfiguration -Name JEA -Force -ErrorAction SilentlyContinue } } - } Describe "JEA session Get-Help test" -Tag @("CI", 'RequireAdminOnWindows') { @@ -155,6 +157,34 @@ Describe "JEA session Get-Help test" -Tag @("CI", 'RequireAdminOnWindows') { Remove-Item $RoleCapDirectory -Recurse -Force -ErrorAction SilentlyContinue } } + + It "Get-Help should throw on " -TestCases (Get-HelpNetworkTestCases) { + param( + $Command, + $ExpectedError + ) + + [string] $RoleCapDirectory = (New-Item -Path "$TestDrive\RoleCapability" -ItemType Directory -Force).FullName + [string] $PSSessionConfigFile = "$RoleCapDirectory\TestConfig.pssc" + $configurationName = 'RestrictedWithNoGetHelpProxy' + try + { + New-PSSessionConfigurationFile -Path $PSSessionConfigFile ` + -SessionType Empty ` + -LanguageMode NoLanguage ` + -ModulesToImport 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Core' ` + -VisibleCmdlets 'Get-command', 'measure-object', 'select-object', 'enter-pssession', 'get-formatdata', 'out-default', 'out-file', 'exit-pssession', 'get-help' + Register-PSSessionConfiguration -Name $configurationName -Path $PSSessionConfigFile -Force -ErrorAction SilentlyContinue + $scriptBlock = [scriptblock]::Create("Get-Help -Name $Command") + {Invoke-Command -ConfigurationName $configurationName -ComputerName localhost -ScriptBlock $scriptBlock -ErrorAction Stop} | + Should -Throw -ErrorId $ExpectedError + } + finally + { + Unregister-PSSessionConfiguration -Name $configurationName -Force -ErrorAction SilentlyContinue + Remove-Item $RoleCapDirectory -Recurse -Force -ErrorAction SilentlyContinue + } + } } Describe "Remoting loopback tests" -Tags @('CI', 'RequireAdminOnWindows') { @@ -358,6 +388,7 @@ Describe "Remoting loopback tests" -Tags @('CI', 'RequireAdminOnWindows') { $session = New-RemoteSession -ConfigurationName $endPoint try { $result = Invoke-Command -Session $session -ScriptBlock { $Host.Version } + Write-Verbose "host version: $result" -Verbose $result | Should -Be $PSVersionTable.PSVersion } finally { diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 index 897d41c251b..dd7cd7a52aa 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 @@ -48,6 +48,7 @@ FunctionsToExport = @( 'Test-PSDefaultParameterValue' 'Push-DefaultParameterValueStack' 'Pop-DefaultParameterValueStack' + 'Get-HelpNetworkTestCases' ) CmdletsToExport= @() diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 index aefd2893a21..50d6a2e668b 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 @@ -533,3 +533,87 @@ function Pop-DefaultParameterValueStack { return $false } } + +function Get-HelpNetworkTestCases +{ + param( + [switch] + $PositiveCases + ) + # .NET doesn't consider these path rooted and we won't go to the network: + # \\? + # \\. + # \?? + + # Command discovery does not follow symlinks to network locations for module qualified paths + $networkBlockedError = "CommandNameNotAllowed,Microsoft.PowerShell.Commands.GetHelpCommand" + $scriptBlockedError = "ScriptsNotAllowed" + + $formats = @( + '//{0}/share/{1}' + '\\{0}\share\{1}' + '//{0}\share/{1}' + 'Microsoft.PowerShell.Core\filesystem:://{0}/share/{1}' + ) + + if (!$PositiveCases) { + $formats += 'filesystem:://{0}/share/{1}' + } + + $moduleQualifiedCommand = 'test.dll\fakecommand' + $lanManFormat = @( + '//;LanmanRedirector/{0}/share/{1}' + ) + + $hosts = @( + 'fakehost' + 'fakehost.pstest' + ) + + $commands = @( + 'test.ps1' + 'test.dll' + $moduleQualifiedCommand + ) + + $variants = @() + $cases = @() + foreach($command in $commands) { + $hostName = $hosts[0] + $format = $formats[0] + $cases += @{ + Command = $format -f $hostName, $command + ExpectedError = $networkBlockedError + } + } + + foreach($hostName in $hosts) { + # chose the format with backslashes(\) to match the host with blackslashes + $format = $formats[1] + $command = $commands[0] + $cases += @{ + Command = $format -f $hostName, $command + ExpectedError = $networkBlockedError + } + } + foreach($format in $formats) { + $hostName = $hosts[0] + $command = $commands[0] + $cases += @{ + Command = $format -f $hostName, $command + ExpectedError = $networkBlockedError + } + } + + foreach($format in $lanManFormat) { + $hostName = $hosts[0] + $command = $moduleQualifiedCommand + $cases += @{ + Command = $format -f $hostName, $command + ExpectedError = $scriptBlockedError + } + } + + return $cases | Sort-Object -Property ExpectedError, Command -Unique +} + diff --git a/test/tools/Modules/PSSysLog/PSSysLog.psm1 b/test/tools/Modules/PSSysLog/PSSysLog.psm1 index 7289a1b8406..4c5296d6c85 100644 --- a/test/tools/Modules/PSSysLog/PSSysLog.psm1 +++ b/test/tools/Modules/PSSysLog/PSSysLog.psm1 @@ -438,7 +438,8 @@ class PSLogItem if($item.LogId -notmatch '^\[com\.microsoft\.powershell') { - Write-Verbose "Skipping logId: $($item.LogId)" -Verbose + # this is really a lot of output, so we'll skip it for now. + # Write-Verbose "Skipping logId: $($item.LogId)" -Verbose $result = $null break } 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/test/tools/Modules/nuget.config b/test/tools/Modules/nuget.config index b0fc73009da..388a65572dd 100644 --- a/test/tools/Modules/nuget.config +++ b/test/tools/Modules/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/test/tools/NamedPipeConnection/.gitignore b/test/tools/NamedPipeConnection/.gitignore new file mode 100644 index 00000000000..89f9ac04aac --- /dev/null +++ b/test/tools/NamedPipeConnection/.gitignore @@ -0,0 +1 @@ +out/ diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index b53f1921a73..22e2a49eb41 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -15,6 +15,19 @@ - + + + + + + + + + + + + + + diff --git a/test/tools/TestAlc/init/Test.Isolated.Init.csproj b/test/tools/TestAlc/init/Test.Isolated.Init.csproj index c1a291fa550..b20dfbe702f 100644 --- a/test/tools/TestAlc/init/Test.Isolated.Init.csproj +++ b/test/tools/TestAlc/init/Test.Isolated.Init.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 85ea03a9c4f..c64c65c3ec7 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -1,6 +1,6 @@ - + @@ -16,8 +16,8 @@ - - + + diff --git a/test/tools/TestAlc/root/Test.Isolated.Root.csproj b/test/tools/TestAlc/root/Test.Isolated.Root.csproj index ab333e0668a..cbe3d6f44e1 100644 --- a/test/tools/TestAlc/root/Test.Isolated.Root.csproj +++ b/test/tools/TestAlc/root/Test.Isolated.Root.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/TestExe/TestExe.cs b/test/tools/TestExe/TestExe.cs index a91e2141b58..39c1d2b2ecb 100644 --- a/test/tools/TestExe/TestExe.cs +++ b/test/tools/TestExe/TestExe.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.IO; using System.Globalization; +using System.Linq; namespace TestExe { @@ -36,6 +37,10 @@ private static int Main(string[] args) case "-stderr": Console.Error.WriteLine(args[1]); break; + case "-stderrandout": + Console.WriteLine(args[1]); + Console.Error.WriteLine(new string(args[1].ToCharArray().Reverse().ToArray())); + break; case "-readbytes": ReadBytes(); break; diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index ed5011fdc19..0917d04b636 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -1,6 +1,6 @@ - + Very tiny windows service to do service testing @@ -10,10 +10,27 @@ true true win-x86;win-x64 + Windows + 8.0 - + + + + + + + + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 3d9d5a4eda6..ae30e42c7cb 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,12 +7,10 @@ - - + + + + + - - - - - diff --git a/test/xUnit/csharp/test_CommandLineParser.cs b/test/xUnit/csharp/test_CommandLineParser.cs index 966834fd2b3..def685c77dc 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..c75159ac279 --- /dev/null +++ b/test/xUnit/csharp/test_RemoteHyperV.cs @@ -0,0 +1,807 @@ +// 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 readonly 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 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)> 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) + { + var itemBytes = item.encoding.GetBytes(item.message); + expectedMessages.Enqueue((message: item.message, bytes: itemBytes, encoding: item.encoding)); + } + + var serverResponseBytes = new Queue<(byte[] bytes, int delayMs)>(); + foreach (var item in serverResponses) + { + (byte[] bytes, int delayMs) queueItem = (item.encoding.GetBytes(item.message), item.delayMs); + serverResponseBytes.Enqueue(queueItem); + } + + _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 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(); + try + { + using (var client = listener.AcceptSocket()) + { + if (sendFirst) + { + // Send the first message from the serverResponses queue + 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); + // 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); + SendResponse(name, client, serverResponses); + } + + 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) + { + _output.WriteLine($"Mock {name} - socket already closed."); + // Socket already closed + } + } + } + + _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(); + } + } + + // 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, 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")] + [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); + DateTimeOffset tokenCreationTime = DateTimeOffset.UtcNow; // Token created 10 minutes ago + var exception = Assert.Throws( + () => 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); + } + + await serverTask; + } + } +} diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index a5ecd4e5296..8a084ecb6d0 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -23,11 +23,13 @@ - + - - + + + + 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/cgmanifest.json b/tools/cgmanifest.json index 8b92f890ec2..a2a43d67905 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -25,8 +25,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "JetBrains.Annotations", - "Version": "2021.2.0" + "Name": "Humanizer.Core", + "Version": "2.14.1" } }, "DevelopmentDependency": false @@ -36,7 +36,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "1.9.0" + "Version": "2.0.2" } }, "DevelopmentDependency": false @@ -46,7 +46,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "3.0.3" + "Version": "5.0.2" } }, "DevelopmentDependency": false @@ -56,7 +56,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonSchema.Net", - "Version": "5.2.6" + "Version": "7.0.4" } }, "DevelopmentDependency": false @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "5.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -106,7 +106,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.Common", - "Version": "4.7.0" + "Version": "4.9.2" } }, "DevelopmentDependency": false @@ -116,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.CSharp", - "Version": "4.7.0" + "Version": "4.9.2" } }, "DevelopmentDependency": false @@ -126,17 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "5.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Management.Infrastructure.Runtime.Unix", - "Version": "2.0.0" + "Version": "8.0.21" } }, "DevelopmentDependency": false @@ -146,21 +136,11 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Management.Infrastructure.Runtime.Win", - "Version": "2.0.0" + "Version": "3.0.0" } }, "DevelopmentDependency": true }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Management.Infrastructure", - "Version": "2.0.0" - } - }, - "DevelopmentDependency": false - }, { "Component": { "Type": "nuget", @@ -171,22 +151,12 @@ }, "DevelopmentDependency": false }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.PowerShell.Native", - "Version": "7.3.2" - } - }, - "DevelopmentDependency": false - }, { "Component": { "Type": "nuget", "Nuget": { "Name": "Microsoft.Security.Extensions", - "Version": "1.2.0" + "Version": "1.4.0" } }, "DevelopmentDependency": false @@ -196,17 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "7.0.0" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "Microsoft.Win32.Registry", - "Version": "4.7.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -216,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -226,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "7.0.5" + "Version": "8.0.21" } }, "DevelopmentDependency": false @@ -236,7 +196,7 @@ "Type": "nuget", "Nuget": { "Name": "Newtonsoft.Json", - "Version": "13.0.3" + "Version": "13.0.4" } }, "DevelopmentDependency": false @@ -246,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -256,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -266,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -276,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.Data.SqlClient.sni", - "Version": "4.7.0" + "Version": "4.4.0" } }, "DevelopmentDependency": false @@ -286,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -296,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -306,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -346,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "StyleCop.Analyzers.Unstable", - "Version": "1.2.0.507" + "Version": "1.2.0.556" } }, "DevelopmentDependency": true @@ -366,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -376,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Collections.Immutable", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -386,7 +346,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -396,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -406,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -416,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -426,7 +386,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -436,7 +396,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.SqlClient", - "Version": "4.8.5" + "Version": "4.9.0" } }, "DevelopmentDependency": false @@ -446,7 +406,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.DiagnosticSource", - "Version": "7.0.2" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -456,7 +416,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "7.0.0" + "Version": "8.0.2" } }, "DevelopmentDependency": false @@ -466,7 +426,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -476,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "7.0.1" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -486,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "7.0.1" + "Version": "8.0.2" } }, "DevelopmentDependency": false @@ -496,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "7.0.1" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -506,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "7.0.0" + "Version": "8.0.21" } }, "DevelopmentDependency": false @@ -516,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Formats.Asn1", - "Version": "7.0.0" + "Version": "8.0.2" } }, "DevelopmentDependency": false @@ -526,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -536,7 +496,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -546,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "7.0.2" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -556,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "7.0.0" + "Version": "8.0.3" } }, "DevelopmentDependency": false @@ -586,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -606,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Metadata", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -616,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "7.0.0" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -636,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.AccessControl", - "Version": "6.0.0" + "Version": "6.0.1" } }, "DevelopmentDependency": false @@ -646,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "7.0.3" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -656,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "7.0.1" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -666,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "7.0.1" + "Version": "8.0.2" } }, "DevelopmentDependency": false @@ -676,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -746,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -756,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "7.0.1" + "Version": "8.0.1" } }, "DevelopmentDependency": false @@ -766,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -776,7 +736,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encoding.CodePages", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -786,17 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Text.Encodings.Web", - "Version": "7.0.0" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Text.Json", - "Version": "6.0.2" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -806,7 +756,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "7.0.1" + "Version": "8.0.0" } }, "DevelopmentDependency": false @@ -816,7 +766,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Web.Services.Description", - "Version": "4.10.0" + "Version": "4.10.3" } }, "DevelopmentDependency": false @@ -826,7 +776,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "7.0.0" + "Version": "8.0.0" } }, "DevelopmentDependency": false diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 060519d30a6..35b32121e9d 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' @@ -17,8 +20,15 @@ if(Test-Path $dotNetPath) # import build into the global scope so it can be used by packaging # argumentList $true says ignore tha we may not be able to build -Import-Module (Join-Path $repoRoot 'build.psm1') -Verbose -Scope Global -ArgumentList $true -Import-Module (Join-Path $repoRoot 'tools\packaging') -Verbose -Scope Global +Write-Verbose "Importing build.psm1" -Verbose +Import-Module (Join-Path $repoRoot 'build.psm1') -Scope Global -ArgumentList $true +$buildCommands = Get-Command -Module build +Write-Verbose "Imported build.psm1 commands: $($buildCommands.Count)" -Verbose + +Write-Verbose "Importing packaging.psm1" -Verbose +Import-Module (Join-Path $repoRoot 'tools\packaging') -Scope Global +$packagingCommands = Get-Command -Module packaging +Write-Verbose "Imported packaging.psm1 commands: $($packagingCommands.Count)" -Verbose # import the windows specific functcion only in Windows PowerShell or on Windows if($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) @@ -91,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 @@ -105,7 +120,7 @@ function Invoke-CIBuild Start-PSBuild -Configuration 'CodeCoverage' -PSModuleRestore -CI -ReleaseTag $releaseTag } - Start-PSBuild -PSModuleRestore -Configuration 'Release' -CI -ReleaseTag $releaseTag + Start-PSBuild -PSModuleRestore -Configuration $Configuration -CI -ReleaseTag $releaseTag -UseNuGetOrg Save-PSOptions $options = (Get-PSOptions) @@ -128,6 +143,10 @@ function Invoke-CIInstall [switch] $SkipUser ) + + # Switch to public sources in CI + Switch-PSNugetConfig -Source Public + # Make sure we have all the tags Sync-PSTags -AddRemoteIfMissing @@ -177,8 +196,6 @@ function Invoke-CIInstall } Set-BuildVariable -Name TestPassed -Value False - Write-Verbose -Verbose -Message "Calling Start-PSBootstrap from Invoke-CIInstall" - Start-PSBootstrap } function Invoke-CIxUnit @@ -211,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 { @@ -220,9 +276,12 @@ function Invoke-CITest [string] $Purpose, [ValidateSet('CI', 'Others')] [string] $TagSet, - [string] $TitlePrefix + [string] $TitlePrefix, + [string] $OutputFormat = "NUnitXml" ) + Write-Verbose -Verbose "CI test: OutputFormat: $OutputFormat" + # Set locale correctly for Linux CIs Set-CorrectLocale @@ -245,7 +304,7 @@ function Invoke-CITest if($IsLinux -or $IsMacOS) { - return Invoke-LinuxTestsCore -Purpose $Purpose -ExcludeTag $ExcludeTag -TagSet $TagSet -TitlePrefix $TitlePrefix + return Invoke-LinuxTestsCore -Purpose $Purpose -ExcludeTag $ExcludeTag -TagSet $TagSet -TitlePrefix $TitlePrefix -OutputFormat $OutputFormat } # CoreCLR @@ -277,12 +336,14 @@ function Invoke-CITest Terse = $true Tag = @() ExcludeTag = $ExcludeTag + 'RequireAdminOnWindows' + OutputFormat = $OutputFormat } $title = "Pester Unelevated - $TagSet" if ($TitlePrefix) { $title = "$TitlePrefix - $title" } + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" Start-PSPester @arguments -Title $title # Fail the build, if tests failed @@ -310,7 +371,10 @@ function Invoke-CITest if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - Start-PSPester @arguments -Title $title + + # We just built the test tools, we don't need to rebuild them + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" + Start-PSPester @arguments -Title $title -SkipTestToolBuild # Fail the build, if tests failed Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile @@ -324,12 +388,15 @@ function Invoke-CITest OutputFile = $testResultsAdminFile Tag = @('RequireAdminOnWindows') ExcludeTag = $ExcludeTag + OutputFormat = $OutputFormat } $title = "Pester Elevated - $TagSet" if ($TitlePrefix) { $title = "$TitlePrefix - $title" } + + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" Start-PSPester @arguments -Title $title # Fail the build, if tests failed @@ -360,7 +427,10 @@ function Invoke-CITest if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - Start-PSPester @arguments -Title $title + + Write-Verbose -Verbose "Starting Pester with output format $($arguments.OutputFormat)" + # We just built the test tools, we don't need to rebuild them + Start-PSPester @arguments -Title $title -SkipTestToolBuild # Fail the build, if tests failed Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile @@ -377,8 +447,6 @@ function New-CodeCoverageAndTestPackage if (Test-DailyBuild) { - Start-PSBootstrap -Verbose - Start-PSBuild -Configuration 'CodeCoverage' -Clean $codeCoverageOutput = Split-Path -Parent (Get-PSOutput) @@ -433,6 +501,18 @@ function Push-Artifact if ($env:TF_BUILD) { # In Azure DevOps Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$Path" + } elseif ($env:GITHUB_WORKFLOW -and $env:RUNNER_WORKSPACE) { + # In GitHub Actions + $destinationPath = Join-Path -Path $env:RUNNER_WORKSPACE -ChildPath $artifactName + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $Path -Destination $destinationPath -Force -Verbose + } else { + Write-Warning "Push-Artifact is not supported in this environment." } } @@ -480,6 +560,9 @@ function Invoke-CIFinish [string[]] $Stage = ('Build','Package') ) + # Switch to public sources in CI + Switch-PSNugetConfig -Source Public + if ($PSEdition -eq 'Core' -and ($IsLinux -or $IsMacOS) -and $Stage -contains 'Build') { return New-LinuxPackage } @@ -537,13 +620,15 @@ function Invoke-CIFinish switch -regex ($Runtime){ default { $runPackageTest = $true - $packageTypes = 'msi', 'nupkg', 'zip', 'zip-pdb', 'msix' + $packageTypes = 'msi', 'zip', 'zip-pdb', 'msix' } 'win-arm.*' { $runPackageTest = $false - $packageTypes = 'zip', 'zip-pdb', 'msix' + $packageTypes = 'msi', 'zip', 'zip-pdb', 'msix' } } + + Install-WixArmZip $packages = Start-PSPackage -Type $packageTypes -ReleaseTag $preReleaseVersion -SkipReleaseChecks -WindowsRuntime $Runtime foreach ($package in $packages) { @@ -574,7 +659,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" @@ -589,14 +674,6 @@ function Invoke-CIFinish throw "Packaging tests failed ($($packagingTestResult.FailedCount) failed/$($packagingTestResult.PassedCount) passed)" } } - - # only publish assembly nuget packages if it is a daily build and tests passed - if (Test-DailyBuild) { - $nugetArtifacts = Get-ChildItem $PSScriptRoot\packaging\nugetOutput -ErrorAction SilentlyContinue -Filter *.nupkg | Select-Object -ExpandProperty FullName - if ($nugetArtifacts) { - $artifacts.AddRange(@($nugetArtifacts)) - } - } } } catch { Get-Error -InputObject $_ @@ -620,6 +697,70 @@ function Invoke-CIFinish } } +function Install-WixArmZip +{ + # cleanup previous install + if((Test-Path "${env:ProgramFiles(x86)}\Arm Support WiX Toolset xcopy")) { + Remove-Item "${env:ProgramFiles(x86)}\Arm Support WiX Toolset xcopy" -Recurse -Force + } + + # This URI is for wix 3.14 which supports generating msi for arm architecures. + $wixUriArmSupport = 'https://aka.ms/ps-wix-3-14-zip' + $zipArmSupport = "$env:TEMP\wixArmSupport.zip" + $targetRoot = "${env:ProgramFiles(x86)}\Arm Support WiX Toolset xcopy" + Invoke-RestMethod -Uri $wixUriArmSupport -OutFile $zipArmSupport + + $binPath = Join-Path -Path $targetRoot -ChildPath 'bin' + Write-Verbose "Expanding $zipArmSupport to $binPath ..." -Verbose + Expand-Archive -Path $zipArmSupport -DestinationPath $binPath -Force + $docExpandPath = Join-Path -Path $binPath -ChildPath 'doc' + $sdkExpandPath = Join-Path -Path $binPath -ChildPath 'sdk' + $docTargetPath = Join-Path -Path $targetRoot -ChildPath 'doc' + $sdkTargetPath = Join-Path -Path $targetRoot -ChildPath 'sdk' + Write-Verbose "Fixing folder structure ..." -Verbose + Move-Item -Path $docExpandPath -Destination $docTargetPath + Move-Item -Path $sdkExpandPath -Destination $sdkTargetPath + Set-Path -Append -Path $binPath + Write-Verbose "Done installing WIX for arm!" +} + +function Set-Path +{ + param + ( + [Parameter(Mandatory)] + [string] + $Path, + + [Parameter(Mandatory)] + [switch] + $Append + ) + + $machinePathString = [System.Environment]::GetEnvironmentVariable('path',[System.EnvironmentVariableTarget]::Machine) + $machinePath = $machinePathString -split ';' + + if($machinePath -inotcontains $path) + { + $newPath = "$machinePathString;$path" + Write-Verbose "Adding $path to path..." -Verbose + [System.Environment]::SetEnvironmentVariable('path',$newPath,[System.EnvironmentVariableTarget]::Machine) + Write-Verbose "Added $path to path." -Verbose + } + else + { + Write-Verbose "$path already in path." -Verbose + } +} + +# 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 { @@ -627,7 +768,7 @@ function Invoke-BootstrapStage Write-Log -Message "Executing ci.psm1 Bootstrap Stage" # Make sure we have all the tags Sync-PSTags -AddRemoteIfMissing - Start-PSBootstrap -Package:$createPackages + Start-PSBootstrap -Scenario Package:$createPackages } # Run pester tests for Linux and macOS @@ -639,7 +780,8 @@ function Invoke-LinuxTestsCore [string] $Purpose = 'All', [string[]] $ExcludeTag = @('Slow', 'Feature', 'Scenario'), [string] $TagSet = 'CI', - [string] $TitlePrefix + [string] $TitlePrefix, + [string] $OutputFormat = "NUnitXml" ) $output = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions)) @@ -652,12 +794,13 @@ function Invoke-LinuxTestsCore $sudoResultsWithExpFeatures = $null $noSudoPesterParam = @{ - 'BinDir' = $output - 'PassThru' = $true - 'Terse' = $true - 'Tag' = @() - 'ExcludeTag' = $testExcludeTag - 'OutputFile' = $testResultsNoSudo + 'BinDir' = $output + 'PassThru' = $true + 'Terse' = $true + 'Tag' = @() + 'ExcludeTag' = $testExcludeTag + 'OutputFile' = $testResultsNoSudo + 'OutputFormat' = $OutputFormat } # Get the experimental feature names and the tests associated with them @@ -695,7 +838,7 @@ function Invoke-LinuxTestsCore if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - $passThruResult = Start-PSPester @noSudoPesterParam -Title $title + $passThruResult = Start-PSPester @noSudoPesterParam -Title $title -SkipTestToolBuild $noSudoResultsWithExpFeatures += $passThruResult } @@ -710,6 +853,7 @@ function Invoke-LinuxTestsCore $sudoPesterParam['ExcludeTag'] = $ExcludeTag $sudoPesterParam['Sudo'] = $true $sudoPesterParam['OutputFile'] = $testResultsSudo + $sudoPesterParam['OutputFormat'] = $OutputFormat $title = "Pester Sudo - $TagSet" if ($TitlePrefix) { @@ -742,7 +886,9 @@ function Invoke-LinuxTestsCore if ($TitlePrefix) { $title = "$TitlePrefix - $title" } - $passThruResult = Start-PSPester @sudoPesterParam -Title $title + + # We just built the test tools for the main test run, we don't need to rebuild them + $passThruResult = Start-PSPester @sudoPesterParam -Title $title -SkipTestToolBuild $sudoResultsWithExpFeatures += $passThruResult } @@ -806,16 +952,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 } } @@ -832,11 +998,17 @@ function Invoke-InitializeContainerStage { # For PRs set the seed to the PR number so that the image is always the same $seed = $env:SYSTEM_PULLREQUEST_PULLREQUESTID + if(!$seed) { # for non-PRs use the integer identifier of the build as the seed. $seed = $fallbackSeed } + # cut down to 32 bits and keep the most varying parts, which are lower bits + if ($seed -ge [Int32]::MaxValue) { + $seed = [int]($seed -band [int]::MaxValue) + } + Write-Verbose "Seed: $seed" -Verbose # Get the latest image matrix JSON for preview @@ -870,3 +1042,226 @@ 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()] + [AllowEmptyCollection()] + [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 + + # 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 = $filesToCheck | 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)" + } +} 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/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 6e372c0ede9..5aeb7de40de 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -26,7 +26,9 @@ $existingRegistrationsJson.Registrations | ForEach-Object { $registration = [Registration]$_ if ($registration.Component) { $name = $registration.Component.Name() - $existingRegistrationTable.Add($name, $registration) + if (!$existingRegistrationTable.ContainsKey($name)) { + $existingRegistrationTable.Add($name, $registration) + } } } @@ -88,6 +90,28 @@ if (!$IsWindows) { Write-Warning "Always using $winDesktopSdk since this is not windows!!!" } +function ConvertTo-SemVer { + param( + [String] $Version + ) + + [System.Management.Automation.SemanticVersion]$desiredVersion = [System.Management.Automation.SemanticVersion]::Empty + + try { + $desiredVersion = $Version + } catch { + <# + Json.More.Net broke the rules and published 2.0.1.2 as 2.0.1. + So, I'm making the logic work for that scenario by + thorwing away any part that doesn't match non-pre-release semver portion + #> + $null = $Version -match '^(\d+\.\d+\.\d+).*' + $desiredVersion = $matches[1] + } + + return $desiredVersion +} + function New-NugetComponent { param( [string]$name, @@ -187,28 +211,34 @@ function Get-CGRegistrations { "alpine-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "linux-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "osx-.*" { $folder = $unixProjectName $target = "$dotnetTargetName|$Runtime" + $neutralTarget = "$dotnetTargetName" } "win-x*" { $sdkToUse = $winDesktopSdk $folder = $windowsProjectName $target = "$dotnetTargetNameWin7|$Runtime" + $neutralTarget = "$dotnetTargetNameWin7" } "win-.*" { $folder = $windowsProjectName $target = "$dotnetTargetNameWin7|$Runtime" + $neutralTarget = "$dotnetTargetNameWin7" } "modules" { $folder = "modules" $actualRuntime = 'linux-x64' $target = "$dotnetTargetName|$actualRuntime" + $neutralTarget = "$dotnetTargetName" } Default { throw "Invalid runtime name: $Runtime" @@ -225,6 +255,7 @@ function Get-CGRegistrations { $null = New-PADrive -Path $PSScriptRoot\..\src\$folder\obj\project.assets.json -Name $folder 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 } catch { Get-ChildItem -Path "${folder}:/targets" | Out-String | Write-Verbose -Verbose throw @@ -234,27 +265,53 @@ function Get-CGRegistrations { Get-PSDrive -Name $folder -ErrorAction Ignore | Remove-PSDrive } + # Name to skip for TPN generation + $skipNames = @( + "Microsoft.PowerShell.Native" + "Microsoft.Management.Infrastructure.Runtime.Unix" + "Microsoft.Management.Infrastructure" + "Microsoft.PowerShell.Commands.Diagnostics" + "Microsoft.PowerShell.Commands.Management" + "Microsoft.PowerShell.Commands.Utility" + "Microsoft.PowerShell.ConsoleHost" + "Microsoft.PowerShell.SDK" + "Microsoft.PowerShell.Security" + "Microsoft.Management.Infrastructure.CimCmdlets" + "Microsoft.WSMan.Management" + "Microsoft.WSMan.Runtime" + "System.Management.Automation" + "Microsoft.PowerShell.GraphicalHost" + "Microsoft.PowerShell.CoreCLR.Eventing" + ) + + Write-Verbose "Found $($targets.Count) targets to process..." -Verbose $targets | ForEach-Object { $target = $_ $parts = ($target -split '\|') $name = $parts[0] - $targetVersion = $parts[1] - $publicVersion = Get-NuGetPublicVersion -Name $name -Version $targetVersion - - # Add the registration to the cgmanifest if the TPN does not contain the name of the target OR - # the exisitng CG contains the registration, because if the existing CG contains the registration, - # that might be the only reason it is in the TPN. - if (!$RegistrationTable.ContainsKey($target)) { - $DevelopmentDependency = $false - if (!$existingRegistrationTable.ContainsKey($name) -or $existingRegistrationTable.$name.Component.Version() -ne $publicVersion) { - $registrationChanged = $true - } - if ($existingRegistrationTable.ContainsKey($name) -and $existingRegistrationTable.$name.DevelopmentDependency) { - $DevelopmentDependency = $true - } - $registration = New-NugetComponent -Name $name -Version $publicVersion -DevelopmentDependency:$DevelopmentDependency - $RegistrationTable.Add($target, $registration) + if ($name -in $skipNames) { + Write-Verbose "Skipping $name..." + + } else { + $targetVersion = $parts[1] + $publicVersion = Get-NuGetPublicVersion -Name $name -Version $targetVersion + + # Add the registration to the cgmanifest if the TPN does not contain the name of the target OR + # the exisitng CG contains the registration, because if the existing CG contains the registration, + # that might be the only reason it is in the TPN. + if (!$RegistrationTable.ContainsKey($target)) { + $DevelopmentDependency = $false + if (!$existingRegistrationTable.ContainsKey($name) -or $existingRegistrationTable.$name.Component.Version() -ne $publicVersion) { + $registrationChanged = $true + } + if ($existingRegistrationTable.ContainsKey($name) -and $existingRegistrationTable.$name.DevelopmentDependency) { + $DevelopmentDependency = $true + } + + $registration = New-NugetComponent -Name $name -Version $publicVersion -DevelopmentDependency:$DevelopmentDependency + $RegistrationTable.Add($target, $registration) + } } } diff --git a/tools/forceCGManifestVersions/cgmanifest.json b/tools/forceCGManifestVersions/cgmanifest.json new file mode 100644 index 00000000000..b4a7b3a7580 --- /dev/null +++ b/tools/forceCGManifestVersions/cgmanifest.json @@ -0,0 +1,34 @@ +{ + "Registrations": [ + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Management.Infrastructure.Runtime.Unix", + "Version": "2.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.PowerShell.Native", + "Version": "7.3.2" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Management.Infrastructure", + "Version": "2.0.0" + } + }, + "DevelopmentDependency": false + }], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" +} diff --git a/tools/install-powershell.ps1 b/tools/install-powershell.ps1 index b6c8f595ccb..2f40e9223c1 100644 --- a/tools/install-powershell.ps1 +++ b/tools/install-powershell.ps1 @@ -268,7 +268,6 @@ try { if ($Daily) { $metadata = Invoke-RestMethod 'https://aka.ms/pwsh-buildinfo-daily' $release = $metadata.ReleaseTag -replace '^v' - $blobName = $metadata.BlobName # Get version from currently installed PowerShell Daily if available. $pwshPath = if ($IsWinEnv) {Join-Path $Destination "pwsh.exe"} else {Join-Path $Destination "pwsh"} @@ -297,8 +296,7 @@ try { throw "The OS architecture is '$architecture'. However, we currently only support daily package for x64." } - - $downloadURL = "https://pscoretestdata.blob.core.windows.net/${blobName}/${packageName}" + $downloadURL = "https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install/$($metadata.ReleaseTag)/$packageName" Write-Verbose "About to download package from '$downloadURL'" -Verbose $packagePath = Join-Path -Path $tempDir -ChildPath $packageName diff --git a/tools/install-powershell.sh b/tools/install-powershell.sh index dbe9206c460..1aed33da16b 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" @@ -121,7 +123,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 diff --git a/tools/metadata.json b/tools/metadata.json index 6d85770f1d9..2be068166e3 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,10 +1,10 @@ { - "StableReleaseTag": "v7.3.6", + "StableReleaseTag": "v7.4.0", "PreviewReleaseTag": "v7.4.0-preview.4", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.3.6", + "ReleaseTag": "v7.4.0", "LTSReleaseTag" : ["v7.2.13"], "NextReleaseTag": "v7.4.0-preview.5", - "LTSRelease": { "Latest": false, "Package": false }, - "StableRelease": { "Latest": false, "Package": false } + "LTSRelease": { "Latest": true, "Package": true }, + "StableRelease": { "Latest": false, "Package": true } } diff --git a/tools/officialRelease/notes.md b/tools/officialRelease/notes.md new file mode 100644 index 00000000000..c0c3c26e863 --- /dev/null +++ b/tools/officialRelease/notes.md @@ -0,0 +1,5 @@ + +|Date |Github User| Notes | +|---------|-----------|-------------------------------| +|20250909 |TravisEz13 | Approved b2d7bf6a7 for release| +|20250906 |TravisEz13 | Approved be24eeff4 for release| diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index f9d673d5482..682c96d9110 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -21,13 +21,6 @@ ], "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, - { - "url": "microsoft-rhel7.3-prod", - "distribution": [ - "trusty" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" - }, { "url": "cbl-mariner-2.0-prod-Microsoft-aarch64", "distribution": [ @@ -60,6 +53,38 @@ "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", "channel": "preview" }, + { + "url": "azurelinux-3.0-prod-ms-oss-aarch64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", + "channel": "stable" + }, + { + "url": "azurelinux-3.0-prod-ms-oss-x86_64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", + "channel": "stable" + }, + { + "url": "azurelinux-3.0-preview-ms-oss-aarch64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", + "channel": "preview" + }, + { + "url": "azurelinux-3.0-preview-ms-oss-x86_64", + "distribution": [ + "bionic" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", + "channel": "preview" + }, { "url": "microsoft-debian-stretch-prod", "distribution": [ @@ -96,18 +121,32 @@ "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" }, { - "url": "microsoft-ubuntu-xenial-prod", - "distribution": [ - "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-ubuntu-noble-prod", + "distribution": [ + "noble" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-ubuntu-xenial-prod", + "distribution": [ + "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" + } ] } diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index 4ec63b872c2..8c941f35d03 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -395,6 +395,10 @@ "Pattern": "hostpolicy.dll", "FileType": "NonProduct" }, + { + "Pattern": "Humanizer.dll", + "FileType": "NonProduct" + }, { "Pattern": "it/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct" @@ -563,10 +567,6 @@ "Pattern": "ja/WindowsFormsIntegration.resources.dll", "FileType": "NonProduct" }, - { - "Pattern": "JetBrains.Annotations.dll", - "FileType": "NonProduct" - }, { "Pattern": "Json.More.dll", "FileType": "NonProduct" @@ -667,10 +667,6 @@ "Pattern": "Markdig.Signed.dll", "FileType": "NonProduct" }, - { - "Pattern": "mi.dll", - "FileType": "NonProduct" - }, { "Pattern": "Microsoft.ApplicationInsights.dll", "FileType": "NonProduct" @@ -787,18 +783,6 @@ "Pattern": "Microsoft.WSMan.Runtime.xml", "FileType": "NonProduct" }, - { - "Pattern": "miutils.dll", - "FileType": "NonProduct" - }, - { - "Pattern": "Modules/*.json", - "FileType": "NonProduct" - }, - { - "Pattern": "Modules/*.sha256", - "FileType": "NonProduct" - }, { "Pattern": "Modules/Microsoft.PowerShell.Archive/*.cat", "FileType": "NonProduct" @@ -807,10 +791,6 @@ "Pattern": "Modules/Microsoft.PowerShell.Archive/*.ps?1", "FileType": "NonProduct" }, - { - "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/_manifest/spdx_2.2/manifest.cat", - "FileType": "NonProduct" - }, { "Pattern": "Modules/Microsoft.PowerShell.PSResourceGet/dependencies/*.dll", "FileType": "NonProduct" @@ -904,7 +884,19 @@ "FileType": "NonProduct" }, { - "Pattern": "Modules\\PSReadLine\\_manifest\\spdx_2.2\\manifest.cat", + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", + "FileType": "NonProduct" + }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.adml", + "FileType": "NonProduct" + }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\PSResourceRepository.admx", + "FileType": "NonProduct" + }, + { + "Pattern": "Modules\\PSReadLine\\.signature.p7s", "FileType": "NonProduct" }, { @@ -3435,6 +3427,10 @@ "Pattern": "Modules/PSDiagnostics/PSDiagnostics.psm1", "FileType": "Product" }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\InstallPSResourceGetPolicyDefinitions.ps1", + "FileType": "Product" + }, { "Pattern": "pwsh.dll", "FileType": "Product" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index a6575088090..8ba2052e81b 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 @@ -50,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", "nupkg", "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", "msi", "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 @@ -61,6 +63,8 @@ function Start-PSPackage { [ValidateScript({$Environment.IsMacOS})] [string] $MacOSRuntime, + [string] $PackageBinPath, + [switch] $Private, [Switch] $Force, @@ -245,7 +249,14 @@ function Start-PSPackage { $Version = (git --git-dir="$RepoRoot/.git" describe) -Replace '^v' } - $Source = Split-Path -Path $Script:Options.Output -Parent + $Source = if ($PackageBinPath) { + $PackageBinPath + } + else { + Split-Path -Path $Script:Options.Output -Parent + } + + Write-Verbose -Verbose "Source: $Source" # Copy the ThirdPartyNotices.txt so it's part of the package Copy-Item "$RepoRoot/ThirdPartyNotices.txt" -Destination $Source -Force @@ -312,18 +323,18 @@ function Start-PSPackage { if (-not $Type) { $Type = if ($Environment.IsLinux) { if ($Environment.LinuxInfo.ID -match "ubuntu") { - "deb", "nupkg", "tar" + "deb", "tar" } elseif ($Environment.IsRedHatFamily) { - "rpm", "nupkg" + "rpm" } elseif ($Environment.IsSUSEFamily) { - "rpm", "nupkg" + "rpm" } else { throw "Building packages for $($Environment.LinuxInfo.PRETTY_NAME) is unsupported!" } } elseif ($Environment.IsMacOS) { - "osxpkg", "nupkg", "tar" + "osxpkg", "tar" } elseif ($Environment.IsWindows) { - "msi", "nupkg", "msix" + "msi", "msix" } Write-Warning "-Type was not specified, continuing with $Type!" } @@ -477,6 +488,12 @@ function Start-PSPackage { $TargetArchitecture = "x86" $r2rArchitecture = "i386" } + elseif ($Runtime -match "-arm64") + { + $TargetArchitecture = "arm64" + $r2rArchitecture = "arm64" + } + Write-Verbose "TargetArchitecture = $TargetArchitecture" -Verbose $Arguments = @{ @@ -500,26 +517,13 @@ function Start-PSPackage { Architecture = $WindowsRuntime.Split('-')[1] Force = $Force Private = $Private + LTS = $LTS } if ($PSCmdlet.ShouldProcess("Create MSIX Package")) { New-MSIXPackage @Arguments } } - 'nupkg' { - $Arguments = @{ - PackageNameSuffix = $NameSuffix - PackageSourcePath = $Source - PackageVersion = $Version - PackageRuntime = $Runtime - PackageConfiguration = $Configuration - Force = $Force - } - - if ($PSCmdlet.ShouldProcess("Create NuPkg Package")) { - New-NugetContentPackage @Arguments - } - } "tar" { $Arguments = @{ PackageSourcePath = $Source @@ -878,7 +882,6 @@ function New-PSBuildZip } } - function Update-PSSignedBuildFolder { param( @@ -886,25 +889,95 @@ 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 + $SignedFilesPathNormalized = (Get-Item $SignedFilesPath).FullName + + Write-Verbose -Verbose "BuildPath = $BuildPathNormalized" + Write-Verbose -Verbose "SignedFilesPath = $signedFilesPath" + # Replace unsigned binaries with signed - $signedFilesFilter = Join-Path -Path $SignedFilesPath -ChildPath '*' - Get-ChildItem -Path $signedFilesFilter -Recurse -File | Select-Object -ExpandProperty FullName | ForEach-Object -Process { - $relativePath = $_.ToLowerInvariant().Replace($SignedFilesPath.ToLowerInvariant(),'') - $destination = Join-Path -Path $BuildPath -ChildPath $relativePath - Write-Log "replacing $destination with $_" - Copy-Item -Path $_ -Destination $destination -Force + $signedFilesFilter = Join-Path -Path $SignedFilesPathNormalized -ChildPath '*' + Write-Verbose -Verbose "signedFilesFilter = $signedFilesFilter" + + $signedFilesList = Get-ChildItem -Path $signedFilesFilter -Recurse -File + foreach ($signedFileObject in $signedFilesList) { + # completely skip replacing pwsh on non-windows systems (there is no .exe extension here) + # and it may not be signed correctly + + # The Shim will not be signed in CI. + + if ($signedFileObject.Name -eq "pwsh" -or ($signedFileObject.Name -eq "Microsoft.PowerShell.GlobalTool.Shim.exe" -and $env:BUILD_REASON -eq 'PullRequest')) { + Write-Verbose -Verbose "Skipping $signedFileObject" + continue + } + + $signedFilePath = $signedFileObject.FullName + Write-Verbose -Verbose "Processing $signedFilePath" + + # Agents seems to be on a case sensitive file system + if ($IsLinux) { + $relativePath = $signedFilePath.Replace($SignedFilesPathNormalized, '') + } else { + $relativePath = $signedFilePath.ToLowerInvariant().Replace($SignedFilesPathNormalized.ToLowerInvariant(), '') + } + + Write-Verbose -Verbose "relativePath = $relativePath" + $destination = (Get-Item (Join-Path -Path $BuildPathNormalized -ChildPath $relativePath)).FullName + Write-Verbose -Verbose "destination = $destination" + Write-Log "replacing $destination with $signedFilePath" + + if (-not (Test-Path $destination)) { + $parent = Split-Path -Path $destination -Parent + $exists = Test-Path -Path $parent + + if ($exists) { + Write-Verbose -Verbose "Parent:" + Get-ChildItem -Path $parent | Select-Object -ExpandProperty FullName | Write-Verbose -Verbose + } + + Write-Error "File not found: $destination, parent - $parent exists: $exists" + } + + # Get-AuthenticodeSignature will only work on Windows + if ($IsWindows) + { + $signature = Get-AuthenticodeSignature -FilePath $signedFilePath + + 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 + { + Write-Verbose -Verbose "Skipping certificate check of $signedFilePath on non-Windows" + } + + Copy-Item -Path $signedFilePath -Destination $destination -Force + } foreach($filter in $RemoveFilter) { - $removePath = Join-Path -Path $BuildPath -ChildPath $filter + $removePath = Join-Path -Path $BuildPathNormalized -ChildPath $filter Remove-Item -Path $removePath -Recurse -Force } } - function Expand-PSSignedBuild { param( @@ -1027,7 +1100,7 @@ function New-UnixPackage { switch ($Type) { "deb" { $packageVersion = Get-LinuxPackageSemanticVersion -Version $Version - if (!$Environment.IsUbuntu -and !$Environment.IsDebian) { + if (!$Environment.IsUbuntu -and !$Environment.IsDebian -and !$Environment.IsMariner) { throw ($ErrorMessage -f "Ubuntu or Debian") } @@ -1124,20 +1197,6 @@ 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")) - } - } - # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1172,41 +1231,150 @@ 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 + } + } + } 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 + } } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - 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 { + # Nothing should reach here + throw "Unknown package type: $Type" } } finally { if ($Environment.IsMacOS) { @@ -1215,13 +1383,17 @@ 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 + 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 } @@ -1234,12 +1406,8 @@ 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 other platforms, the package name from dpkg-deb/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1284,14 +1452,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 ) @@ -1300,64 +1481,83 @@ 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 - $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 + # 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 + 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 + # 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" + 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 @@ -1366,7 +1566,7 @@ Class LinkInfo [string] $Destination } -function Get-FpmArguments +function New-RpmSpec { param( [Parameter(Mandatory,HelpMessage='Package Name')] @@ -1381,11 +1581,6 @@ function Get-FpmArguments [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, @@ -1401,109 +1596,495 @@ function Get-FpmArguments [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 - })] + [Parameter(Mandatory,HelpMessage='Packages required to install this package')] [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 - })] + [Parameter(Mandatory,HelpMessage='Script to run after the package installation.')] [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 - })] + [Parameter(Mandatory,HelpMessage='Script to run after the package removal.')] [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") + # 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 { - $Arguments += @("--license", "MIT License") - } + # For cross-architecture builds, don't specify BuildArch in spec + # The --target option will handle the architecture - if ($Environment.IsMacOS) { - $Arguments += @("--osxpkg-identifier-prefix", "com.microsoft") + # 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" } - foreach ($Dependency in $Dependencies) { - $Arguments += @("--depends", $Dependency) + # Add dependencies + foreach ($dep in $Dependencies) { + $specContent += "Requires: $dep`n" } - if ($AfterInstallScript) { - $Arguments += @("--after-install", $AfterInstallScript) + $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. + # 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" } - if ($AfterRemoveScript) { - $Arguments += @("--after-remove", $AfterRemoveScript) + # 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" } - $Arguments += @( - "$Staging/=$Destination/", - "$ManGzipFile=$ManDestination" + # 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 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 ) - foreach($link in $LinkInfo) - { - $linkArgument = "$($link.Source)=$($link.Destination)" - $Arguments += $linkArgument - } + Write-Log "Creating native DEB package..." - if ($AppsFolder) - { - $Arguments += "$AppsFolder=/" + # 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)] + 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, - return $Arguments + [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-PackageDependencies @@ -1540,7 +2121,7 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + "libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) @@ -1578,25 +2159,25 @@ function Get-PackageDependencies function Test-Dependencies { - foreach ($Dependency in "fpm", "ronn") { - if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -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 -Package")) { - continue - } - else { - $env:PATH = $originalPath - } - } + # RPM packages use rpmbuild directly. + # DEB packages use dpkg-deb directly. + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools. + $Dependencies = @() + + # 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")) { throw "Dependency precheck failed!" } } @@ -1626,7 +2207,7 @@ function New-AfterScripts $packagingStrings.RedHatAfterInstallScript -f "$Link", $Destination | Out-File -FilePath $AfterInstallScript -Encoding ascii $packagingStrings.RedHatAfterRemoveScript -f "$Link", $Destination | Out-File -FilePath $AfterRemoveScript -Encoding ascii } - elseif ($Environment.IsDebianFamily -or $Environment.IsSUSEFamily) { + elseif ($Environment.IsDebianFamily -or $Environment.IsSUSEFamily -or $Distribution -in $script:DebianDistributions) { $AfterInstallScript = (Join-Path $env:HOME $([System.IO.Path]::GetRandomFileName())) $AfterRemoveScript = (Join-Path $env:HOME $([System.IO.Path]::GetRandomFileName())) $packagingStrings.UbuntuAfterInstallScript -f "$Link", $Destination | Out-File -FilePath $AfterInstallScript -Encoding ascii @@ -1656,32 +2237,21 @@ function New-ManGzip ) Write-Log "Creating man gz..." - # run ronn to convert man page to roff - $RonnFile = "$RepoRoot/assets/pwsh.1.ronn" - - if ($IsPreview.IsPresent -or $IsLTS.IsPresent) - { - $prodName = if ($IsLTS) { 'pwsh-lts' } else { 'pwsh-preview' } - $newRonnFile = $RonnFile -replace 'pwsh', $prodName - Copy-Item -Path $RonnFile -Destination $newRonnFile -Force - $RonnFile = $newRonnFile - } - - $RoffFile = $RonnFile -replace "\.ronn$" - # Run ronn on assets file - Write-Log "Creating man gz - running ronn..." - Start-NativeExecution { ronn --roff $RonnFile } + # run roff to convert man page to roff + $RoffFile = "$RepoRoot/assets/manpage/pwsh.1" - if ($IsPreview.IsPresent) - { - Remove-Item $RonnFile + if ($IsPreview.IsPresent -or $IsLTS.IsPresent) { + $prodName = if ($IsLTS) { 'pwsh-lts' } else { 'pwsh-preview' } + $newRoffFile = $RoffFile -replace 'pwsh', $prodName + Copy-Item -Path $RoffFile -Destination $newRoffFile -Force -Verbose + $RoffFile = $newRoffFile } # gzip in assets directory $GzipFile = "$RoffFile.gz" Write-Log "Creating man gz - running gzip..." - Start-NativeExecution { gzip -f $RoffFile } -VerboseOutputOnError + Start-NativeExecution { gzip -kf $RoffFile } -VerboseOutputOnError $ManFile = Join-Path "/usr/local/share/man/man1" (Split-Path -Leaf $GzipFile) @@ -1757,10 +2327,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 @@ -2238,7 +2810,6 @@ function New-ILNugetPackageSource [Parameter(Mandatory = $true)] [string] $RefAssemblyPath, - [Parameter(Mandatory = $true)] [string] $CGManifestPath ) @@ -2295,9 +2866,15 @@ function New-ILNugetPackageSource CreateNugetPlatformFolder -FileName $FileName -Platform 'win' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $WinFxdBinPath + Write-Verbose -Verbose "Done creating Windows runtime assemblies for $FileName" + if ($linuxExceptionList -notcontains $FileName ) { CreateNugetPlatformFolder -FileName $FileName -Platform 'unix' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $LinuxFxdBinPath + Write-Verbose -Verbose "Done creating Linux runtime assemblies for $FileName" + } + else { + Write-Verbose -Verbose "Skipping creating Linux runtime assemblies for $FileName" } if ($FileName -eq "Microsoft.PowerShell.SDK.dll") @@ -2346,6 +2923,14 @@ function New-ILNugetPackageSource Write-Log "Copied the built-in modules to contentFiles for the SDK package" } + else { + Write-Verbose -Verbose "Skipping copying the built-in modules and reference assemblies for $FileName" + } + + if (-not $PSBoundParameters.ContainsKey("CGManifestPath")) { + Write-Verbose -Verbose "CGManifestPath is not provided. Skipping CGManifest creation." + return + } # Create a CGManifest file that lists all dependencies for this package, which is used when creating the SBOM. if (! (Test-Path -Path $CGManifestPath)) { @@ -2968,95 +3553,6 @@ function Publish-NugetToMyGet } } -<# -.SYNOPSIS -The function creates a nuget package for daily feed. - -.DESCRIPTION -The nuget package created is a content package and has all the binaries laid out in a flat structure. -This package is used by install-powershell.ps1 -#> -function New-NugetContentPackage -{ - [CmdletBinding(SupportsShouldProcess=$true)] - param ( - - # Name of the Product - [ValidateNotNullOrEmpty()] - [string] $PackageName = 'powershell', - - # Suffix of the Name - [string] $PackageNameSuffix, - - # Version of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $PackageVersion, - - # Runtime of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $PackageRuntime, - - # Configuration of the Product - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $PackageConfiguration, - - # Source Path to the Product Files - required to package the contents into an Zip - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] $PackageSourcePath, - - [Switch] - $Force - ) - - Write-Log "PackageVersion: $PackageVersion" - $nugetSemanticVersion = Get-NugetSemanticVersion -Version $PackageVersion - Write-Log "nugetSemanticVersion: $nugetSemanticVersion" - - $nugetFolder = New-SubFolder -Path $PSScriptRoot -ChildPath 'nugetOutput' -Clean - - $nuspecPackageName = $PackageName - if ($PackageNameSuffix) - { - $nuspecPackageName += '-' + $PackageNameSuffix - } - - # Setup staging directory so we don't change the original source directory - $stagingRoot = New-SubFolder -Path $PSScriptRoot -ChildPath 'nugetStaging' -Clean - $contentFolder = Join-Path -Path $stagingRoot -ChildPath 'content' - if ($PSCmdlet.ShouldProcess("Create staging folder")) { - New-StagingFolder -StagingPath $contentFolder -PackageSourcePath $PackageSourcePath - } - - $projectFolder = Join-Path $PSScriptRoot 'projects/nuget' - - $arguments = @('pack') - $arguments += @('--output',$nugetFolder) - $arguments += @('--configuration',$PackageConfiguration) - $arguments += "/p:StagingPath=$stagingRoot" - $arguments += "/p:RID=$PackageRuntime" - $arguments += "/p:SemVer=$nugetSemanticVersion" - $arguments += "/p:PackageName=$nuspecPackageName" - $arguments += $projectFolder - - Write-Log "Running dotnet $arguments" - Write-Log "Use -verbose to see output..." - Start-NativeExecution -sb {dotnet $arguments} | ForEach-Object {Write-Verbose $_} - - $nupkgFile = "${nugetFolder}\${nuspecPackageName}-${packageRuntime}.${nugetSemanticVersion}.nupkg" - if (Test-Path $nupkgFile) - { - Get-Item $nupkgFile - } - else - { - throw "Failed to create $nupkgFile" - } -} - function New-SubFolder { [CmdletBinding(SupportsShouldProcess=$true)] @@ -3206,12 +3702,23 @@ function Get-NugetSemanticVersion # Get the paths to various WiX tools function Get-WixPath { - $wixToolsetBinPath = "${env:ProgramFiles(x86)}\WiX Toolset *\bin" + [CmdletBinding()] + param ( + [bool] $IsProductArchitectureArm = $false + ) + + $wixToolsetBinPath = $IsProductArchitectureArm ? "${env:ProgramFiles(x86)}\Arm Support WiX Toolset *\bin" : "${env:ProgramFiles(x86)}\WiX Toolset *\bin" - Write-Verbose "Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath" + Write-Verbose -Verbose "Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath" if (-not (Test-Path $wixToolsetBinPath)) { - 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" + 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. @@ -3235,7 +3742,6 @@ function Get-WixPath WixLightExePath = $wixLightExePath WixInsigniaExePath = $wixInsigniaExePath } - } <# @@ -3287,7 +3793,7 @@ function New-MSIPackage # Architecture to use when creating the MSI [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64")] + [ValidateSet("x86", "x64", "arm64")] [ValidateNotNullOrEmpty()] [string] $ProductTargetArchitecture, @@ -3297,7 +3803,7 @@ function New-MSIPackage [string] $CurrentLocation = (Get-Location) ) - $wixPaths = Get-WixPath + $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") $windowsNames = Get-WindowsNames -ProductName $ProductName -ProductNameSuffix $ProductNameSuffix -ProductVersion $ProductVersion $productSemanticVersionWithName = $windowsNames.ProductSemanticVersionWithName @@ -3335,6 +3841,11 @@ function New-MSIPackage $fileArchitecture = 'x86' $ProductProgFilesDir = "ProgramFilesFolder" } + elseif ($ProductTargetArchitecture -eq "arm64") + { + $fileArchitecture = 'arm64' + $ProductProgFilesDir = "ProgramFiles64Folder" + } $wixFragmentPath = Join-Path $env:Temp "Fragment.wxs" @@ -3449,7 +3960,7 @@ function New-ExePackage { # Architecture to use when creating the MSI [Parameter(Mandatory = $true)] - [ValidateSet("x86", "x64")] + [ValidateSet("x86", "x64", "arm64")] [ValidateNotNullOrEmpty()] [string] $ProductTargetArchitecture, @@ -3498,7 +4009,12 @@ function Expand-ExePackageEngine { # Location to put the expanded engine. [Parameter(Mandatory = $true)] [string] - $EnginePath + $EnginePath, + + [Parameter(Mandatory = $true)] + [ValidateSet("x86", "x64", "arm64")] + [ValidateNotNullOrEmpty()] + [string] $ProductTargetArchitecture ) <# @@ -3506,7 +4022,7 @@ function Expand-ExePackageEngine { insignia -ib TestInstaller.exe -o engine.exe #> - $wixPaths = Get-WixPath + $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") $resolvedExePath = (Resolve-Path -Path $ExePath).ProviderPath $resolvedEnginePath = [System.IO.Path]::GetFullPath($EnginePath) @@ -3528,7 +4044,12 @@ function Compress-ExePackageEngine { # Location of the signed engine [Parameter(Mandatory = $true)] [string] - $EnginePath + $EnginePath, + + [Parameter(Mandatory = $true)] + [ValidateSet("x86", "x64", "arm64")] + [ValidateNotNullOrEmpty()] + [string] $ProductTargetArchitecture ) @@ -3537,7 +4058,7 @@ function Compress-ExePackageEngine { insignia -ab engine.exe TestInstaller.exe -o TestInstaller.exe #> - $wixPaths = Get-WixPath + $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") $resolvedEnginePath = (Resolve-Path -Path $EnginePath).ProviderPath $resolvedExePath = (Resolve-Path -Path $ExePath).ProviderPath @@ -3571,7 +4092,7 @@ function Start-MsiBuild { $outDir = $env:Temp - $wixPaths = Get-WixPath + $wixPaths = Get-WixPath -IsProductArchitectureArm ($ProductTargetArchitecture -eq "arm64") $extensionArgs = @() foreach ($extensionName in $Extension) { @@ -3655,6 +4176,9 @@ function New-MSIXPackage # Produce private package for testing in Store [Switch] $Private, + # Produce LTS package + [Switch] $LTS, + # Force overwrite of package [Switch] $Force, @@ -3699,6 +4223,9 @@ function New-MSIXPackage } elseif ($ProductSemanticVersion.Contains('-')) { $ProductName += 'Preview' $displayName += ' Preview' + } elseif ($LTS) { + $ProductName += '-LTS' + $displayName += '-LTS' } Write-Verbose -Verbose "ProductName: $productName" @@ -3709,6 +4236,10 @@ function New-MSIXPackage $isPreview = Test-IsPreview -Version $ProductSemanticVersion if ($isPreview) { 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 @@ -4119,7 +4650,8 @@ function New-GlobalToolNupkgSource [Parameter(Mandatory)] [string] $WindowsBinPath, [Parameter(Mandatory)] [string] $WindowsDesktopBinPath, [Parameter(Mandatory)] [string] $AlpineBinPath, - [Parameter(Mandatory)] [string] $PackageVersion + [Parameter(Mandatory)] [string] $PackageVersion, + [Parameter()] [switch] $SkipCGManifest ) if ($PackageType -ne "Unified") @@ -4240,20 +4772,22 @@ function New-GlobalToolNupkgSource $toolSettings = $packagingStrings.GlobalToolSettingsFile -f "pwsh.dll" } - "PowerShell.Windows.x64" - { - $PackageName = "PowerShell.Windows.x64" - $RootFolder = New-TempFolder + # Due to needing a signed shim for the global tool, we build the global tool in build instead of packaging. + # keeping the code for reference. + # "PowerShell.Windows.x64" + # { + # $PackageName = "PowerShell.Windows.x64" + # $RootFolder = New-TempFolder - Copy-Item -Path $iconPath -Destination "$RootFolder/$iconFileName" -Verbose + # Copy-Item -Path $iconPath -Destination "$RootFolder/$iconFileName" -Verbose - $ridFolder = New-Item -Path (Join-Path $RootFolder "tools/$script:netCoreRuntime/any") -ItemType Directory + # $ridFolder = New-Item -Path (Join-Path $RootFolder "tools/$script:netCoreRuntime/any") -ItemType Directory - Write-Log "New-GlobalToolNupkgSource: Copying runtime assemblies from $WindowsDesktopBinPath for $PackageType" - Copy-Item "$WindowsDesktopBinPath/*" -Destination $ridFolder -Recurse - Remove-Item -Path $ridFolder/runtimes/win-arm -Recurse -Force - $toolSettings = $packagingStrings.GlobalToolSettingsFile -f "pwsh.dll" - } + # Write-Log "New-GlobalToolNupkgSource: Copying runtime assemblies from $WindowsDesktopBinPath for $PackageType" + # Copy-Item "$WindowsDesktopBinPath/*" -Destination $ridFolder -Recurse + # Remove-Item -Path $ridFolder/runtimes/win-arm -Recurse -Force + # $toolSettings = $packagingStrings.GlobalToolSettingsFile -f "pwsh.dll" + # } "PowerShell.Windows.arm32" { @@ -4283,12 +4817,21 @@ function New-GlobalToolNupkgSource # Set VSTS environment variable for package NuSpec source path. $pkgNuSpecSourcePathVar = "GlobalToolNuSpecSourcePath" Write-Log "New-GlobalToolNupkgSource: Creating NuSpec source path VSTS variable: $pkgNuSpecSourcePathVar" + Write-Verbose -Verbose "sending: [task.setvariable variable=$pkgNuSpecSourcePathVar]$RootFolder" Write-Host "##vso[task.setvariable variable=$pkgNuSpecSourcePathVar]$RootFolder" + $global:GlobalToolNuSpecSourcePath = $RootFolder # Set VSTS environment variable for package Name. $pkgNameVar = "GlobalToolPkgName" Write-Log "New-GlobalToolNupkgSource: Creating current package name variable: $pkgNameVar" + Write-Verbose -Verbose "sending: vso[task.setvariable variable=$pkgNameVar]$PackageName" Write-Host "##vso[task.setvariable variable=$pkgNameVar]$PackageName" + $global:GlobalToolPkgName = $PackageName + + if ($SkipCGManifest.IsPresent) { + Write-Verbose -Verbose "New-GlobalToolNupkgSource: Skipping CGManifest creation." + return + } # Set VSTS environment variable for CGManifest file path. $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools\cgmanifest.json" @@ -4331,7 +4874,7 @@ function New-GlobalToolNupkgFromSource [Parameter(Mandatory)] [string] $PackageNuSpecPath, [Parameter(Mandatory)] [string] $PackageName, [Parameter(Mandatory)] [string] $DestinationPath, - [Parameter(Mandatory)] [string] $CGManifestPath + [Parameter()] [string] $CGManifestPath ) if (! (Test-Path -Path $PackageNuSpecPath)) @@ -4345,6 +4888,12 @@ function New-GlobalToolNupkgFromSource Write-Log "New-GlobalToolNupkgFromSource: Removing GlobalTool NuSpec source directory: $PackageNuSpecPath" Remove-Item -Path $PackageNuSpecPath -Recurse -Force -ErrorAction SilentlyContinue + if (-not ($PSBoundParameters.ContainsKey('CGManifestPath'))) + { + Write-Verbose -Verbose "New-GlobalToolNupkgFromSource: CGManifest file path not provided." + return + } + Write-Log "New-GlobalToolNupkgFromSource: Removing GlobalTool CGManifest source directory: $CGManifestPath" if (! (Test-Path -Path $CGManifestPath)) { diff --git a/tools/packaging/packaging.strings.psd1 b/tools/packaging/packaging.strings.psd1 index 39afb75a96b..adf39654d95 100644 --- a/tools/packaging/packaging.strings.psd1 +++ b/tools/packaging/packaging.strings.psd1 @@ -193,6 +193,29 @@ open {0} +'@ + + WindowsX64GlobalToolNuspec = @' + + + + PowerShelll.Windows.x64 + {0} + Microsoft + Microsoft,PowerShell + https://github.com/PowerShell/PowerShell + Powershell_64.png + false + PowerShell global tool + MIT + PowerShell + en-US + © Microsoft Corporation. All rights reserved. + + + + + '@ GlobalToolSettingsFile = @' diff --git a/tools/packaging/projects/nuget/package.csproj b/tools/packaging/projects/nuget/package.csproj deleted file mode 100644 index 390283c5ef1..00000000000 --- a/tools/packaging/projects/nuget/package.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - NotUsed - PowerShell nuget package with .NET CLI host including everything needed to run it. - powershell.nuspec - runtime=$(RID);version=$(SemVer);PackageName=$(PackageName) - $(StagingPath) - True - net8.0 - - diff --git a/tools/packaging/projects/nuget/powershell.nuspec b/tools/packaging/projects/nuget/powershell.nuspec deleted file mode 100644 index 5c191e911e5..00000000000 --- a/tools/packaging/projects/nuget/powershell.nuspec +++ /dev/null @@ -1,21 +0,0 @@ - - - - $PackageName$-$runtime$ - $version$ - PowerShell for $runtime$ - PowerShell - PowerShell - false - MIT - https://github.com/powershell/powershell - https://github.com/PowerShell/PowerShell/blob/master/assets/Powershell_64.png - This package contains PowerShell for $runtime$. - Copyright (c) Microsoft Corporation. - PowerShell - - - - - - 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 4b756e722aa..910a5ae576b 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 @@ -8,7 +8,7 @@ 11.0 - + diff --git a/tools/performance/README.md b/tools/performance/README.md index c598fca5f28..e0c79659de2 100644 --- a/tools/performance/README.md +++ b/tools/performance/README.md @@ -3,7 +3,7 @@ This directory contains useful scripts and related files for analyzing PowerShell performance. -If you use the [Windows Performance Toolkit](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk), you can use the following to collect data and analyze a trace. +If you use the [Windows Performance Toolkit](https://learn.microsoft.com/windows-hardware/test/wpt/), you can use the following to collect data and analyze a trace. ```PowerShell $PowerShellGitRepo = "D:\PowerShell" diff --git a/tools/releaseBuild/.gitignore b/tools/releaseBuild/.gitignore deleted file mode 100644 index 0ff566888a7..00000000000 --- a/tools/releaseBuild/.gitignore +++ /dev/null @@ -1 +0,0 @@ -PSRelease/ diff --git a/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 b/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 deleted file mode 100644 index 2475dce7d89..00000000000 --- a/tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1 +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# PowerShell Script to build and package PowerShell from specified form and branch -# Script is intented to use in Docker containers -# Ensure PowerShell is available in the provided image - -param ( - [string] $location = "/powershell", - - # Destination location of the package on docker host - [string] $destination = '/mnt', - - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string]$ReleaseTag, - - [switch]$TarX64, - [switch]$TarArm, - [switch]$TarArm64, - [switch]$TarMinSize, - [switch]$FxDependent, - [switch]$Alpine -) - -$releaseTagParam = @{} -if ($ReleaseTag) -{ - $releaseTagParam = @{ 'ReleaseTag' = $ReleaseTag } -} - -#Remove the initial 'v' from the ReleaseTag -$version = $ReleaseTag -replace '^v' -$semVersion = [System.Management.Automation.SemanticVersion] $version - -$metadata = Get-Content "$location/tools/metadata.json" -Raw | ConvertFrom-Json - -$LTS = $metadata.LTSRelease.Package - -Write-Verbose -Verbose -Message "LTS is set to: $LTS" - -function BuildPackages { - param( - [switch] $LTS - ) - - Push-Location - try { - Set-Location $location - Import-Module "$location/build.psm1" - Import-Module "$location/tools/packaging" - - Start-PSBootstrap -Package -NoSudo - - $buildParams = @{ Configuration = 'Release'; PSModuleRestore = $true; Restore = $true } - - if ($FxDependent.IsPresent) { - $projectAssetsZipName = 'linuxFxDependantProjectAssetssymbols.zip' - $buildParams.Add("Runtime", "fxdependent") - } elseif ($Alpine.IsPresent) { - $projectAssetsZipName = 'linuxAlpineProjectAssetssymbols.zip' - $buildParams.Add("Runtime", 'musl-x64') - } else { - # make the artifact name unique - $projectAssetsZipName = "linuxProjectAssets-$((Get-Date).Ticks)-symbols.zip" - } - - Start-PSBuild @buildParams @releaseTagParam - $options = Get-PSOptions - - if ($FxDependent) { - Start-PSPackage -Type 'fxdependent' @releaseTagParam -LTS:$LTS - } elseif ($Alpine) { - Start-PSPackage -Type 'tar-alpine' @releaseTagParam -LTS:$LTS - } else { - Start-PSPackage @releaseTagParam -LTS:$LTS - } - - if ($TarX64) { Start-PSPackage -Type tar @releaseTagParam -LTS:$LTS } - - if ($TarMinSize) { - Write-Verbose -Verbose "---- Min-Size ----" - Write-Verbose -Verbose "options.Output: $($options.Output)" - Write-Verbose -Verbose "options.Top $($options.Top)" - - $binDir = Join-Path -Path $options.Top -ChildPath 'bin' - Write-Verbose -Verbose "Remove $binDir, to get a clean build for min-size package" - Remove-Item -Path $binDir -Recurse -Force - - ## Build 'min-size' and create 'tar.gz' package for it. - $buildParams['ForMinimalSize'] = $true - Start-PSBuild @buildParams @releaseTagParam - Start-PSPackage -Type min-size @releaseTagParam -LTS:$LTS - } - - if ($TarArm) { - ## Build 'linux-arm' and create 'tar.gz' package for it. - ## Note that 'linux-arm' can only be built on Ubuntu environment. - Start-PSBuild -Configuration Release -Restore -Runtime linux-arm -PSModuleRestore @releaseTagParam - Start-PSPackage -Type tar-arm @releaseTagParam -LTS:$LTS - } - - if ($TarArm64) { - Start-PSBuild -Configuration Release -Restore -Runtime linux-arm64 -PSModuleRestore @releaseTagParam - Start-PSPackage -Type tar-arm64 @releaseTagParam -LTS:$LTS - } - } finally { - Pop-Location - } -} - -BuildPackages - -if ($LTS) { - Write-Verbose -Verbose "Packaging LTS" - BuildPackages -LTS -} - -$linuxPackages = Get-ChildItem "$location/powershell*" -Include *.deb,*.rpm,*.tar.gz - -foreach ($linuxPackage in $linuxPackages) -{ - $filePath = $linuxPackage.FullName - Write-Verbose "Copying $filePath to $destination" -Verbose - Copy-Item -Path $filePath -Destination $destination -Force -} - -Write-Verbose "Exporting project.assets files ..." -Verbose - -$projectAssetsCounter = 1 -$projectAssetsFolder = Join-Path -Path $destination -ChildPath 'projectAssets' -$projectAssetsZip = Join-Path -Path $destination -ChildPath $projectAssetsZipName -Get-ChildItem $location\project.assets.json -Recurse | ForEach-Object { - $subfolder = $_.FullName.Replace($location,'') - $subfolder.Replace('project.assets.json','') - $itemDestination = Join-Path -Path $projectAssetsFolder -ChildPath $subfolder - New-Item -Path $itemDestination -ItemType Directory -Force - $file = $_.FullName - Write-Verbose "Copying $file to $itemDestination" -Verbose - Copy-Item -Path $file -Destination "$itemDestination\" -Force - $projectAssetsCounter++ -} - -Compress-Archive -Path $projectAssetsFolder -DestinationPath $projectAssetsZip -Remove-Item -Path $projectAssetsFolder -Recurse -Force -ErrorAction SilentlyContinue diff --git a/tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile b/tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile deleted file mode 100644 index e0a3946c3c4..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -# Docker image file that describes an Centos7 image with PowerShell installed from Microsoft YUM Repo - -FROM mcr.microsoft.com/powershell:centos-7 -LABEL maintainer="PowerShell Team " - -# Install dependencies and clean up -RUN yum install -y \ - glibc \ - libcurl \ - ca-certificates \ - libgcc \ - libicu \ - openssl \ - libstdc++ \ - ncurses-base \ - libunwind \ - uuid \ - zlib \ - which \ - curl \ - git \ - wget \ - && yum clean all - -COPY PowerShellPackage.ps1 / - -ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - -# Use PowerShell as the default shell -ENTRYPOINT [ "pwsh" ] diff --git a/tools/releaseBuild/Images/microsoft_powershell_ubuntu16.04/Dockerfile b/tools/releaseBuild/Images/microsoft_powershell_ubuntu16.04/Dockerfile deleted file mode 100644 index 401af92128a..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_ubuntu16.04/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# Docker image file that describes an Ubuntu16.04 image with PowerShell installed from Microsoft APT Repo - -FROM mcr.microsoft.com/powershell:ubuntu-16.04 -LABEL maintainer="PowerShell Team " - -# Install dependencies and clean up -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - apt-utils \ - libc6 \ - libcurl3 \ - ca-certificates \ - libgcc1 \ - libicu55 \ - libssl1.0.0 \ - libstdc++6 \ - libtinfo5 \ - libunwind8 \ - libuuid1 \ - libcroco3 \ - libgraphite2-3 \ - zlib1g \ - curl \ - git \ - apt-transport-https \ - locales \ - wget \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -COPY PowerShellPackage.ps1 / - -ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - -# Use PowerShell as the default shell -ENTRYPOINT [ "pwsh" ] diff --git a/tools/releaseBuild/Images/microsoft_powershell_ubuntu18.04/Dockerfile b/tools/releaseBuild/Images/microsoft_powershell_ubuntu18.04/Dockerfile deleted file mode 100644 index f8049e9de1c..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_ubuntu18.04/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# Docker image file that describes an Ubuntu16.04 image with PowerShell installed from Microsoft APT Repo - -FROM mcr.microsoft.com/powershell:ubuntu-18.04 -LABEL maintainer="PowerShell Team " - -# Install dependencies and clean up -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-utils \ - apt-utils \ - libc6 \ - libcurl4 \ - ca-certificates \ - libgcc1 \ - libicu60 \ - libssl1.0.0 \ - libstdc++6 \ - libtinfo5 \ - libunwind8 \ - libuuid1 \ - libcroco3 \ - libgraphite2-3 \ - zlib1g \ - curl \ - git \ - apt-transport-https \ - locales \ - wget \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -COPY PowerShellPackage.ps1 / - -ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - -# Use PowerShell as the default shell -ENTRYPOINT [ "pwsh" ] diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/Dockerfile b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/Dockerfile deleted file mode 100644 index ef24e3aa7e9..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -# escape=` -#0.3.6 (no powershell 6) -FROM mcr.microsoft.com/powershell:windowsservercore -LABEL maintainer='PowerShell Team ' -LABEL description="This Dockerfile for Windows Server Core with git installed via chocolatey." - -SHELL ["C:\\Program Files\\PowerShell\\latest\\pwsh.exe", "-command"] -# Install Git, and NuGet -# Git installs to C:\Program Files\Git -# nuget installs to C:\ProgramData\chocolatey\bin\NuGet.exe -COPY dockerInstall.psm1 containerFiles/dockerInstall.psm1 -RUN Import-Module ./containerFiles/dockerInstall.psm1; ` - Install-ChocolateyPackage -PackageName git -Executable git.exe; ` - Install-ChocolateyPackage -PackageName nuget.commandline -Executable nuget.exe -Cleanup - -# Install WIX -ADD https://github.com/wixtoolset/wix3/releases/download/wix311rtm/wix311-binaries.zip /wix.zip -COPY wix.psm1 containerFiles/wix.psm1 -RUN Import-Module ./containerFiles/wix.psm1; ` - Install-WixZip -zipPath \wix.Zip - -# Install makeappx and makepri -ADD https://pscoretestdata.blob.core.windows.net/build-files/makeappx/makeappx.zip?sp=r&st=2019-04-05T18:02:52Z&se=2020-04-06T02:02:52Z&spr=https&sv=2018-03-28&sig=t07uC1K3uFLtINQsmorHobgPh%2B%2BBgjFnmHEJGNZT6Hk%3D&sr=b /makeappx.zip -RUN Expand-Archive /makeappx.zip - -COPY PowerShellPackage.ps1 / - -ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - -ENTRYPOINT ["C:\\Program Files\\PowerShell\\latest\\pwsh.exe", "-command"] diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 deleted file mode 100644 index ae0bc4f2b10..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -[cmdletbinding(DefaultParameterSetName='default')] -# PowerShell Script to clone, build and package PowerShell from specified fork and branch -param ( - [string] $fork = 'powershell', - - [string] $branch = 'master', - - [string] $location = "$PWD\powershell", - - [string] $destination = "$env:WORKSPACE", - - [ValidateSet("win7-x64", "win7-x86", "win-arm", "win-arm64", "fxdependent", "fxdependent-win-desktop")] - [string] $Runtime = 'win7-x64', - - [switch] $ForMinimalSize, - - [switch] $Wait, - - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string] $ReleaseTag, - - [Parameter(Mandatory,ParameterSetName='IncludeSymbols')] - [switch] $Symbols, - - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [ValidatePattern("-signed.zip$")] - [string] $BuildZip, - - [Parameter(Mandatory,ParameterSetName='ComponentRegistration')] - [switch] $ComponentRegistration -) - -$releaseTagParam = @{} -if ($ReleaseTag) -{ - $releaseTagParam = @{ 'ReleaseTag' = $ReleaseTag } -} - -if (-not $env:homedrive) -{ - Write-Verbose "fixing empty home paths..." -Verbose - $profileParts = $env:userprofile -split ':' - $env:homedrive = $profileParts[0]+':' - $env:homepath = $profileParts[1] -} - -if (! (Test-Path $destination)) -{ - Write-Verbose "Creating destination $destination" -Verbose - $null = New-Item -Path $destination -ItemType Directory -} - -Write-Verbose "homedrive : ${env:homedrive}" -Write-Verbose "homepath : ${env:homepath}" - -# Don't use CIM_PhysicalMemory, docker containers may cache old values -$memoryMB = (Get-CimInstance win32_computersystem).TotalPhysicalMemory /1MB -$requiredMemoryMB = 2048 -if ($memoryMB -lt $requiredMemoryMB) -{ - throw "Building powershell requires at least $requiredMemoryMB MiB of memory and only $memoryMB MiB is present." -} -Write-Verbose "Running with $memoryMB MB memory." -Verbose - -try -{ - Set-Location $location - - Import-Module "$location\build.psm1" -Force - Import-Module "$location\tools\packaging" -Force - $env:platform = $null - - Write-Verbose "Sync'ing Tags..." -Verbose - Sync-PSTags -AddRemoteIfMissing - - Write-Verbose "Bootstrapping powershell build..." -Verbose - Start-PSBootstrap -Force -Package -ErrorAction Stop - - if ($PSCmdlet.ParameterSetName -eq 'packageSigned') - { - Write-Verbose "Expanding signed build..." -Verbose - if($Runtime -like 'fxdependent*') - { - Expand-PSSignedBuild -BuildZip $BuildZip -SkipPwshExeCheck - } - else - { - Expand-PSSignedBuild -BuildZip $BuildZip - } - - Remove-Item -Path $BuildZip - } - else - { - Write-Verbose "Starting powershell build for RID: $Runtime and ReleaseTag: $ReleaseTag ..." -Verbose - $buildParams = @{ - ForMinimalSize = $ForMinimalSize - } - - if($Symbols) - { - $buildParams['NoPSModuleRestore'] = $true - } - else - { - $buildParams['PSModuleRestore'] = $true - } - - Start-PSBuild -Clean -Runtime $Runtime -Configuration Release @releaseTagParam @buildParams - } - - if ($ComponentRegistration) - { - Write-Verbose "Exporting project.assets files ..." -Verbose - - $projectAssetsCounter = 1 - $projectAssetsFolder = Join-Path -Path $destination -ChildPath 'projectAssets' - $projectAssetsZip = Join-Path -Path $destination -ChildPath 'windowsProjectAssetssymbols.zip' - Get-ChildItem $location\project.assets.json -Recurse | ForEach-Object { - $subfolder = $_.FullName.Replace($location,'') - $subfolder.Replace('project.assets.json','') - $itemDestination = Join-Path -Path $projectAssetsFolder -ChildPath $subfolder - New-Item -Path $itemDestination -ItemType Directory -Force > $null - $file = $_.FullName - Write-Verbose "Copying $file to $itemDestination" -Verbose - Copy-Item -Path $file -Destination "$itemDestination\" -Force - $projectAssetsCounter++ - } - - Compress-Archive -Path $projectAssetsFolder -DestinationPath $projectAssetsZip - Remove-Item -Path $projectAssetsFolder -Recurse -Force -ErrorAction SilentlyContinue - - return - } - - if ($Runtime -like 'fxdependent*') - { - $pspackageParams = @{'Type' = $Runtime} - } - else - { - ## Set the default package type. - $pspackageParams = @{'Type' = 'msi'; 'WindowsRuntime' = $Runtime} - if ($ForMinimalSize) - { - ## Special case for the minimal size self-contained package. - $pspackageParams['Type'] = 'min-size' - } - } - - if (!$Symbols -and $Runtime -notlike 'fxdependent*' -and !$ForMinimalSize) - { - if ($Runtime -notmatch 'arm') - { - Write-Verbose "Starting powershell packaging(msi)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } - - $pspackageParams['Type']='msix' - Write-Verbose "Starting powershell packaging(msix)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } - - if ($Runtime -like 'fxdependent*' -or $ForMinimalSize) - { - ## Add symbols for just like zip package. - $pspackageParams['IncludeSymbols']=$Symbols - Start-PSPackage @pspackageParams @releaseTagParam - - ## Copy the fxdependent Zip package to destination. - Get-ChildItem $location\PowerShell-*.zip | ForEach-Object { - $file = $_.FullName - Write-Verbose "Copying $file to $destination" -Verbose - Copy-Item -Path $file -Destination "$destination\" -Force - } - } - else - { - if (!$Symbols) { - $pspackageParams['Type'] = 'zip-pdb' - Write-Verbose "Starting powershell symbols packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } - - $pspackageParams['Type']='zip' - $pspackageParams['IncludeSymbols']=$Symbols - Write-Verbose "Starting powershell packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - - Write-Verbose "Exporting packages ..." -Verbose - - Get-ChildItem $location\*.msi,$location\*.zip,$location\*.wixpdb,$location\*.msix,$location\*.exe | ForEach-Object { - $file = $_.FullName - Write-Verbose "Copying $file to $destination" -Verbose - Copy-Item -Path $file -Destination "$destination\" -Force - } - } -} -finally -{ - Write-Verbose "Beginning build clean-up..." -Verbose - if ($Wait) - { - $path = Join-Path $PSScriptRoot -ChildPath 'delete-to-continue.txt' - $null = New-Item -Path $path -ItemType File - Write-Verbose "Computer name: $env:COMPUTERNAME" -Verbose - Write-Verbose "Delete $path to exit." -Verbose - while(Test-Path -LiteralPath $path) - { - Start-Sleep -Seconds 60 - } - } -} diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 deleted file mode 100644 index 311fed7e169..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/dockerInstall.psm1 +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -function Install-ChocolateyPackage -{ - param( - [Parameter(Mandatory=$true)] - [string] - $PackageName, - - [Parameter(Mandatory=$false)] - [string] - $Executable, - - [string[]] - $ArgumentList, - - [switch] - $Cleanup, - - [int] - $ExecutionTimeout = 2700, - - [string] - $Version - ) - - if(-not(Get-Command -Name Choco -ErrorAction SilentlyContinue)) - { - Write-Verbose "Installing Chocolatey provider..." -Verbose - Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression - } - - Write-Verbose "Installing $PackageName..." -Verbose - $extraCommand = @() - if($Version) - { - $extraCommand += '--version', $version - } - choco install -y $PackageName --no-progress --execution-timeout=$ExecutionTimeout $ArgumentList $extraCommands - - if($executable) - { - Write-Verbose "Verifing $Executable is in path..." -Verbose - $exeSource = $null - $exeSource = Get-ChildItem -Path "$env:ProgramFiles\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - if(!$exeSource) - { - Write-Verbose "Falling back to x86 program files..." -Verbose - $exeSource = Get-ChildItem -Path "${env:ProgramFiles(x86)}\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - # Don't search the chocolatey program data until more official locations have been searched - if(!$exeSource) - { - Write-Verbose "Falling back to chocolatey..." -Verbose - $exeSource = Get-ChildItem -Path "$env:ProgramData\chocolatey\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - # all obvious locations are exhausted, use brute force and search from the root of the filesystem - if(!$exeSource) - { - Write-Verbose "Falling back to the root of the drive..." -Verbose - $exeSource = Get-ChildItem -Path "/$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName - } - - if(!$exeSource) - { - throw "$Executable not found" - } - - $exePath = Split-Path -Path $exeSource - Append-Path -path $exePath - } - - if($Cleanup.IsPresent) - { - Remove-Folder -Folder "$env:temp\chocolatey" - } -} - -function Append-Path -{ - param - ( - $path - ) - $machinePathString = [System.Environment]::GetEnvironmentVariable('path',[System.EnvironmentVariableTarget]::Machine) - $machinePath = $machinePathString -split ';' - - if($machinePath -inotcontains $path) - { - $newPath = "$machinePathString;$path" - Write-Verbose "Adding $path to path..." -Verbose - [System.Environment]::SetEnvironmentVariable('path',$newPath,[System.EnvironmentVariableTarget]::Machine) - Write-Verbose "Added $path to path." -Verbose - } - else - { - Write-Verbose "$path already in path." -Verbose - } -} - -function Remove-Folder -{ - param( - [string] - $Folder - ) - - Write-Verbose "Cleaning up $Folder..." -Verbose - $filter = Join-Path -Path $Folder -ChildPath * - [int]$measuredCleanupMB = (Get-ChildItem $filter -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB - Remove-Item -Recurse -Force $filter -ErrorAction SilentlyContinue - Write-Verbose "Cleaned up $measuredCleanupMB MB from $Folder" -Verbose -} diff --git a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/wix.psm1 b/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/wix.psm1 deleted file mode 100644 index e2b446cb7b7..00000000000 --- a/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/wix.psm1 +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -Import-Module "$PSScriptRoot\dockerInstall.psm1" - -# Install using Wix Zip because the MSI requires an older version of dotnet -# which was large and unstable in docker -function Install-WixZip -{ - param($zipPath) - - $targetRoot = "${env:ProgramFiles(x86)}\WiX Toolset xcopy" - $binPath = Join-Path -Path $targetRoot -ChildPath 'bin' - Write-Verbose "Expanding $zipPath to $binPath ..." -Verbose - Expand-Archive -Path $zipPath -DestinationPath $binPath -Force - $docExpandPath = Join-Path -Path $binPath -ChildPath 'doc' - $sdkExpandPath = Join-Path -Path $binPath -ChildPath 'sdk' - $docTargetPath = Join-Path -Path $targetRoot -ChildPath 'doc' - $sdkTargetPath = Join-Path -Path $targetRoot -ChildPath 'sdk' - Write-Verbose "Fixing folder structure ..." -Verbose - Move-Item -Path $docExpandPath -Destination $docTargetPath - Move-Item -Path $sdkExpandPath -Destination $sdkTargetPath - Append-Path -path $binPath - Write-Verbose "Done installing WIX!" -} diff --git a/tools/releaseBuild/README.md b/tools/releaseBuild/README.md deleted file mode 100644 index 9b78e742b5f..00000000000 --- a/tools/releaseBuild/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Azure Dev Ops Release Builds - -## Requirements - -Docker must be installed to run any of the release builds. - -## Running Windows Release Builds Locally - -From PowerShell on Windows, run `.\vstsbuild.ps1 -ReleaseTag -Name `. - -For the package builds, run `.\vstsbuild.ps1 -ReleaseTag -Name -BuildPath -SignedFilesPath ` - -Windows Build Names: - -* `win7-x64-symbols` - * Builds the Windows x64 Zip with symbols -* `win7-x86-symbols` - * Builds the Windows x86 Zip with symbols -* `win7-arm-symbols` - * Builds the Windows ARM Zip with symbols -* `win7-arm64-symbols` - * Builds the Windows ARM64 Zip with symbols -* `win7-fxdependent-symbols` - * Builds the Windows FxDependent Zip with symbols -* `win7-x64-package` - * Builds the Windows x64 packages -* `win7-x86-package` - * Builds the Windows x86 packages -* `win7-arm-package` - * Builds the Windows ARM packages -* `win7-arm64-package` - * Builds the Windows ARM64 packages -* `win7-fxdependent-package` - * Builds the Windows FxDependent packages - -## Running Linux Release Builds Locally - -From PowerShell on Linux or macOS, run `.\vstsbuild.ps1 -ReleaseTag -Name `. - -Linux Build Names: - -* `deb` - * Builds the Debian Packages, ARM32 and ARM64. -* `alpine` - * Builds the Alpine Package -* `rpm` - * Builds the RedHat variant Package - -## Azure Dev Ops Build - -The release build is fairly complicated. The definition is at `./azureDevOps/releaseBuild.yml`. - -Here is a diagram of the build: - -[![Release Build diagram](https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/releaseBuild/azureDevOps/diagram.svg?sanitize=true)](https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/releaseBuild/azureDevOps/diagram.svg?sanitize=true) diff --git a/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml b/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml deleted file mode 100644 index ff8dbd6d720..00000000000 --- a/tools/releaseBuild/azureDevOps/AzArtifactFeed/PSGalleryToAzArtifacts.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Sync packages from PSGallery to Azure DevOps Artifacts feed - -resources: -- repo: self - clean: true - -pool: - name: 1es - demands: - - ImageOverride -equals PSMMS2019-Minimal - -steps: - - pwsh: | - $minVer = [version]"2.2.3" - $curVer = Get-Module PowerShellGet -ListAvailable | Select-Object -First 1 | ForEach-Object Version - if (-not $curVer -or $curVer -lt $minVer) { - Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -Force - } - displayName: Update PSGet and PackageManagement - condition: succeededOrFailed() - - - pwsh: | - Import-Module -Force "$(Build.SourcesDirectory)/tools/releaseBuild/azureDevOps/AzArtifactFeed/SyncGalleryToAzArtifacts.psm1" - SyncGalleryToAzArtifacts -AzDevOpsFeedUserName $(AzDevOpsFeedUserName) -AzDevOpsPAT $(AzDevOpsFeedPAT2) -Destination $(Build.ArtifactStagingDirectory) - displayName: Download packages from PSGallery that need to be updated - condition: succeededOrFailed() - - - pwsh: | - Write-Verbose -Verbose "Packages to upload" - if(Test-Path $(Build.ArtifactStagingDirectory)) { Get-ChildItem "$(Build.ArtifactStagingDirectory)/*.nupkg" | ForEach-Object { $_.FullName }} - displayName: List packages to upload - condition: succeededOrFailed() - - - task: NuGetCommand@2 - displayName: 'NuGet push' - inputs: - command: push - publishVstsFeed: 'pscore-release' - publishFeedCredentials: 'AzArtifactsFeed' diff --git a/tools/releaseBuild/azureDevOps/AzArtifactFeed/SyncGalleryToAzArtifacts.psm1 b/tools/releaseBuild/azureDevOps/AzArtifactFeed/SyncGalleryToAzArtifacts.psm1 deleted file mode 100644 index d0aeac9da54..00000000000 --- a/tools/releaseBuild/azureDevOps/AzArtifactFeed/SyncGalleryToAzArtifacts.psm1 +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -<# -.SYNOPSIS -Downloads to packages from PowerShell Gallery which are missing from the Azure DevOps Artifacts feed. - -.PARAMETER AzureDevOpsPAT -PAT for the username used for authenticating to the Azure DevOps Artifacts feed. - -.PARAMETER Destination -Path to the folder where the packages should be stored for uploading to Azure DevOps Artifacts feed. - -#> -function SyncGalleryToAzArtifacts { - param( - [Parameter(Mandatory = $true)] [string] $AzDevOpsFeedUserName, - [Parameter(Mandatory = $true)] [string] $AzDevOpsPAT, - [Parameter(Mandatory = $true)] [string] $Destination - ) - - $csproj = [xml] (Get-Content 'src/Modules/PSGalleryModules.csproj') - $packages = @($csproj.Project.ItemGroup.PackageReference | ForEach-Object { [ordered] @{Name = $_.Include; Version = $_.Version }}) - - $galleryPackages = @() - $azArtifactsPackages = @() - $modulesToUpdate = @() - - $galleryUrl = 'https://www.powershellgallery.com/api/v2/' - $azArtifactsUrl = 'https://mscodehub.pkgs.visualstudio.com/_packaging/pscore-release/nuget/v2' - - $azDevOpsCreds = [pscredential]::new($AzDevOpsFeedUserName, (ConvertTo-SecureString -String $AzDevOpsPAT -AsPlainText -Force)) - - foreach ($package in $packages) { - try { - # Get module from gallery - $foundPackageOnGallery = Find-Package -ProviderName NuGet -Source $galleryUrl -AllVersions -Name $package.Name -Force -AllowPreReleaseVersion | SortPackage | Select-Object -First 1 - Write-Verbose -Verbose "Found module $($package.Name) - $($foundPackageOnGallery.Version) in gallery" - $galleryPackages += $foundPackageOnGallery - } catch { - if ($_.FullyQualifiedErrorId -eq 'NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.FindPackage') { - # Log and ignore failure is required version is not found on gallery. - Write-Warning "Module not found on gallery $($package.Name) - $($package.Version)" - } - else { - Write-Error $_ - } - } - - try { - # Get module from Az Artifacts - # There seems to be a bug in the feed with RequiredVersion matching. Adding workaround with post filtering. - # Issue: https://github.com/OneGet/oneget/issues/397 - $foundPackageOnAz = Find-Package -ProviderName NuGet -Source $azArtifactsUrl -AllVersions -Name $package.Name -Force -Credential $azDevOpsCreds -AllowPreReleaseVersion | SortPackage | Select-Object -First 1 - Write-Verbose -Verbose "Found module $($package.Name) - $($foundPackageOnAz.Version) in azArtifacts" - $azArtifactsPackages += $foundPackageOnAz - } catch { - if ($_.FullyQualifiedErrorId -eq 'NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.FindPackage') { - # Log and add the module to update list. - Write-Verbose -Verbose "Az Artifacts Module needs update to - $($package.Name) - $($package.Version)" - $modulesToUpdate += $package - } - else { - Write-Error $_ - } - } - - # Check if Az package version is less that gallery version - $pkgOnAzVersion = [semver]::new($foundPackageOnAz.Version) - $pkgOnGalleryVersion = [semver]::new($foundPackageOnGallery.Version) - - if ($pkgOnAzVersion -lt $pkgOnGalleryVersion) { - Write-Verbose -Verbose "Module needs to be updated $($package.Name) - $($foundPackageOnGallery.Version)" - $modulesToUpdate += $foundPackageOnGallery - } elseif ($pkgOnGalleryVersion -lt $pkgOnAzVersion) { - Write-Warning "Newer version found on Az Artifacts - $($foundPackageOnAz.Name) - $($foundPackageOnAz.Version)" - } else { - Write-Verbose -Verbose "Module is in sync - $($package.Name)" - } - } - - "`nGallery Packages:" - $galleryPackages - - "`nAz Artifacts Packages:`n" - $azArtifactsPackages - - "`nModules to update:`n" - $modulesToUpdate - - foreach ($package in $modulesToUpdate) { - Write-Verbose -Verbose "Saving package $($package.Name) - $($package.Version)" - Save-Package -Provider NuGet -Source $galleryUrl -Name $package.Name -RequiredVersion $package.Version -Path $Destination - } - - if ($modulesToUpdate.Length -gt 0) - { - # Remove dependent packages downloaded by Save-Package if there are already present in AzArtifacts feed. - try { - $null = Register-PackageSource -Name local -Location $Destination -ProviderName NuGet -Force - $packageNamesToKeep = @() - $savedPackages = Find-Package -Source local -AllVersions -AllowPreReleaseVersion - - Write-Verbose -Verbose "Saved packages:" - $savedPackages | Out-String | Write-Verbose -Verbose - - foreach($package in $savedPackages) { - $pkgVersion = NormalizeVersion -version $package.Version - $foundMatch = $azArtifactsPackages | Where-Object { $_.Name -eq $package.Name -and (NormalizeVersion -version $_.Version) -eq $pkgVersion } - - if(-not $foundMatch) { - Write-Verbose "Keeping package $($package.PackageFileName)" -Verbose - $packageNamesToKeep += "{0}*.nupkg" -f $package.Name - } - } - - if ($packageNamesToKeep.Length -gt 0) { - ## Removing only if we do have some packages to keep, - ## otherwise the '$Destination' folder will be removed. - Remove-Item -Path $Destination -Exclude $packageNamesToKeep -Recurse -Force -Verbose - } - - Write-Verbose -Verbose "Packages kept for upload" - Get-ChildItem $Destination | Out-String | Write-Verbose -Verbose - } - finally { - Unregister-PackageSource -Name local -Force -ErrorAction SilentlyContinue - } - } -} - -Function SortPackage { - param( - [Parameter(ValueFromPipeline = $true)] - [Microsoft.PackageManagement.Packaging.SoftwareIdentity[]] - $packages - ) - - Begin { - $allPackages = @() - } - - Process { - $allPackages += $packages - } - - End { - $versions = $allPackages.Version | - ForEach-Object { ($_ -split '-')[0] } | - Select-Object -Unique | - Sort-Object -Descending -Property Version - - foreach ($version in $versions) { - $exactMatch = $allPackages | Where-Object { - Write-Verbose "testing $($_.version) -eq $version" - $_.version -eq $version - } - - if ($exactMatch) { - Write-Output $exactMatch - } - - $allPackages | Where-Object { - $_.version -like "${version}-*" - } | Sort-Object -Descending -Property Version | Write-Output - } - } -} - - -function NormalizeVersion { - param ([string] $version) - - $sVer = if ($version -match "(\d+.\d+.\d+).0") { - $Matches[1] - } elseif ($version -match "^\d+.\d+$") { - # Two digit versions are stored as three digit versions - "$version.0" - } else { - $version - } - - $sVer -} - -Export-ModuleMember -Function 'SyncGalleryToAzArtifacts', 'SortPackage' diff --git a/tools/releaseBuild/azureDevOps/compliance.yml b/tools/releaseBuild/azureDevOps/compliance.yml deleted file mode 100644 index 57c29194de6..00000000000 --- a/tools/releaseBuild/azureDevOps/compliance.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Compliance-$(Build.BuildId) - -trigger: none -pr: none - -schedules: - # Chrontab format, see https://en.wikipedia.org/wiki/Cron - # this is in UTC - - cron: '0 13 * * *' - branches: - include: - - master - -resources: - repositories: - - repository: ComplianceRepo - type: github - endpoint: ComplianceGHRepo - name: PowerShell/compliance - ref: master - -variables: - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - # Defines the variables AzureFileCopySubscription, StorageAccount, StorageAccountKey, StorageResourceGroup, StorageSubscriptionName - - group: 'Azure Blob variable group' - # Defines the variables CgPat, CgOrganization, and CgProject - - group: 'ComponentGovernance' - - group: 'PoolNames' - -stages: - - stage: compliance - displayName: 'Compliance' - dependsOn: [] - jobs: - - template: templates/compliance/compliance.yml - parameters: - parentJobs: [] - - stage: APIScan - displayName: 'ApiScan' - dependsOn: [] - jobs: - - template: templates/compliance/apiscan.yml - parameters: - parentJobs: [] - - stage: notice - displayName: Generate Notice File - dependsOn: [] - jobs: - - template: templates/compliance/generateNotice.yml - parameters: - parentJobs: [] diff --git a/tools/releaseBuild/azureDevOps/diagram.puml b/tools/releaseBuild/azureDevOps/diagram.puml deleted file mode 100644 index ade53b11b9c..00000000000 --- a/tools/releaseBuild/azureDevOps/diagram.puml +++ /dev/null @@ -1,107 +0,0 @@ -@startuml - -folder "Linux Builds" as LinuxBuilds { - ' Define the build tasks as business processes - agent "DEB" as BuildDEB - agent "RPM" as BuildRPM - agent "Alpine" as BuildAlpine - agent "Linux-FxDependent" as BuildLinuxFx - -} - -agent "macOS Build" as BuildMac - -agent "Upload build metadata" as BuildMetadata - -folder "Windows Builds" as WinBuilds { - agent "x64" as BuildWinX64 - agent "x86" as BuildWinX86 - agent "arm32" as BuildWinArm32 - agent "arm64" as BuildWinArm64 - agent "FxDependent" as BuildWinFx -} - -agent "ComponentRegistration" as BuildCG - -folder "Linux Package Scanning and Upload" as PkgScanUploadLinux { - agent "DEB" as UploadDEB - agent "RPM" as UploadRPM - agent "Alpine" as UploadAlpine - agent "Linux-FxDependent" as UploadLinuxFx -} - -folder "Package Signing and Upload" as PkgSignUpload { - agent "macOS" as SignMac - - agent "Windows" as SignWin -} - -folder "Build Test Artifacts" as TestArtifacts { - agent "Windows" as WinTest - agent "Linux" as LinuxTest - agent "Linux-ARM" as LinuxArmTest - agent "Linux-ARM64" as LinuxArm64Test -} - -agent "Compliance" as Compliance - - -agent "Create SDK and Global Tool and Upload" as BuildNuGet - - -' Define finishing the build as a goal filled -control "Finish" as Finish -control "Start" as Start - -' map the various Upload task dependencies -BuildDEB -down-> UploadDEB -BuildRPM -down-> UploadRPM -BuildLinuxFx -down-> UploadLinuxFx -BuildAlpine -down-> UploadAlpine - -' map all of the SignMac task dependencies -BuildMac -down-> SignMac - -' map all of the SignWin task dependencies -WinBuilds -down-> SignWin -'BuildWinX64 -down-> SignWin -'BuildWinX86 -down-> SignWin -'BuildWinArm32 -down-> SignWin -'BuildWinArm64 -down-> SignWin -'BuildWinFx -down-> SignWin - -' map all of the Compliance task dependencies -BuildWinX86 -down-> Compliance -BuildWinX64 -down-> Compliance -BuildWinFx -down-> Compliance - -PkgSignUpload -down-> BuildNuGet -LinuxBuilds -down-> BuildNuGet - -' map all leafs to finish -Compliance ~~ Finish -UploadAlpine ~~ Finish -UploadDEB ~~ Finish -UploadRPM ~~ Finish -UploadLinuxFx ~~ Finish -SignMac ~~ Finish -BuildCG ~~ Finish -BuildNuGet ~~ Finish -TestArtifacts ~~ Finish -BuildMetadata ~~ Finish - -Start ~~ BuildDEB -Start ~~ BuildRPM -Start ~~ BuildAlpine -Start ~~ BuildLinuxFx -Start ~~ BuildMac -Start ~~ BuildWinX64 -Start ~~ BuildWinX86 -Start ~~ BuildWinFx -Start ~~ BuildWinArm32 -Start ~~ BuildWinArm64 -Start ~~ BuildCG -Start ~~ TestArtifacts -Start ~~ BuildMetadata - -@enduml diff --git a/tools/releaseBuild/azureDevOps/diagram.svg b/tools/releaseBuild/azureDevOps/diagram.svg deleted file mode 100644 index 024128bf988..00000000000 --- a/tools/releaseBuild/azureDevOps/diagram.svg +++ /dev/null @@ -1,108 +0,0 @@ -Linux BuildsWindows BuildsLinux Package Scanning and UploadPackage Signing and UploadBuild Test ArtifactsDEBRPMAlpineLinux-FxDependentx64x86arm32arm64FxDependentDEBRPMAlpineLinux-FxDependentmacOSWindowsWindowsLinuxLinux-ARMLinux-ARM64macOS BuildUpload build metadataComponentRegistrationComplianceCreate SDK and Global Tool and UploadFinishStart \ No newline at end of file diff --git a/tools/releaseBuild/azureDevOps/releaseBuild.yml b/tools/releaseBuild/azureDevOps/releaseBuild.yml deleted file mode 100644 index dd576e1860d..00000000000 --- a/tools/releaseBuild/azureDevOps/releaseBuild.yml +++ /dev/null @@ -1,373 +0,0 @@ -name: UnifiedPackageBuild-$(Build.BuildId) -trigger: - branches: - include: - - master - - release* -pr: - branches: - include: - - master - - release* - -parameters: - - name: ForceAzureBlobDelete - displayName: Delete Azure Blob - type: string - values: - - true - - false - default: false - -resources: - repositories: - - repository: ComplianceRepo - type: github - endpoint: ComplianceGHRepo - name: PowerShell/compliance - ref: master - -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 - # Prevents auto-injection of nuget-security-analysis@0 - - name: skipNugetSecurityAnalysis - value: true - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - name: ForceAzureBlobDelete - value: ${{ parameters.ForceAzureBlobDelete }} - - name: Github_Build_Repository_Uri - value: https://github.com/powershell/powershell - - name: SBOMGenerator_Formats - value: spdx:2.2 - - name: BUILDSECMON_OPT_IN - value: true - - group: PoolNames - -stages: - - stage: prep - jobs: - - template: templates/checkAzureContainer.yml - - - stage: macos - dependsOn: ['prep'] - jobs: - - template: templates/mac.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac.yml - parameters: - buildArchitecture: arm64 - - - stage: linux - dependsOn: ['prep'] - jobs: - - template: templates/linux.yml - parameters: - buildName: deb - - - template: templates/linux.yml - parameters: - buildName: rpm - parentJob: build_deb - - - template: templates/linux.yml - parameters: - buildName: fxdependent - parentJob: build_deb - - - template: templates/linux.yml - parameters: - buildName: alpine - - - stage: windows - dependsOn: ['prep'] - jobs: - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x64 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x64 - BuildConfiguration: minSize - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: x86 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: arm64 - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: fxdependent - - - template: templates/windows-hosted-build.yml - parameters: - Architecture: fxdependentWinDesktop - - - stage: SignFiles - displayName: Sign files - dependsOn: ['windows', 'linux', 'macos'] - jobs: - - template: templates/mac-file-signing.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-file-signing.yml - parameters: - buildArchitecture: arm64 - - - job: SignFilesWinLinux - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - displayName: Sign files - - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - strategy: - matrix: - linux-x64: - runtime: linux-x64 - unsignedBuildArtifactContainer: pwshLinuxBuild.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuild.tar.gz - signedArtifactContainer: authenticode-signed - linux-x64-Alpine: - runtime: linux-x64-Alpine - unsignedBuildArtifactContainer: pwshLinuxBuildAlpine.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuildAlpine.tar.gz - signedArtifactContainer: authenticode-signed - linux-x64-Alpine-Fxdependent: - runtime: linux-x64-Alpine-Fxdependent - unsignedBuildArtifactContainer: pwshAlpineFxdBuildAmd64.tar.gz - unsignedBuildArtifactName: pwshAlpineFxdBuildAmd64.tar.gz - signedBuildArtifactName: pwshAlpineFxdBuildAmd64.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm32: - runtime: linux-arm32 - unsignedBuildArtifactContainer: pwshLinuxBuildArm32.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildArm32.tar.gz - signedBuildArtifactName: pwshLinuxBuildArm32.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm64: - runtime: linux-arm64 - unsignedBuildArtifactContainer: pwshLinuxBuildArm64.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildArm64.tar.gz - signedBuildArtifactName: pwshLinuxBuildArm64.tar.gz - signedArtifactContainer: authenticode-signed - linux-fxd: - runtime: linux-fxd - unsignedBuildArtifactContainer: pwshLinuxBuildFxdependent.tar.gz - unsignedBuildArtifactName: pwshLinuxBuild.tar.gz - signedBuildArtifactName: pwshLinuxBuildFxdependent.tar.gz - signedArtifactContainer: authenticode-signed - linux-mariner: - runtime: linux-mariner - unsignedBuildArtifactContainer: pwshMarinerBuildAmd64.tar.gz - unsignedBuildArtifactName: pwshMarinerBuildAmd64.tar.gz - signedBuildArtifactName: pwshMarinerBuildAmd64.tar.gz - signedArtifactContainer: authenticode-signed - linux-arm64-mariner: - runtime: linux-arm64-mariner - unsignedBuildArtifactContainer: pwshMarinerBuildArm64.tar.gz - unsignedBuildArtifactName: pwshMarinerBuildArm64.tar.gz - signedBuildArtifactName: pwshMarinerBuildArm64.tar.gz - signedArtifactContainer: authenticode-signed - linux-minsize: - runtime: linux-minsize - unsignedBuildArtifactContainer: pwshLinuxBuildMinSize.tar.gz - unsignedBuildArtifactName: pwshLinuxBuildMinSize.tar.gz - signedBuildArtifactName: pwshLinuxBuildMinSize.tar.gz - signedArtifactContainer: authenticode-signed - win-x64: - runtime: win-x64 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x64.zip' - signedBuildArtifactName: '-symbols-win-x64-signed.zip' - signedArtifactContainer: results - win-x86: - runtime: win-x86 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x86.zip' - signedBuildArtifactName: '-symbols-win-x86-signed.zip' - signedArtifactContainer: results - win-arm64: - runtime: win-arm64 - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-arm64.zip' - signedBuildArtifactName: '-symbols-win-arm64-signed.zip' - signedArtifactContainer: results - win-x64-gc: - runtime: win-x64-gc - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-x64-gc.zip' - signedBuildArtifactName: '-symbols-win-x64-gc-signed.zip' - signedArtifactContainer: results - win-fxdependent: - runtime: win-fxdependent - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-fxdependent.zip' - signedBuildArtifactName: '-symbols-win-fxdependent-signed.zip' - signedArtifactContainer: results - win-fxdependentWinDesktop: - runtime: win-fxdependentWinDesktop - unsignedBuildArtifactContainer: results - unsignedBuildArtifactName: '**/*-symbols-win-fxdependentWinDesktop.zip' - signedBuildArtifactName: '-symbols-win-fxdependentWinDesktop-signed.zip' - signedArtifactContainer: results - steps: - - template: templates/sign-build-file.yml - - - stage: mac_packaging - displayName: macOS packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/mac-package-build.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-package-build.yml - parameters: - buildArchitecture: arm64 - - - stage: linux_packaging - displayName: Linux Packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/linux-packaging.yml - parameters: - buildName: deb - - - template: templates/linux-packaging.yml - parameters: - buildName: rpm - uploadDisplayName: Upload and Sign - - - template: templates/linux-packaging.yml - parameters: - buildName: alpine - - - template: templates/linux-packaging.yml - parameters: - buildName: fxdependent - - - stage: win_packaging - displayName: Windows Packaging - dependsOn: ['SignFiles'] - jobs: - - template: templates/windows-packaging.yml - parameters: - Architecture: x64 - parentJob: build_windows_x64_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: x64 - BuildConfiguration: minSize - parentJob: build_windows_x64_minSize - - - template: templates/windows-packaging.yml - parameters: - Architecture: x86 - parentJob: build_windows_x86_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: arm64 - parentJob: build_windows_arm64_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: fxdependent - parentJob: build_windows_fxdependent_release - - - template: templates/windows-packaging.yml - parameters: - Architecture: fxdependentWinDesktop - parentJob: build_windows_fxdependentWinDesktop_release - - - stage: package_signing - displayName: Package Signing - dependsOn: ['mac_packaging', 'linux_packaging', 'win_packaging'] - jobs: - - template: templates/windows-package-signing.yml - - - template: templates/mac-package-signing.yml - parameters: - buildArchitecture: x64 - - - template: templates/mac-package-signing.yml - parameters: - buildArchitecture: arm64 - - - stage: nuget_and_json - displayName: NuGet Packaging and Build Json - dependsOn: ['package_signing'] - jobs: - - template: templates/nuget.yml - - template: templates/json.yml - - # This is done late so that we dont use resources before the big signing and packaging tasks. - - stage: compliance - dependsOn: ['package_signing'] - jobs: - - template: templates/compliance.yml - - - stage: test_and_release_artifacts - displayName: Test and Release Artifacts - dependsOn: ['prep'] - jobs: - - template: templates/testartifacts.yml - - - job: release_json - displayName: Create and Upload release.json - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - template: templates/SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - $metadata = Get-Content '$(Build.SourcesDirectory)/tools/metadata.json' -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package - @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" - Get-Content "$(Build.StagingDirectory)\release.json" - Write-Host "##vso[artifact.upload containerfolder=metadata;artifactname=metadata]$(Build.StagingDirectory)\release.json" - displayName: Create and upload release.json file to build artifact - retryCountOnTaskFailure: 2 - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/releasePipeline.yml b/tools/releaseBuild/azureDevOps/releasePipeline.yml index fb6b8d5d956..535276629b7 100644 --- a/tools/releaseBuild/azureDevOps/releasePipeline.yml +++ b/tools/releaseBuild/azureDevOps/releasePipeline.yml @@ -13,6 +13,10 @@ parameters: displayName: Skip nuget publishing. Used in testing publishing stage. default: false type: boolean + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' resources: pipelines: @@ -48,6 +52,8 @@ variables: value: true - group: ReleasePipelineSecrets - group: PipelineExecutionPats + - name: __DOTNET_RUNTIME_FEED + value: ${{ parameters.InternalSDKBlobURL }} stages: - stage: MSIXBundle @@ -290,8 +296,8 @@ stages: Update and merge the changelog for the release. This step is required for creating GitHub draft release. -- stage: GitHubDraftRelease - displayName: Create GitHub draft release +- stage: BlobPublic + displayName: Make Blob Public # do not include stages that are likely to fail in dependency as there is no way to force deploy. dependsOn: UpdateChangeLog @@ -314,6 +320,38 @@ stages: steps: - template: templates/release-MakeContainerPublic.yml + - template: templates/release/approvalJob.yml + parameters: + displayName: Copy Global tool packages to PSInfra storage + jobName: CopyBlobApproval + instructions: | + Approval for Copy global tool packages to PSInfra storage + + - job: PSInfraBlobPublic + displayName: Copy global tools to PSInfra storage + dependsOn: CopyBlobApproval + + pool: + name: PowerShell1ES + demands: + - ImageOverride -equals PSMMS2019-Secure + + variables: + - group: 'PSInfraStorage' + + steps: + - template: templates/release-CopyGlobalTools.yml + parameters: + sourceContainerName: 'tool-private' + destinationContainerName: 'tool' + sourceStorageAccountName: '$(GlobalToolStorageAccount)' + destinationStorageAccountName: '$(PSInfraStorageAccount)' + blobPrefix: '$(Version)' + +- stage: GitHubTasks + displayName: GitHub tasks + dependsOn: BlobPublic + jobs: - job: GitHubDraft displayName: Create GitHub Draft release @@ -324,30 +362,27 @@ stages: variables: - group: 'Azure Blob variable group' - - group: 'AzDevOpsArtifacts' + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv - group: ReleasePipelineSecrets - dependsOn: AzureBlobPublic steps: - template: templates/release-CreateGitHubDraft.yml -- stage: GitHubManualTasks - displayName: GitHub manual tasks - dependsOn: GitHubDraftRelease - jobs: - deployment: PushTag + dependsOn: GitHubDraft displayName: Push Git Tag pool : server environment: PSReleasePushTag - deployment: MakeDraftPublic + dependsOn: PushTag displayName: Make GitHub Draft public pool : server environment: PSReleaseDraftPublic - dependsOn: PushTag - stage: PublishPackages displayName: Publish packages - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks jobs: - job: PublishNuget @@ -370,8 +405,10 @@ stages: - ImageOverride -equals PSMMSUbuntu20.04-Secure variables: - - group: 'AzDevOpsArtifacts' + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv - group: 'packages.microsoft.com' + - group: 'mscodehub-code-read-akv' steps: - template: templates/release-PublishPackageMsftCom.yml parameters: @@ -405,7 +442,7 @@ stages: - stage: ReleaseDocker displayName: Release Docker dependsOn: - - GitHubManualTasks + - GitHubTasks jobs: - deployment: ReleaseDocker displayName: Release Docker @@ -504,7 +541,7 @@ stages: Notify the PM team to start the process of releasing to MU. - stage: UpdateDotnetDocker - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Update DotNet SDK Docker images jobs: - template: templates/release/approvalJob.yml @@ -519,7 +556,7 @@ stages: 4. create PR targeting nightly branch - stage: UpdateWinGet - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Add manifest entry to winget jobs: - template: templates/release/approvalJob.yml @@ -530,7 +567,7 @@ stages: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Publish MSIX to store jobs: - template: templates/release/approvalJob.yml @@ -541,7 +578,7 @@ stages: Ask Steve to release MSIX bundle package to Store - stage: BuildInfoJson - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Upload BuildInfoJson jobs: - deployment: UploadJson @@ -562,7 +599,7 @@ stages: - template: templates/release-BuildJson.yml - stage: ReleaseVPack - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Release VPack jobs: - job: KickoffvPack @@ -611,7 +648,7 @@ stages: } - stage: ReleaseDeps - dependsOn: GitHubManualTasks + dependsOn: GitHubTasks displayName: Update pwsh.deps.json links jobs: - template: templates/release-UpdateDepsJson.yml diff --git a/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml b/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml deleted file mode 100644 index dd9252a406f..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/SetVersionVariables.yml +++ /dev/null @@ -1,63 +0,0 @@ -parameters: - ReleaseTagVar: v6.2.0 - ReleaseTagVarName: ReleaseTagVar - CreateJson: 'no' - UseJson: 'yes' - -steps: -- ${{ if eq(parameters['UseJson'],'yes') }}: - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'BuildInfoJson' - itemPattern: '**/*.json' - downloadPath: '$(System.ArtifactsDirectory)' - displayName: Download Build Info Json - -- 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 detect 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' - -- powershell: | - $createJson = ("${{ parameters.CreateJson }}" -ne "no") - $releaseTag = & "$env:REPOROOT/tools/releaseBuild/setReleaseTag.ps1" -ReleaseTag ${{ parameters.ReleaseTagVar }} -Variable "${{ parameters.ReleaseTagVarName }}" -CreateJson:$createJson - $version = $releaseTag.Substring(1) - $vstsCommandString = "vso[task.setvariable variable=Version]$version" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $azureVersion = $releaseTag.ToLowerInvariant() -replace '\.', '-' - $vstsCommandString = "vso[task.setvariable variable=AzureVersion]$azureVersion" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' - -- powershell: | - Get-ChildItem -Path env: - displayName: Capture environment - condition: succeededOrFailed() diff --git a/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml b/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml deleted file mode 100644 index af6451004e4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/checkAzureContainer.yml +++ /dev/null @@ -1,51 +0,0 @@ -jobs: -- job: DeleteBlob - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: Azure Blob variable group - displayName: Delete blob is exists - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no - - - task: AzurePowerShell@4 - displayName: Check if blob exists and delete if specified - inputs: - azureSubscription: '$(AzureFileCopySubscription)' - scriptType: inlineScript - azurePowerShellVersion: latestVersion - inline: | - try { - $container = Get-AzStorageContainer -Container '$(AzureVersion)' -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -ErrorAction Stop - - if ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'false') { - throw 'Azure blob container $(AzureVersion) already exists. To overwrite, use ForceAzureBlobDelete parameter' - } - elseif ($container -ne $null -and '$(ForceAzureBlobDelete)' -eq 'true') { - Write-Verbose -Verbose 'Removing container $(AzureVersion) due to ForceAzureBlobDelete parameter' - Remove-AzStorageContainer -Name '$(AzureVersion)' -Context (New-AzStorageContext -StorageAccountName '$(StorageAccount)') -Force - } - } - catch { - if ($_.FullyQualifiedErrorId -eq 'ResourceNotFoundException,Microsoft.WindowsAzure.Commands.Storage.Blob.Cmdlet.GetAzureStorageContainerCommand') { - Write-Verbose -Verbose 'Container "$(AzureVersion)" does not exists.' - } - else { - throw $_ - } - } - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml b/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml deleted file mode 100644 index 352458390f9..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/cloneToOfficialPath.yml +++ /dev/null @@ -1,19 +0,0 @@ -parameters: - nativePathRoot: '' - -steps: - - powershell: | - $dirSeparatorChar = [system.io.path]::DirectorySeparatorChar - $nativePath = "${{parameters.nativePathRoot }}${dirSeparatorChar}PowerShell" - Write-Host "##vso[task.setvariable variable=PowerShellRoot]$nativePath" - - if ((Test-Path "$nativePath")) { - Remove-Item -Path "$nativePath" -Force -Recurse -Verbose -ErrorAction ignore - } - else { - Write-Verbose -Verbose -Message "No cleanup required." - } - - git clone --quiet $env:REPOROOT $nativePath - displayName: Clone PowerShell Repo to /PowerShell - errorActionPreference: silentlycontinue diff --git a/tools/releaseBuild/azureDevOps/templates/compliance.yml b/tools/releaseBuild/azureDevOps/templates/compliance.yml deleted file mode 100644 index 0a416389bf4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance.yml +++ /dev/null @@ -1,124 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: compliance - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - displayName: Compliance - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download artifacts' - inputs: - buildType: current - downloadType: single - artifactName: results - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture artifacts directory' - continueOnError: true - - - template: expand-compliance.yml - parameters: - architecture: fxdependent - version: $(version) - - - template: expand-compliance.yml - parameters: - architecture: x86 - version: $(version) - - - template: expand-compliance.yml - parameters: - architecture: x64 - version: $(version) - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-antimalware.AntiMalware@3 - displayName: 'Run Defender Scan' - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3 - displayName: 'Run BinSkim ' - inputs: - InputType: Basic - AnalyzeTarget: '$(CompliancePath)\*.dll;$(CompliancePath)\*.exe' - AnalyzeSymPath: 'SRV*' - AnalyzeVerbose: true - AnalyzeHashes: true - AnalyzeStatistics: true - continueOnError: true - - # add RoslynAnalyzers - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-autoapplicability.AutoApplicability@1 - displayName: 'Run AutoApplicability' - inputs: - ExternalRelease: true - IsSoftware: true - DataSensitivity: lbi - continueOnError: true - - # add codeMetrics - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-vulnerabilityassessment.VulnerabilityAssessment@0 - displayName: 'Run Vulnerability Assessment' - continueOnError: true - - # FXCop is not applicable - - # PreFASt is not applicable - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 - displayName: 'Publish Security Analysis Logs to Build Artifacts' - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-uploadtotsa.TSAUpload@1 - displayName: 'TSA upload to Codebase: PowerShellCore_201906' - inputs: - tsaVersion: TsaV2 - codeBaseName: 'PowerShellCore_201906' - uploadAPIScan: false - uploadBinSkim: true - uploadCredScan: false - uploadFortifySCA: false - uploadFxCop: false - uploadModernCop: false - uploadPoliCheck: false - uploadPREfast: false - uploadRoslyn: false - uploadTSLint: false - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 - displayName: 'Create Security Analysis Report' - inputs: - TsvFile: false - APIScan: false - BinSkim: true - CredScan: true - PoliCheck: true - PoliCheckBreakOn: Severity2Above - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml index ea5efe0b224..3a46cc85667 100644 --- a/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml +++ b/tools/releaseBuild/azureDevOps/templates/compliance/apiscan.yml @@ -19,6 +19,8 @@ jobs: - group: DotNetPrivateBuildAccess - group: Azure Blob variable group - group: ReleasePipelineSecrets + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv pool: name: PowerShell1ES @@ -35,6 +37,10 @@ jobs: CreateJson: yes UseJson: no + - template: ../insert-nuget-config-azfeed.yml + parameters: + repoRoot: '$(Build.SourcesDirectory)' + - pwsh: | Import-Module .\build.psm1 -force Start-PSBootstrap @@ -42,7 +48,6 @@ jobs: retryCountOnTaskFailure: 2 displayName: 'Bootstrap' env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - pwsh: | @@ -126,7 +131,7 @@ jobs: displayName: 'Build PowerShell Source' - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() @@ -175,9 +180,8 @@ jobs: verbosityLevel: standard # write a status update every 5 minutes. Default is 1 minute statusUpdateInterval: '00:05:00' - surrogateConfigurationFolder : $(surrogateFilePath) env: - AzureServicesAuthConnectionString: RunAs=App;AppId=$(APIScanClient);TenantId=$(APIScanTenant);AppKey=$(APIScanSecret) + AzureServicesAuthConnectionString: RunAs=App - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@2 continueOnError: true @@ -197,7 +201,7 @@ jobs: GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\tools\guardian\tsaconfig-APIScan.json' - pwsh: | - Get-ChildItem -Path env: + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture Environment condition: succeededOrFailed() diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml b/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml deleted file mode 100644 index 8db52fc83f0..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance/compliance.yml +++ /dev/null @@ -1,83 +0,0 @@ -parameters: - - name: parentJobs - type: jobList - -jobs: -- job: compliance - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - # Defines the variables APIScanClient, APIScanTenant and APIScanSecret - - group: PS-PS-APIScan - - displayName: Compliance - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - # APIScan can take a long time - timeoutInMinutes: 180 - - steps: - - checkout: self - clean: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3 - displayName: 'Run CredScan' - inputs: - suppressionsFile: tools/credScan/suppress.json - debugMode: false - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@2 - displayName: 'Run PoliCheck' - inputs: - # targetType F means file or folder and is the only applicable value and the default - targetType: F - # 1 to enable source code comment scanning, which is what we should do for open source - optionsFC: 1 - # recurse - optionsXS: 1 - # run for severity 1, 2, 3 and 4 issues - optionsPE: '1|2|3|4' - # disable history management - optionsHMENABLE: 0 - # Excluclusion access database - optionsRulesDBPath: '$(Build.SourcesDirectory)\tools\terms\PowerShell-Terms-Rules.mdb' - # Terms Exclusion xml file - optionsUEPath: $(Build.SourcesDirectory)\tools\terms\TermsExclusion.xml - continueOnError: true - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs to Build Artifacts' - continueOnError: true - - - task: TSAUpload@2 - displayName: 'TSA upload' - inputs: - GdnPublishTsaOnboard: false - GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\tools\guardian\tsaconfig-others.json' - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 - displayName: 'Create Security Analysis Report' - inputs: - TsvFile: false - APIScan: false - BinSkim: false - CredScan: true - PoliCheck: true - PoliCheckBreakOn: Severity2Above - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml b/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml deleted file mode 100644 index 3e91b9174d2..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/compliance/generateNotice.yml +++ /dev/null @@ -1,90 +0,0 @@ -parameters: - - name: parentJobs - type: jobList - -jobs: -- job: generateNotice - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - - displayName: Generate Notice - dependsOn: - ${{ parameters.parentJobs }} - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - timeoutInMinutes: 15 - - steps: - - checkout: self - clean: true - - - pwsh: | - [string]$Branch=$env:BUILD_SOURCEBRANCH - $branchOnly = $Branch -replace '^refs/heads/'; - $branchOnly = $branchOnly -replace '[_\-]' - - if ($branchOnly -eq 'master') { - $container = 'tpn' - } else { - $branchOnly = $branchOnly -replace '[\./]', '-' - $container = "tpn-$branchOnly" - } - - $vstsCommandString = "vso[task.setvariable variable=tpnContainer]$container" - Write-Verbose -Message $vstsCommandString -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Set ContainerName - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - - - pwsh: | - ./tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest - displayName: Verify that packages have license data - - - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 - displayName: 'NOTICE File Generator' - inputs: - outputfile: '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' - # output format can be html or text - outputformat: text - # this isn't working - # additionaldata: $(Build.SourcesDirectory)\assets\additionalAttributions.txt - - - - pwsh: | - Get-Content -Raw -Path $(Build.SourcesDirectory)\assets\additionalAttributions.txt | Out-File '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' -Encoding utf8NoBOM -Force -Append - Get-Content -Raw -Path '$(Build.SourcesDirectory)\assets\additionalAttributions.txt' - displayName: Append Additional Attributions - continueOnError: true - - - pwsh: | - Get-Content -Raw -Path '$(System.ArtifactsDirectory)\ThirdPartyNotices.txt' - displayName: Capture Notice - continueOnError: true - - - task: AzureFileCopy@4 - displayName: 'upload Notice' - inputs: - SourcePath: $(System.ArtifactsDirectory)\ThirdPartyNotices.txt - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: $(tpnContainer) - resourceGroup: '$(StorageResourceGroup)' - retryCountOnTaskFailure: 2 - - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(System.ArtifactsDirectory) - artifactName: notice - displayName: Publish notice artifacts - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml b/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml deleted file mode 100644 index 4cc25433262..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/expand-compliance.yml +++ /dev/null @@ -1,12 +0,0 @@ -parameters: - architecture: x86 - version: 6.2.0 - -steps: - - powershell: | - Expand-Archive -Path "$(System.ArtifactsDirectory)\results\PowerShell-${{ parameters.version }}-symbols-win-${{ parameters.architecture }}.zip" -Destination "$(Build.StagingDirectory)\symbols\${{ parameters.architecture }}" - displayName: Expand symbols zip - ${{ parameters.architecture }} - - - powershell: | - tools/releaseBuild/createComplianceFolder.ps1 -ArtifactFolder "$(Build.StagingDirectory)\symbols\${{ parameters.architecture }}" -VSTSVariableName 'CompliancePath' - displayName: Expand Compliance file - ${{ parameters.architecture }} diff --git a/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml b/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml deleted file mode 100644 index d7200809cca..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/global-tool-pkg-sbom.yml +++ /dev/null @@ -1,64 +0,0 @@ -parameters: - - name: PackageVersion - - name: LinuxBinPath - - name: WindowsBinPath - - name: WindowsDesktopBinPath - - name: AlpineBinPath - - name: DestinationPath - - name: ListOfPackageTypes - type: object - default: - - Unified - - PowerShell.Linux.Alpine - - PowerShell.Linux.x64 - - PowerShell.Linux.arm32 - - PowerShell.Linux.arm64 - - PowerShell.Windows.x64 - -steps: - -- pwsh: | - Write-Verbose -Verbose 'LinuxBinPath path: ${{ parameters.LinuxBinPath }}' - Write-Verbose -Verbose 'WindowsBinPath path: ${{ parameters.WindowsBinPath }}' - Write-Verbose -Verbose 'WindowsDesktopBinPath path: ${{ parameters.WindowsDesktopBinPath }}' - Write-Verbose -Verbose 'AlpineBinPath path: ${{ parameters.AlpineBinPath }}' - - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - Start-PrepForGlobalToolNupkg -LinuxBinPath '${{ parameters.LinuxBinPath }}' -WindowsBinPath '${{ parameters.WindowsBinPath }}' -WindowsDesktopBinPath '${{ parameters.WindowsDesktopBinPath }}' -AlpineBinPath '${{ parameters.AlpineBinPath }}' - displayName: 'Preparation for Global Tools package creation.' - -# NOTE: The Unified package must always be created first, and so must always be first in ListOfPackageTypes. -- ${{ each value in parameters.ListOfPackageTypes }}: - - pwsh: | - $PackageType = '${{ value }}' - - Write-Verbose -Verbose "PackageType: $PackageType" - Write-Verbose -Verbose 'Destination path: ${{ parameters.PackagePath }}' - - # Create global tool NuSpec source for package. - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - New-GlobalToolNupkgSource -PackageType $PackageType -PackageVersion '${{ parameters.PackageVersion }}' -LinuxBinPath '${{ parameters.LinuxBinPath }}' -WindowsBinPath '${{ parameters.WindowsBinPath }}' -WindowsDesktopBinPath '${{ parameters.WindowsDesktopBinPath }}' -AlpineBinPath '${{ parameters.AlpineBinPath }}' - displayName: 'Create global tool NuSpec source for package.' - - - pwsh: | - Get-ChildItem -Path env: - displayName: 'Capture environment variables after Global Tool package source is created.' - - # NOTE: The above 'New-GlobalToolNupkgSource' task function sets the 'GlobalToolNuSpecSourcePath', 'GlobalToolPkgName', - # and 'GlobalToolCGManifestPath' environment variables. - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: $(GlobalToolNuSpecSourcePath) - Build_Repository_Uri: 'https://github.com/powershell/powershell' - PackageName: $(GlobalToolPkgName) - PackageVersion: ${{ parameters.PackageVersion }} - sourceScanPath: $(GlobalToolCGManifestPath) - displayName: SBOM for Global Tool package - - - pwsh: | - Import-Module -Name $env:REPOROOT\build.psm1 - Import-Module -Name $env:REPOROOT\tools\packaging - New-GlobalToolNupkgFromSource -PackageNuSpecPath "$env:GlobalToolNuSpecSourcePath" -PackageName "$env:GlobalToolPkgName" -DestinationPath '${{ parameters.DestinationPath }}' -CGManifestPath "$env:GlobalToolCGManifestPath" - displayName: 'Create global tool NuSpec package from NuSpec source.' diff --git a/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml b/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml deleted file mode 100644 index 3ff723be6ed..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml +++ /dev/null @@ -1,38 +0,0 @@ -parameters: - - name: "repoRoot" - default: $(REPOROOT) - -steps: -- pwsh: | - $configPath = "${env:NugetConfigDir}/nuget.config" - Import-Module ${{ parameters.repoRoot }}/build.psm1 -Force - New-NugetConfigFile -NugetFeedUrl $(AzDevOpsFeed) -UserName $(AzDevOpsFeedUserName) -ClearTextPAT $(AzDevOpsFeedPAT2) -FeedName AzDevOpsFeed -Destination "${env:NugetConfigDir}" - - if(-not (Test-Path $configPath)) - { - throw "nuget.config is not created" - } - Get-Content $configPath | Write-Verbose -Verbose - displayName: 'Add nuget.config for Azure DevOps feed for PSGallery modules' - condition: and(succeededOrFailed(), ne(variables['AzDevOpsFeed'], '')) - env: - NugetConfigDir: ${{ parameters.repoRoot }}/src/Modules - -- pwsh: | - $configPath = "${env:NugetConfigDir}/nuget.config" - Import-Module ${{ parameters.repoRoot }}/build.psm1 -Force - New-NugetConfigFile -NugetFeedUrl $(PSInternalNugetFeed) -UserName $(PSInternalNugetFeedUserName) -ClearTextPAT $(PSInternalNugetFeedPAT) -FeedName AzDevOpsFeed -Destination "${env:NugetConfigDir}" - - if(-not (Test-Path $configPath)) - { - throw "nuget.config is not created" - } - Get-Content $configPath | Write-Verbose -Verbose - displayName: 'Add nuget.config for Azure DevOps feed for packages' - condition: and(succeededOrFailed(), ne(variables['PSInternalNugetFeed'], '')) - env: - NugetConfigDir: ${{ parameters.repoRoot }} - -- task: nuget-security-analysis@0 - displayName: 'Run Secure Supply Chain analysis' - condition: and(succeededOrFailed(), ne(variables['PSInternalNugetFeed'], ''), ne(variables['AzDevOpsFeed'], '')) diff --git a/tools/releaseBuild/azureDevOps/templates/json.yml b/tools/releaseBuild/azureDevOps/templates/json.yml deleted file mode 100644 index 48a50e0bf14..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/json.yml +++ /dev/null @@ -1,57 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: json - variables: - - name: runCodesignValidationInjection - value : false - - name: NugetSecurityAnalysisWarningLevel - value: none - displayName: Create Json for Blob - dependsOn: - ${{ parameters.parentJobs }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - #- task: @ - # inputs: - # - # displayName: '' - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - task: AzureFileCopy@4 - displayName: 'upload daily-build-info JSON file to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(BuildInfoPath)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: 'BuildInfo' - condition: and(succeeded(), eq(variables['IS_DAILY'], 'true')) - - - task: AzureCLI@1 - displayName: 'Make blob public' - inputs: - azureSubscription: '$(AzureFileCopySubscription)' - scriptLocation: inlineScript - inlineScript: 'az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion) --public-access blob' - condition: and(succeeded(), eq(variables['IS_DAILY'], 'true')) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml b/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml deleted file mode 100644 index 719ba1a6c30..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux-authenticode-sign.yml +++ /dev/null @@ -1,184 +0,0 @@ -jobs: -- job: sign_linux_builds - displayName: Sign all linux builds - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - dependsOn: ['build_fxdependent', 'build_rpm'] - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuild.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download deb build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildMinSize.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download min-size build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm32.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download arm32 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download arm64 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildAmd64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download mariner build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildArm64.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Download mariner arm64 build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz - displayName: Download alpine build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz - displayName: Download alpine fxdependent build - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildFxdependent.tar.gz - path: $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz - displayName: Download fxdependent build - - - pwsh: | - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/linuxTars - displayName: Capture downloaded tars - - - pwsh: | - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - Write-Verbose -Verbose "File permisions after expanding" - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildMinSize.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildMinSize.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm32.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm32.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshMarinerBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildAlpine.tar.gz/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz/pwshAlpineFxdBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshAlpineFxdBuildAmd64.tar.gz/pwshAlpineFxdBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpineFxd - - Write-Verbose -Verbose -Message "Expanding $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/linuxTars/pwshLinuxBuildFxdependent.tar.gz/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent - displayName: Expand builds - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - Set-Location $env:POWERSHELLROOT - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - - - checkout: ComplianceRepo - clean: true - - - template: shouldSign.yml - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuild - buildPrefixName: 'PowerShell Linux' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildMinSize - buildPrefixName: 'PowerShell Linux Minimum Size' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildArm32 - buildPrefixName: 'PowerShell Linux Arm32' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildArm64 - buildPrefixName: 'PowerShell Linux Arm64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshMarinerBuildAmd64 - buildPrefixName: 'PowerShell Linux x64 (Mariner) Framework Dependent' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshMarinerBuildArm64 - buildPrefixName: 'PowerShell Linux arm64 (Mariner) Framework Dependent' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildAlpine - buildPrefixName: 'PowerShell Linux Alpine x64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildAlpineFxd - buildPrefixName: 'PowerShell Linux Alpine Fxd x64' - - - template: signBuildFiles.yml - parameters: - binLocation: pwshLinuxBuildFxdependent - buildPrefixName: 'PowerShell Linux Framework Dependent' diff --git a/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml b/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml deleted file mode 100644 index 4439ded9f26..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux-packaging.yml +++ /dev/null @@ -1,490 +0,0 @@ -parameters: - buildName: '' - uploadDisplayName: 'Upload' - -jobs: -- job: pkg_${{ parameters.buildName }} - displayName: Package ${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - variables: - - name: runCodesignValidationInjection - value: false - - name: build - value: ${{ parameters.buildName }} - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - ${{ if or(eq(variables.build,'deb'), eq(variables.build,'rpm')) }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed - pattern: '**/pwshLinuxBuild.tar.gz' - displayName: Download deb build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed - pattern: '**/pwshLinuxBuildMinSize.tar.gz' - displayName: Download min-size build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed - pattern: '**/pwshLinuxBuildArm32.tar.gz' - displayName: Download arm32 build - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed - pattern: '**/pwshLinuxBuildArm64.tar.gz' - displayName: Download arm64 build - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed - pattern: '**/pwshMarinerBuildAmd64.tar.gz' - displayName: Download mariner amd64 build - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed - pattern: '**/pwshMarinerBuildArm64.tar.gz' - displayName: Download mariner arm64 build - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed - pattern: '**/pwshLinuxBuildAlpine.tar.gz' - displayName: Download alpine build - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed - pattern: '**/pwshAlpineFxdBuildAmd64.tar.gz' - displayName: Download alpine framework dependent build - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: authenticode-signed - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed - pattern: '**/pwshLinuxBuildFxdependent.tar.gz' - displayName: Download fxdependent build - - - ${{ if or(eq(variables.build,'deb'), eq(variables.build,'rpm')) }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuild-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download deb build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildMinSize-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-meta - displayName: Download min-size build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm32-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-meta - displayName: Download arm32 build meta - - - ${{ if eq(variables.build,'deb') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildArm64-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-meta - displayName: Download arm64 build meta - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildAmd64-meta - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-meta - displayName: Download mariner x64 build meta - - - ${{ if eq(variables.build,'rpm') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshMarinerBuildArm64-meta - path: $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-meta - displayName: Download mariner arm64 build meta - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildAlpine-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download alpine build meta - - - ${{ if eq(variables.build,'alpine') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshAlpineFxdBuildAmd64-meta - path: $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-meta - displayName: Download alpine build meta - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: DownloadPipelineArtifact@2 - inputs: - artifact: pwshLinuxBuildFxdependent-meta - path: $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-meta - displayName: Download fxdependent build meta - - - pwsh: | - Get-ChildItem '$(Build.ArtifactStagingDirectory)' | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Capture downloads - - - pwsh: | - if ('$(build)' -eq 'deb' -or '$(build)' -eq 'rpm') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed/pwshLinuxBuild.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuild-signed/pwshLinuxBuild.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - } - - if ('$(build)' -eq 'deb') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed/pwshLinuxBuildMinSize.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize-signed/pwshLinuxBuildMinSize.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildMinSize - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed/pwshLinuxBuildArm32.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32-signed/pwshLinuxBuildArm32.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm32 - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed/pwshLinuxBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64-signed/pwshLinuxBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuildArm64 - } - - if ('$(build)' -eq 'rpm') { - # for mariner x64 - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed/pwshMarinerBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64-signed/pwshMarinerBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildAmd64 - - # for mariner arm64 - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed/pwshMarinerBuildArm64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64-signed/pwshMarinerBuildArm64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshMarinerBuildArm64 - } - - if ('$(build)' -eq 'alpine') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed/pwshLinuxBuildAlpine.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildAlpine-signed/pwshLinuxBuildAlpine.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed/pwshAlpineFxdBuildAmd64.tar.gz to $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64 -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64-signed/pwshAlpineFxdBuildAmd64.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshAlpineFxdBuildAmd64 - } - - if ('$(build)' -eq 'fxdependent') { - Write-Verbose -Verbose "Expanding $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed/pwshLinuxBuildFxdependent.tar.gz to $(Build.ArtifactStagingDirectory)/pwshLinuxBuild" - New-Item -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild -ItemType Directory - tar -xf $(Build.ArtifactStagingDirectory)/pwshLinuxBuildFxdependent-signed/pwshLinuxBuildFxdependent.tar.gz -C $(Build.ArtifactStagingDirectory)/pwshLinuxBuild - } - displayName: Expand all signed tar.gz - - - pwsh: | - Get-ChildItem '$(Build.ArtifactStagingDirectory)' | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Capture expanded - - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir /PowerShell - - # make the current user the owner - sudo chown $env:USER /PowerShell - displayName: 'Create /PowerShell' - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - powershell: | - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - Import-Module "$env:POWERSHELLROOT/build.psm1" - - Start-PSBootstrap -Package - displayName: 'Bootstrap' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - powershell: | - try { - Import-Module "$env:POWERSHELLROOT/build.psm1" - Import-Module "$env:POWERSHELLROOT/tools/packaging" - - $metadata = Get-Content "$env:POWERSHELLROOT/tools/metadata.json" -Raw | ConvertFrom-Json - - # LTSRelease.Package indicates that the release should be packaged as an LTS - $LTS = $metadata.LTSRelease.Package - Write-Verbose -Verbose -Message "LTS is set to: $LTS" - - Invoke-AzDevOpsLinuxPackageCreation -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - - if ($LTS) { - Write-Verbose -Verbose "Packaging LTS" - Invoke-AzDevOpsLinuxPackageCreation -LTS -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - } - } catch { - Get-Error - throw - } - displayName: 'Package' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - $linuxPackages = Get-ChildItem "$env:POWERSHELLROOT/powershell*" -Include *.deb,*.rpm,*.tar.gz - - $bucket = 'release' - foreach ($linuxPackage in $linuxPackages) - { - $filePath = $linuxPackage.FullName - Write-Verbose "Publishing $filePath to $bucket" -Verbose - Write-Host "##vso[artifact.upload containerfolder=$bucket;artifactname=$bucket]$filePath" - } - displayName: Publish artifacts - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - retryCountOnTaskFailure: 2 - - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml - -- job: upload_${{ parameters.buildName }} - displayName: ${{ parameters.uploadDisplayName }} ${{ parameters.buildName }} - dependsOn: pkg_${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: buildName - value: ${{ parameters.buildName }} - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipComponentGovernanceDetection - value: true - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Deb Artifacts' - inputs: - downloadType: specific - itemPattern: '**/*.deb' - downloadPath: '$(System.ArtifactsDirectory)\finished' - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download tar.gz Artifacts copy' - inputs: - downloadType: specific - itemPattern: '**/*.tar.gz' - downloadPath: '$(System.ArtifactsDirectory)\finished' - - - powershell: | - Write-Host 'We handle the min-size package only when uploading for deb build.' - Write-Host '- For deb build, the min-size package is moved to a separate folder "finished\minSize",' - Write-Host ' so that the min-size package can be uploaded to a different Az Blob container.' - Write-Host '- For other builds, the min-size package is removed after being downloaded, so that it' - Write-Host ' does not get accidentally uploaded to the wrong Az Blob container.' - - $minSizePkg = '$(System.ArtifactsDirectory)\finished\release\*-gc.tar.gz' - if (Test-Path -Path $minSizePkg) - { - if ('$(buildName)' -eq 'DEB') - { - $minSizeDir = '$(System.ArtifactsDirectory)\finished\minSize' - New-Item -Path $minSizeDir -Type Directory -Force > $null - Move-Item -Path $minSizePkg -Destination $minSizeDir - - Write-Host "`nCapture the min-size package moved to the target folder." - Get-ChildItem -Path $minSizeDir - } - else - { - Write-Host '$(buildName): Remove the min-size package.' - Remove-Item -Path $minSizePkg -Force - } - } - else - { - Write-Host 'min-size package not found, so skip this step.' - } - displayName: 'Move minSize package to separate folder' - - - task: DownloadBuildArtifacts@0 - displayName: 'Download rpm Artifacts copy' - inputs: - downloadType: specific - itemPattern: '**/*.rpm' - downloadPath: '$(System.ArtifactsDirectory)\rpm' - condition: and(eq(variables['buildName'], 'RPM'), succeeded()) - - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(System.ArtifactsDirectory) - pattern: | - **\*.rpm - **\*.deb - **\*.tar.gz - - - ${{ if eq(variables['buildName'], 'RPM') }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\rpm - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "CP-450779-Pgp" - pattern: | - **\*.rh.*.rpm - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign RedHat RPM - OutputMode: AlwaysCopy - - - ${{ if eq(variables['buildName'], 'RPM') }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - # Sign in-place, previous task copied the files to this folder - buildOutputPath: $(Build.StagingDirectory)\signedPackages - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "CP-459159-Pgp" - pattern: | - **\*.cm.*.rpm - **\*.cm?.*.rpm - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign Mariner RPM - OutputMode: NeverCopy - - # requires windows - - ${{ if ne(variables['buildName'], 'RPM') }}: - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - DEB and tar.gz' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\finished\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\finished\release - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - min-size package for Guest Config' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\finished\minSize\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-gc' - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\finished\minSize - condition: and(eq(variables['buildName'], 'DEB'), succeeded()) - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - RPM - Unsigned' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\rpm\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - retryCountOnTaskFailure: 2 - - # requires windows - - task: AzureFileCopy@4 - displayName: 'Upload to Azure - RPM - Signed' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\release\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - retryCountOnTaskFailure: 2 - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\rpm\release - condition: and(and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - - - template: upload-final-results.yml - parameters: - artifactPath: '$(Build.StagingDirectory)\signedPackages\release' - condition: and(and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')),eq(variables['buildName'], 'RPM')) - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/linux.yml b/tools/releaseBuild/azureDevOps/templates/linux.yml deleted file mode 100644 index a65045ce323..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/linux.yml +++ /dev/null @@ -1,314 +0,0 @@ -parameters: - buildName: '' - uploadDisplayName: 'Upload' - parentJob: '' - -jobs: -- job: build_${{ parameters.buildName }} - displayName: Build ${{ parameters.buildName }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - dependsOn: ${{ parameters.parentJob }} - variables: - - name: runCodesignValidationInjection - value: false - - name: build - value: ${{ parameters.buildName }} - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir /PowerShell - - # make the current user the owner - sudo chown $env:USER /PowerShell - displayName: 'Create /PowerShell' - - - template: cloneToOfficialPath.yml - - - template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - powershell: | - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - powershell: | - Import-Module "$env:POWERSHELLROOT/build.psm1" - - Start-PSBootstrap -Package - displayName: 'Bootstrap' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - try { - Import-Module "$env:POWERSHELLROOT/build.psm1" - Import-Module "$env:POWERSHELLROOT/tools/packaging" - - Invoke-AzDevOpsLinuxPackageBuild -ReleaseTag '$(ReleaseTagVar)' -BuildType '$(build)' - - Write-Verbose -Verbose "File permisions after building" - Get-ChildItem -Path $(System.ArtifactsDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - } catch { - Get-Error - throw - } - displayName: 'Build' - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - workingDirectory: $(PowerShellRoot) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuild' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: ${{ parameters.buildName }} SBOM - PackageName: PowerShell Linux - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'rpm') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Mariner x64 SBOM - PackageName: PowerShell Linux Framework Dependent - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'rpm') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Mariner arm64 SBOM - PackageName: PowerShell Linux Framework Dependent - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: MinSize SBOM - PackageName: PowerShell Linux Minimum Size - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Arm32 SBOM - PackageName: PowerShell Linux Arm32 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'deb') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Arm64 SBOM - PackageName: PowerShell Linux Arm64 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - ${{ if eq(variables.build,'alpine') }} : - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - displayName: Alpine FXD SBOM - PackageName: PowerShell Alpine Framework Dependent AMD64 - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuild' - Write-Verbose -Verbose "File permisions before compressing" - Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/pwshLinuxBuild/pwsh | Select-Object -Property 'unixmode', 'size', 'name' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz * - displayName: Compress pwshLinuxBuild - - - ${{ if eq(variables.build,'deb') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildMinSize.tar.gz * - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildArm32.tar.gz * - Set-Location '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64' - tar -czvf $(System.ArtifactsDirectory)/pwshLinuxBuildArm64.tar.gz * - displayName: Compress deb - - - ${{ if eq(variables.build,'rpm') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64' - tar -czvf $(System.ArtifactsDirectory)/pwshMarinerBuildAmd64.tar.gz * - displayName: Compress pwshMarinerBuildAmd64 - - - ${{ if eq(variables.build,'alpine') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64' - tar -czvf $(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64.tar.gz * - displayName: Compress pwshAlpineFxdBuildAmd64 - - - ${{ if eq(variables.build,'rpm') }} : - - pwsh: | - Set-Location '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64' - tar -czvf $(System.ArtifactsDirectory)/pwshMarinerBuildArm64.tar.gz * - displayName: Compress pwshMarinerBuildArm64 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuild.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuild-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize.tar.gz' - artifactName: pwshLinuxBuildMinSize.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildMinSize-meta' - artifactName: pwshLinuxBuildMinSize-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32.tar.gz' - artifactName: pwshLinuxBuildArm32.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm32-meta' - artifactName: pwshLinuxBuildArm32-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64.tar.gz' - artifactName: pwshLinuxBuildArm64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'deb') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuildArm64-meta' - artifactName: pwshLinuxBuildArm64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64.tar.gz' - artifactName: pwshMarinerBuildAmd64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildAmd64-meta' - artifactName: pwshMarinerBuildAmd64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64.tar.gz' - artifactName: pwshMarinerBuildArm64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'rpm') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshMarinerBuildArm64-meta' - artifactName: pwshMarinerBuildArm64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuildAlpine.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuildAlpine-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64.tar.gz' - artifactName: pwshAlpineFxdBuildAmd64.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'alpine') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshAlpineFxdBuildAmd64-meta' - artifactName: pwshAlpineFxdBuildAmd64-meta - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild.tar.gz' - artifactName: pwshLinuxBuildFxdependent.tar.gz - retryCountOnTaskFailure: 2 - - - ${{ if eq(variables.build,'fxdependent') }} : - - task: PublishPipelineArtifact@1 - inputs: - path: '$(System.ArtifactsDirectory)/pwshLinuxBuild-meta' - artifactName: pwshLinuxBuildFxdependent-meta - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml b/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml deleted file mode 100644 index 8159c2bc7d9..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-file-signing.yml +++ /dev/null @@ -1,121 +0,0 @@ -parameters: - buildArchitecture: 'x64' - -jobs: - - job: MacFileSigningJob_${{ parameters.buildArchitecture }} - displayName: macOS File signing ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'macosBinResults' - itemPattern: '**/*.zip' - downloadPath: '$(System.ArtifactsDirectory)\Symbols' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $zipPath = Get-Item '$(System.ArtifactsDirectory)\Symbols\macosBinResults\*symbol*${{ parameters.buildArchitecture }}*.zip' - Write-Verbose -Verbose "Zip Path: $zipPath" - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture artifacts dir Binaries' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\$(SymbolsFolder)" -Recurse -Include pwsh, *.dylib - displayName: 'Capture Expanded Binaries' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos" - $zipFile = "$(Build.StagingDirectory)\macos\powershell-files-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Get-ChildItem "$(System.ArtifactsDirectory)\$(SymbolsFolder)" -Recurse -Include pwsh, *.dylib | - Compress-Archive -Destination $zipFile - Write-Host $zipFile - displayName: 'Compress macOS binary files' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(Build.StagingDirectory)\macos - signOutputPath: $(Build.StagingDirectory)\signedMacOSPackages - certificateId: "CP-401337-Apple" - pattern: | - **\*.zip - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign macOS Binaries - - - pwsh: | - $destination = "$(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }}" - New-Item -Path $destination -Type Directory - $zipPath = Get-ChildItem "$(Build.StagingDirectory)\signedMacOSPackages\powershell-*.zip" -Recurse | select-object -expandproperty fullname - foreach ($z in $zipPath) { Expand-Archive -Path $z -DestinationPath $destination } - displayName: 'Extract and copy macOS artifacts for upload' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }} - artifactFilter: "*" - artifactName: signedMacOsBins_${{ parameters.buildArchitecture }} - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - ${{ if eq(variables['SHOULD_SIGN'], 'true') }}: - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(System.ArtifactsDirectory)\azureMacOs_${{ parameters.buildArchitecture }} - pattern: | - **\* - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml b/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml deleted file mode 100644 index f3801deaa9e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-package-build.yml +++ /dev/null @@ -1,145 +0,0 @@ -parameters: - parentJob: '' - buildArchitecture: x64 - -jobs: -- job: package_macOS_${{ parameters.buildArchitecture }} - displayName: Package macOS ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - vmImage: macos-latest - variables: - # Turn off Homebrew analytics - - name: HOMEBREW_NO_ANALYTICS - value: 1 - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - steps: - - checkout: self - clean: true - - - pwsh: | - # create folder - sudo mkdir "$(Agent.TempDirectory)/PowerShell" - - # make the current user the owner - sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" - displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - template: cloneToOfficialPath.yml - parameters: - nativePathRoot: '$(Agent.TempDirectory)' - - - task: DownloadBuildArtifacts@0 - displayName: Download macosBinResults - inputs: - artifactName: 'macosBinResults' - itemPattern: '**/*${{ parameters.buildArchitecture }}.zip' - downloadPath: '$(System.ArtifactsDirectory)/Symbols' - - - task: DownloadBuildArtifacts@0 - displayName: Download signedMacOsBins - inputs: - artifactName: 'signedMacOsBins_${{ parameters.buildArchitecture }}' - itemPattern: '**/*' - downloadPath: '$(System.ArtifactsDirectory)/macOsBins' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $zipPath = Get-Item '$(System.ArtifactsDirectory)\Symbols\macosBinResults\*symbol*${{ parameters.buildArchitecture }}.zip' - Write-Verbose -Verbose "Zip Path: $zipPath" - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)/macOsBins/signedMacOsBins_${{ parameters.buildArchitecture }}/' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - displayName: Merge signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)/$(SymbolsFolder)' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - PackageName: PowerShell macOS ${{ parameters.buildArchitecture }} - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)/tools' - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $destFolder = '$(System.ArtifactsDirectory)\signedZip' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - $null = New-Item -ItemType Directory -Path $destFolder -Force - - $BuildPackagePath = New-PSBuildZip -BuildPath $BuildPath -DestinationFolder $destFolder - - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - - $vstsCommandString = "vso[task.setvariable variable=BuildPackagePath]$BuildPackagePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Compress signed files - retryCountOnTaskFailure: 2 - - - - pwsh: | - try { - tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -location $(PowerShellRoot) -BootStrap - } catch { - Get-Error - throw - } - displayName: 'Bootstrap VM' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - # Add -SkipReleaseChecks as a mitigation to unblock release. - # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. - try { - $(Build.SourcesDirectory)/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -ReleaseTag $(ReleaseTagVar) -Destination $(System.ArtifactsDirectory) -location $(PowerShellRoot) -ArtifactName macosPkgResults -BuildZip $(BuildPackagePath) -ExtraPackage "tar" -Runtime 'osx-${{ parameters.buildArchitecture }}' -SkipReleaseChecks - } catch { - Get-Error - throw - } - displayName: 'Package' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml b/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml deleted file mode 100644 index d4901580b0b..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac-package-signing.yml +++ /dev/null @@ -1,135 +0,0 @@ -parameters: - buildArchitecture: x64 - -jobs: -- job: MacPackageSigningJob_${{ parameters.buildArchitecture }} - displayName: macOS Package signing ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - group: ESRP - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: shouldSign.yml - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'macosPkgResults' - itemPattern: '**/*' - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos" - $zipFile = "$(Build.StagingDirectory)\macos\powershell-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Compress-Archive -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-${{ parameters.buildArchitecture }}.pkg" -Destination $zipFile - Write-Host $zipFile - - $ltsPkgPath = "$(System.ArtifactsDirectory)\macosPkgResults\powershell-lts-$(Version)-osx-${{ parameters.buildArchitecture }}.pkg" - - if(Test-Path $ltsPkgPath) - { - $ltsZipFile = "$(Build.StagingDirectory)\macos\powershell-lts-$(Version)-osx-${{ parameters.buildArchitecture }}.zip" - Compress-Archive -Path $ltsPkgPath -Destination $ltsZipFile - Write-Host $ltsZipFile - } - displayName: 'Compress macOS Package' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(Build.StagingDirectory)\macos - signOutputPath: $(Build.StagingDirectory)\signedMacOSPackages - certificateId: "CP-401337-Apple" - pattern: | - **\*.zip - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign pkg - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\macosPkgResults - artifactFilter: "*${{ parameters.buildArchitecture }}.tar.gz" - - - pwsh: | - $destination = "$(System.ArtifactsDirectory)\azureMacOs" - New-Item -Path $destination -Type Directory - $zipPath = dir "$(Build.StagingDirectory)\signedMacOSPackages\powershell-*.zip" -Recurse | select-object -expandproperty fullname - foreach ($z in $zipPath) { Expand-Archive -Path $z -DestinationPath $destination } - $targzPath = dir "$(System.ArtifactsDirectory)\*osx*.tar.gz" -Recurse | select-object -expandproperty fullname - Copy-Item -Path $targzPath -Destination $destination - displayName: 'Extract and copy macOS artifacts for upload' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\azureMacOs - artifactFilter: "*.pkg" - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - $null = new-item -type directory -path "$(Build.StagingDirectory)\macos-unsigned" - Copy-Item -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-x64.pkg" -Destination "$(Build.StagingDirectory)\macos-unsigned" - Copy-Item -Path "$(System.ArtifactsDirectory)\macosPkgResults\powershell-$(Version)-osx-x64.tar.gz" -Destination "$(Build.StagingDirectory)\macos-unsigned" - displayName: 'Create unsigned folder to upload' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - task: AzureFileCopy@4 - displayName: 'AzureBlob File Copy - unsigned' - inputs: - SourcePath: '$(Build.StagingDirectory)\macos-unsigned\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'AzureBlob File Copy - signed' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\azureMacOs\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/mac.yml b/tools/releaseBuild/azureDevOps/templates/mac.yml deleted file mode 100644 index f13c00ef421..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/mac.yml +++ /dev/null @@ -1,70 +0,0 @@ -parameters: - buildArchitecture: 'x64' - -jobs: -- job: build_macOS_${{ parameters.buildArchitecture }} - displayName: Build macOS ${{ parameters.buildArchitecture }} - condition: succeeded() - pool: - vmImage: macos-latest - variables: - # Turn off Homebrew analytics - - name: HOMEBREW_NO_ANALYTICS - value: 1 - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - steps: - #- task: @ - # inputs: - # - # displayName: '' - - checkout: self - clean: true - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - # create folder - sudo mkdir "$(Agent.TempDirectory)/PowerShell" - - # make the current user the owner - sudo chown $env:USER "$(Agent.TempDirectory)/PowerShell" - displayName: 'Create $(Agent.TempDirectory)/PowerShell' - - - template: cloneToOfficialPath.yml - parameters: - nativePathRoot: '$(Agent.TempDirectory)' - - - pwsh: | - tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -location $(PowerShellRoot) -BootStrap - displayName: 'Bootstrap VM' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - $env:AzDevOpsFeedPAT2 = '$(AzDevOpsFeedPAT2)' - # Add -SkipReleaseChecks as a mitigation to unblock release. - # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. - $(Build.SourcesDirectory)/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 -ReleaseTag $(ReleaseTagVar) -Destination $(System.ArtifactsDirectory) -Symbols -location $(PowerShellRoot) -Build -ArtifactName macosBinResults -Runtime 'osx-${{ parameters.buildArchitecture }}' -SkipReleaseChecks - $env:AzDevOpsFeedPAT2 = $null - displayName: 'Build' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(Build.SourcesDirectory)/tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml b/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml index f0a033fd9e4..7eefad98d71 100644 --- a/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml +++ b/tools/releaseBuild/azureDevOps/templates/nuget-pkg-sbom.yml @@ -20,6 +20,10 @@ parameters: steps: +- template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(REPOROOT) + - pwsh: | Import-Module "$env:REPOROOT/build.psm1" -Force Start-PSBootstrap @@ -81,6 +85,8 @@ steps: Write-Host "##$vstsCommandString" displayName: Build reference assemblies + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ${{ each value in parameters.ListOfFiles }}: - pwsh: | diff --git a/tools/releaseBuild/azureDevOps/templates/nuget.yml b/tools/releaseBuild/azureDevOps/templates/nuget.yml deleted file mode 100644 index 247e91013a3..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/nuget.yml +++ /dev/null @@ -1,291 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: build_nuget - dependsOn: - ${{ parameters.parentJobs }} - displayName: Build NuGet packages - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - - timeoutInMinutes: 90 - - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: build - value: ${{ parameters.buildName }} - - group: ESRP - - name: GenAPIToolPath - value: '$(System.ArtifactsDirectory)/GenAPI' - - name: PackagePath - value: '$(System.ArtifactsDirectory)/UnifiedPackagePath' - - name: winFxdPath - value: '$(System.ArtifactsDirectory)/winFxd' - - name: winFxdWinDesktopPath - value: '$(System.ArtifactsDirectory)/winFxdWinDesktop' - - name: linuxFxdPath - value: '$(System.ArtifactsDirectory)/linuxFxd' - - name: alpineFxdPath - value: '$(System.ArtifactsDirectory)/alpineFxd' - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - $content = Get-Content "$env:REPOROOT/global.json" -Raw | ConvertFrom-Json - $vstsCommandString = "vso[task.setvariable variable=SDKVersion]$($content.sdk.version)" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Find SDK version from global.json' - - - pwsh: | - Import-Module "$env:REPOROOT/build.psm1" -Force - # We just need .NET but we fixed this in an urgent situation. - Start-PSBootStrap -Verbose - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - task: DownloadBuildArtifacts@0 - displayName: 'Download PowerShell build artifacts - finalResults' - inputs: - buildType: current - downloadType: single - artifactName: finalResults - downloadPath: '$(System.ArtifactsDirectory)' - - - task: DownloadBuildArtifacts@0 - displayName: 'Download PowerShell build artifacts - macosPkgResults' - inputs: - buildType: current - downloadType: single - artifactName: macosPkgResults - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: 'Get-ChildItem $(System.ArtifactsDirectory) -recurse' - displayName: 'Capture downloaded artifacts' - - - powershell: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) packages) - New-Item $packagePath -ItemType Directory -Force > $null - $packages = Get-ChildItem $(System.ArtifactsDirectory) -Include *.zip, *.tar.gz -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - Get-ChildItem $packagePath -Recurse - displayName: 'Conflate packages to same folder' - - - task: ExtractFiles@1 - displayName: 'Extract files win-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/PowerShell-*-win-fxdependent.zip' - destinationFolder: '$(winFxdPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files win-fxdependentWinDesktop' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/PowerShell-*-win-fxdependentWinDesktop.zip' - destinationFolder: '$(winFxdWinDesktopPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files linux-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/powershell-*-linux-x64-fxdependent.tar.gz' - destinationFolder: '$(linuxFxdPath)' - - - task: ExtractFiles@1 - displayName: 'Extract files alpine-fxdependent' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/packages/powershell-*-linux-x64-musl-noopt-fxdependent.tar.gz' - destinationFolder: '$(alpineFxdPath)' - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # Create nuget packages along with SBOM manifests. - - template: nuget-pkg-sbom.yml - parameters: - PackageVersion: $(Version) - PackagePath: $(PackagePath) - WinFxdPath: $(winFxdPath) - LinuxFxdPath: $(linuxFxdPath) - - - pwsh: | - Get-ChildItem $(linuxFxdPath) - Get-ChildItem $(winFxdPath) - Get-ChildItem $(winFxdWinDesktopPath) - Get-ChildItem $(alpineFxdPath) - displayName: Capture fxd folders - - # Create Global Tool packages along with SBOM manifests - - template: global-tool-pkg-sbom.yml - parameters: - PackageVersion: $(Version) - LinuxBinPath: $(linuxFxdPath) - WindowsBinPath: $(winFxdPath) - WindowsDesktopBinPath: $(winFxdWinDesktopPath) - AlpineBinPath: $(alpineFxdPath) - DestinationPath: $(PackagePath)\globaltool - - - pwsh: | - Get-ChildItem "$(PackagePath)" -Recurse - displayName: Capture generated packages - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(PackagePath) - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "CP-401405" - pattern: | - **\*.nupkg - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign NuPkg - - - pwsh: | - if (-not (Test-Path '$(System.ArtifactsDirectory)\signed\')) { $null = New-Item -ItemType Directory -Path '$(System.ArtifactsDirectory)\signed\' } - Copy-Item -Path '$(PackagePath)\*.nupkg' -Destination '$(System.ArtifactsDirectory)\signed\' -Verbose -Force - Copy-Item -Path '$(PackagePath)\globaltool\*.nupkg' -Destination '$(System.ArtifactsDirectory)\signed\' -Verbose -Force - displayName: Fake copy when not signing - condition: eq(variables['SHOULD_SIGN'], 'false') - - - pwsh: | - Import-Module "${env:REPOROOT}\build.psm1" -Force - Get-ChildItem -Recurse "$(System.ArtifactsDirectory)\signed\*.nupkg" -Verbose | ForEach-Object { Start-NativeExecution -sb { nuget.exe verify -All $_.FullName } } - displayName: Verify all packages are signed - condition: eq(variables['SHOULD_SIGN'], 'true') - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-antimalware.AntiMalware@3 - displayName: 'Run MpCmdRun.exe' - inputs: - FileDirPath: '$(PackagePath)' - TreatStaleSignatureAs: Warning - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 - displayName: 'Publish Security Analysis Logs' - - - template: upload-final-results.yml - parameters: - artifactPath: '$(System.ArtifactsDirectory)\signed' - - - pwsh: | - if (-not (Test-Path "$(System.ArtifactsDirectory)\signed\globaltool")) - { - $null = New-Item -Path "$(System.ArtifactsDirectory)\signed\globaltool" -ItemType Directory -Force - } - - Move-Item -Path "$(System.ArtifactsDirectory)\signed\PowerShell.*" -Destination "$(System.ArtifactsDirectory)\signed\globaltool" -Force - Get-ChildItem "$(System.ArtifactsDirectory)\signed\globaltool" -Recurse - displayName: Move global tool packages to subfolder and capture - - - pwsh: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) checksum) - New-Item $packagePath -ItemType Directory -Force > $null - $srcPaths = @("$(System.ArtifactsDirectory)\finalResults", "$(System.ArtifactsDirectory)\macosPkgResults", "$(System.ArtifactsDirectory)\signed") - - $packages = Get-ChildItem -Path $srcPaths -Include *.zip, *.tar.gz, *.msi*, *.pkg, *.deb, *.rpm -Exclude "PowerShell-Symbols*" -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - - $packagePathList = Get-ChildItem $packagePath -Recurse | Select-Object -ExpandProperty FullName | Out-String - Write-Verbose -Verbose $packagePathList - - $checksums = Get-ChildItem -Path $packagePath -Exclude "SHA512SUMS" | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA512).Hash.ToLower() - - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - - $checksums | Out-File -FilePath "$packagePath\SHA512SUMS" -Force - - - $fileContent = Get-Content -Path "$packagePath\SHA512SUMS" -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - - Copy-Item -Path "$packagePath\SHA512SUMS" -Destination '$(System.ArtifactsDirectory)\signed\' -verbose - displayName: Generate checksum file for packages - - - pwsh: | - $packagePath = (Join-Path $(System.ArtifactsDirectory) checksum_gbltool) - New-Item $packagePath -ItemType Directory -Force > $null - $srcPaths = @("$(System.ArtifactsDirectory)\signed\globaltool") - $packages = Get-ChildItem -Path $srcPaths -Include *.nupkg -Recurse - $packages | ForEach-Object { Copy-Item $_.FullName -Destination $packagePath -Verbose } - - $packagePathList = Get-ChildItem $packagePath -Recurse | Select-Object -ExpandProperty FullName | Out-String - Write-Verbose -Verbose $packagePathList - - $checksums = Get-ChildItem -Path $packagePath -Exclude "SHA512SUMS" | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA512).Hash.ToLower() - - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - - $checksums | Out-File -FilePath "$packagePath\SHA512SUMS" -Force - - $fileContent = Get-Content -Path "$packagePath\SHA512SUMS" -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - - Copy-Item -Path "$packagePath\SHA512SUMS" -Destination '$(System.ArtifactsDirectory)\signed\globaltool\' -verbose - displayName: Generate checksum for global tools - - - template: upload-final-results.yml - parameters: - artifactPath: '$(System.ArtifactsDirectory)\checksum' - artifactFilter: SHA512SUMS - - - task: AzureFileCopy@4 - displayName: 'Upload NuGet packages to Azure' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\*' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-nuget' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'Upload global tool packages to Azure' - inputs: - sourcePath: '$(System.ArtifactsDirectory)\signed\globaltool\*' - azureSubscription: '$(GlobalToolSubscription)' - Destination: AzureBlob - storage: '$(GlobalToolStorageAccount)' - ContainerName: 'tool' - blobPrefix: '$(Version)' - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PackagePath)' diff --git a/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml b/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml deleted file mode 100644 index d183601a06c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-BuildJson.yml +++ /dev/null @@ -1,102 +0,0 @@ -steps: -- checkout: self - clean: true - -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: BuildInfoJson - path: '$(Pipeline.Workspace)/releasePipeline/BuildInfoJson' - -- pwsh: | - Import-Module '$(Build.SourcesDirectory)/tools/ci.psm1' - $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/BuildInfoJson/*.json" - $fileName = Split-Path $jsonFile -Leaf - - $dateTime = [datetime]::UtcNow - $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) - - $metadata = Get-Content ./tools/metadata.json | ConvertFrom-Json - $stableRelease = $metadata.StableRelease.Latest - $ltsRelease = $metadata.LTSRelease.Latest - - Write-Verbose -Verbose "Writing $jsonFile contents:" - $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw - Write-Verbose -Verbose $buildInfoJsonContent - - $buildInfo = $buildInfoJsonContent | ConvertFrom-Json - $buildInfo.ReleaseDate = $dateTime - - $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 - } else { - Set-BuildVariable -Name CopyMainBuildInfo -Value NO - } - - Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile - - ## Create 'lts.json' if it's the latest stable and also a LTS release. - - if ($fileName -eq "stable.json") { - 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 - } else { - Set-BuildVariable -Name CopyLTSBuildInfo -Value NO - } - - $releaseTag = $buildInfo.ReleaseTag - $version = $releaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version - - $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 - } - displayName: Download and Capture NuPkgs - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info JSON file Copy' - inputs: - SourcePath: '$(BuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info ''lts.json'' Copy when needed' - inputs: - SourcePath: '$(LtsBuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyLTSBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'AzureBlob build info ''Major-Minor.json'' Copy when needed' - inputs: - SourcePath: '$(VersionBuildInfoJsonFile)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: BuildInfo - condition: and(succeeded(), eq(variables['CopyVersionBuildInfo'], 'YES')) - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml b/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml deleted file mode 100644 index 64c4d1b6a24..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-CreateGitHubDraft.yml +++ /dev/null @@ -1,110 +0,0 @@ -steps: -- checkout: self - clean: true - -- download: none - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/PowerShell/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/PowerShell/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion) $(System.ArtifactsDirectory) --recursive - - $packagesPath = Get-ChildItem -Path $(System.ArtifactsDirectory)\*.deb -Recurse -File | Select-Object -First 1 -ExpandProperty DirectoryName - Write-Host "sending -- vso[task.setvariable variable=PackagesRoot]$packagesPath" - Write-Host "##vso[task.setvariable variable=PackagesRoot]$packagesPath" - - displayName: Download Azure Artifacts - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty FullName - displayName: Capture downloaded artifacts - -- pwsh: | - git clone https://$(AzureDevOpsPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools '$(Pipeline.Workspace)/tools' - displayName: Clone Internal-Tools repository - -- pwsh: | - $Path = "$(PackagesRoot)" - $OutputPath = Join-Path $Path ‘hashes.sha256’ - $srcPaths = @($Path) - $packages = Get-ChildItem -Path $srcPaths -Include * -Recurse -File - $checksums = $packages | - ForEach-Object { - Write-Verbose -Verbose "Generating checksum file for $($_.FullName)" - $packageName = $_.Name - $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower() - # the '*' before the packagename signifies it is a binary - "$hash *$packageName" - } - $checksums | Out-File -FilePath $OutputPath -Force - $fileContent = Get-Content -Path $OutputPath -Raw | Out-String - Write-Verbose -Verbose -Message $fileContent - displayName: Add sha256 hashes - -- checkout: ComplianceRepo - -- pwsh: | - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=ReleaseVersion]$releaseVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Set release version' - -- template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(PackagesRoot)' - Build_Repository_Uri: 'https://github.com/powershell/powershell.git' - displayName: PowerShell Hashes SBOM - packageName: PowerShell Artifact Hashes - packageVersion: $(ReleaseVersion) - sourceScanPath: '$(PackagesRoot)' - -- pwsh: | - Import-module '$(Pipeline.Workspace)/tools/Scripts/GitHubRelease.psm1' - $releaseVersion = '$(ReleaseTag)' -replace '^v','' - $semanticVersion = [System.Management.Automation.SemanticVersion]$releaseVersion - - $isPreview = $semanticVersion.PreReleaseLabel -ne $null - - $fileName = if ($isPreview) { - "preview.md" - } - else { - $semanticVersion.Major.ToString() + "." + $semanticVersion.Minor.ToString() + ".md" - } - - $filePath = "$env:BUILD_SOURCESDIRECTORY/PowerShell/CHANGELOG/$fileName" - Write-Verbose -Verbose "Selected Log file: $filePath" - - if (-not (Test-Path $filePath)) { - throw "$filePath not found" - } - - $changelog = Get-Content -Path $filePath - - $startPattern = "^## \[" + ([regex]::Escape($releaseVersion)) + "\]" - $endPattern = "^## \[{0}\.{1}\.{2}*" -f $semanticVersion.Major, $semanticVersion.Minor, $semanticVersion.Patch - - $clContent = $changelog | ForEach-Object { - if ($_ -match $startPattern) { $outputLine = $true } - elseif ($_ -match $endPattern) { $outputLine = $false } - if ($outputLine) { $_} - } | Out-String - - Write-Verbose -Verbose "Selected content: `n$clContent" - - Publish-ReleaseDraft -Tag '$(ReleaseTag)' -Name '$(ReleaseTag) Release of PowerShell' -Description $clContent -User PowerShell -Repository PowerShell -PackageFolder $(PackagesRoot) -Token $(GitHubReleasePat) - displayName: Publish Release Draft diff --git a/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml b/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml deleted file mode 100644 index cc6af2d8526..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-GlobalToolTest.yml +++ /dev/null @@ -1,152 +0,0 @@ -parameters: - jobName: "" - displayName: "" - imageName: "" - globalToolExeName: 'pwsh.exe' - globalToolPackageName: 'PowerShell.Windows.x64' - - -jobs: -- job: ${{ parameters.jobName }} - displayName: ${{ parameters.displayName }} - pool: - # test - vmImage: ${{ parameters.imageName }} - variables: - - group: DotNetPrivateBuildAccess - - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.nupkg' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - pwsh: | - $dotnetMetadataPath = "$(Build.SourcesDirectory)/DotnetRuntimeMetadata.json" - $dotnetMetadataJson = Get-Content $dotnetMetadataPath -Raw | ConvertFrom-Json - - # Channel is like: $Channel = "5.0.1xx-preview2" - $Channel = $dotnetMetadataJson.sdk.channel - - $sdkVersion = (Get-Content "$(Build.SourcesDirectory)/global.json" -Raw | ConvertFrom-Json).sdk.version - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - - Find-Dotnet - - if(-not (Get-PackageSource -Name 'dotnet' -ErrorAction SilentlyContinue)) - { - $nugetFeed = ([xml](Get-Content $(Build.SourcesDirectory)/nuget.config -Raw)).Configuration.packagesources.add | Where-Object { $_.Key -eq 'dotnet' } | Select-Object -ExpandProperty Value - if ($nugetFeed) { - Register-PackageSource -Name 'dotnet' -Location $nugetFeed -ProviderName NuGet - Write-Verbose -Message "Register new package source 'dotnet'" -verbose - } - } - - ## Install latest version from the channel - - #Install-Dotnet -Channel "$Channel" -Version $sdkVersion - Start-PSBootstrap - - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $branch = $ENV:BUILD_SOURCEBRANCH - $version = $branch -replace '^.*(release[-/])v' - $vstsCommandString = "vso[task.setvariable variable=PowerShellVersion]$version" - Write-Verbose -Message "Version is $version" -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Set PowerShell Version - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - - $toolPath = New-Item -ItemType Directory "$(System.DefaultWorkingDirectory)/toolPath" | Select-Object -ExpandProperty FullName - - dotnet tool install --add-source "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults" --tool-path $toolPath --version '$(PowerShellVersion)' '${{ parameters.globalToolPackageName }}' - - Get-ChildItem -Path $toolPath - - displayName: Install global tool - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" - - if (-not (Test-Path $toolPath)) - { - throw "Tool is not installed at $toolPath" - } - else - { - Write-Verbose -Verbose "Tool found at: $toolPath" - } - displayName: Validate tool is installed - - - pwsh: | - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - - $exeName = if ($IsWindows) { "pwsh.exe" } else { "pwsh" } - - $toolPath = "$(System.DefaultWorkingDirectory)/toolPath/${{ parameters.globalToolExeName }}" - - $source = (get-command -Type Application -Name dotnet | Select-Object -First 1 -ExpandProperty source) - $target = (Get-ChildItem $source).target - - # If we find a symbolic link for dotnet, then we need to split the filename off the target. - if ($target) { - Write-Verbose -Verbose "Splitting target: $target" - $target = Split-Path $target - } - - Write-Verbose -Verbose "target is set as $target" - - $env:DOTNET_ROOT = (resolve-path -Path (Join-Path (split-path $source) $target)).ProviderPath - - Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" - Get-ChildItem $env:DOTNET_ROOT - - $versionFound = & $toolPath -c '$PSVersionTable.PSVersion.ToString()' - - if ( '$(PowerShellVersion)' -ne $versionFound) - { - throw "Expected version of global tool not found. Installed version is $versionFound" - } - else - { - write-verbose -verbose "Found expected version: $versionFound" - } - - $dateYear = & $toolPath -c '(Get-Date).Year' - - if ( $dateYear -ne [DateTime]::Now.Year) - { - throw "Get-Date returned incorrect year: $dateYear" - } - else - { - write-verbose -verbose "Got expected year: $dateYear" - } - displayName: Basic validation - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml b/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml deleted file mode 100644 index 65d5ea50191..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-MakeContainerPublic.yml +++ /dev/null @@ -1,20 +0,0 @@ -steps: -- download: none - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - az login --service-principal -u $(az_url) -p $(az_key) --tenant $(az_name) - displayName: az login - -- pwsh: | - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion) --public-access blob - displayName: Make container public - -- pwsh: | - az storage container set-permission --account-name $(StorageAccount) --name $(azureVersion)-gc --public-access blob - displayName: Make guest configuration miminal package container public - -- pwsh: | - az logout - displayName: az logout diff --git a/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml b/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml deleted file mode 100644 index a9591b2d251..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-MsixBundle.yml +++ /dev/null @@ -1,81 +0,0 @@ -jobs: -- job: CreateMSIXBundle - displayName: Create .msixbundle file - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: msixTools - - group: 'Azure Blob variable group' - - steps: - - template: release-SetReleaseTagAndContainerName.yml - - - task: DownloadPipelineArtifact@2 - retryCountOnTaskFailure: 2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.msix' - path: '$(Pipeline.Workspace)\releasePipeline\msix' - - - pwsh: | - $cmd = Get-Command makeappx.exe -ErrorAction Ignore - if ($cmd) { - Write-Verbose -Verbose 'makeappx available in PATH' - $exePath = $cmd.Source - } else { - $toolsDir = '$(Pipeline.Workspace)\releasePipeline\tools' - New-Item $toolsDir -Type Directory -Force > $null - Invoke-RestMethod -Uri '$(makeappUrl)' -OutFile "$toolsDir\makeappx.zip" - Expand-Archive "$toolsDir\makeappx.zip" -DestinationPath "$toolsDir\makeappx" -Force - $exePath = "$toolsDir\makeappx\makeappx.exe" - - Write-Verbose -Verbose 'makeappx was installed:' - Get-ChildItem -Path $toolsDir -Recurse - } - - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install makeappx tool - retryCountOnTaskFailure: 1 - - - pwsh: | - $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' - $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 - $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Create MsixBundle - retryCountOnTaskFailure: 1 - - - task: AzureFileCopy@4 - displayName: 'Upload MSIX Bundle package to Az Blob' - retryCountOnTaskFailure: 2 - inputs: - SourcePath: '$(BundleDir)/*.msixbundle' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: succeeded() diff --git a/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml b/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml deleted file mode 100644 index 0333c77b88c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-PublishPackageMsftCom.yml +++ /dev/null @@ -1,57 +0,0 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -steps: -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $packageVersion = '$(ReleaseTag)'.ToLowerInvariant() -replace '^v','' - $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Set Package version - -- pwsh: | - $branch = 'main-mirror' - $gitArgs = "clone", - "--verbose", - "--branch", - "$branch", - "https://$(AzureDevOpsPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", - '$(Pipeline.Workspace)/tools' - $gitArgs | Write-Verbose -Verbose - git $gitArgs - displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub - -- task: PipAuthenticate@1 - inputs: - artifactFeeds: 'pmc' - pythonDownloadServiceConnections: pmcDownload - -- pwsh: | - pip install pmc-cli - - $newPath = (resolve-path '~/.local/bin').providerpath - $vstsCommandString = "vso[task.setvariable variable=PATH]${env:PATH}:$newPath" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: Install pmc cli - -- pwsh: | - $metadata = Get-Content -Path "$(Build.SourcesDirectory)/tools/metadata.json" -Raw | ConvertFrom-Json - $params = @{ - ReleaseTag = "$(ReleaseTag)" - AadClientId = "$(PmcCliClientID)" - BlobFolderName = "$(AzureVersion)" - LTS = $metadata.LTSRelease.Latest - ForProduction = $true - SkipPublish = $${{ parameters.skipPublish }} - MappingFilePath = '$(System.DefaultWorkingDirectory)/tools/packages.microsoft.com/mapping.json' - } - - $params | Out-String -width 9999 -Stream | write-Verbose -Verbose - - & '$(Pipeline.Workspace)/tools/packages.microsoft.com-v4/releaseLinuxPackages.ps1' @params - displayName: Run release script diff --git a/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml b/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml deleted file mode 100644 index db2cc86e259..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-PublishSymbols.yml +++ /dev/null @@ -1,51 +0,0 @@ -steps: -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: results - path: '$(Pipeline.Workspace)\results' - itemPattern: | - **/* - !**/*signed.zip - -- pwsh: | - Write-Verbose -Verbose "Enumerating $(Pipeline.Workspace)\results" - $downloadedArtifacts = Get-ChildItem -Recurse "$(Pipeline.Workspace)\results" - $downloadedArtifacts - $expandedRoot = New-Item -Path "$(Pipeline.Workspace)/expanded" -ItemType Directory -Verbose - $symbolsRoot = New-Item -Path "$(Pipeline.Workspace)/symbols" -ItemType Directory -Verbose - - $downloadedArtifacts | ForEach-Object { - $destFolder = New-Item -Path "$expandedRoot/$($_.BaseName)/" -ItemType Directory -Verbose - Expand-Archive -Path $_.FullName -DestinationPath $destFolder -Force - - $symbolsZipFile = Join-Path -Path $destFolder -ChildPath "symbols.zip" - $symbolZipFileContents = New-Item -Path "$destFolder/Symbols-$($_.BaseName)" -ItemType Directory -Verbose - Expand-Archive -Path $symbolsZipFile -DestinationPath $symbolZipFileContents -Force - - $symbolsToPublish = New-Item -Path "$symbolsRoot/$($_.BaseName)" -ItemType Directory -Verbose - - Get-ChildItem -Path $symbolZipFileContents -Recurse -Filter '*.pdb' | ForEach-Object { - Copy-Item -Path $_.FullName -Destination $symbolsToPublish -Verbose - } - } - - Write-Verbose -Verbose "Enumerating $symbolsRoot" - Get-ChildItem -Path $symbolsRoot -Recurse - $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$symbolsRoot" - Write-Verbose -Message "$vstsCommandString" -Verbose - Write-Host -Object "##$vstsCommandString" - displayName: Expand and capture symbols folders -- task: PublishSymbols@2 - inputs: - symbolsFolder: '$(SymbolsPath)' - searchPattern: '**/*.pdb' - indexSources: false - publishSymbols: true - symbolServerType: teamServices - detailedLog: true diff --git a/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml b/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml deleted file mode 100644 index 33a72f56bbb..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ReleaseToNuGet.yml +++ /dev/null @@ -1,56 +0,0 @@ -parameters: - - name: skipPublish - default: false - type: boolean - -steps: -- task: DownloadPipelineArtifact@2 - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/*.nupkg' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - -- task: DownloadPipelineArtifact@2 - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: metadata - path: '$(Pipeline.Workspace)/releasePipeline/metadata' - -- pwsh: | - #Exclude all global tool packages. Their names start with 'PowerShell.' - $null = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/release" - Copy-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/*.nupkg" -Destination "$(Pipeline.Workspace)/release" -Exclude "PowerShell.*.nupkg" -Force -Verbose - - $releaseVersion = Get-Content "$ENV:PIPELINE_WORKSPACE/releasePipeline/metadata/release.json" | ConvertFrom-Json | Select-Object -ExpandProperty 'ReleaseVersion' - $globalToolPath = "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/PowerShell.$releaseVersion.nupkg" - - if ($releaseVersion -notlike '*-*') { - # Copy the global tool package for stable releases - Copy-Item $globalToolPath -Destination "$(Pipeline.Workspace)/release" - } - - Get-ChildItem "$(Pipeline.Workspace)/release" -recurse - displayName: Download and capture nupkgs - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - -- task: NuGetCommand@2 - displayName: 'NuGet push' - condition: and(eq('${{ parameters.skipPublish }}', 'false'), succeeded()) - inputs: - command: push - packagesToPush: '$(Pipeline.Workspace)/release/*.nupkg' - nuGetFeedType: external - publishFeedCredentials: PowerShellNuGetOrgPush diff --git a/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml b/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml index 2279c3325e1..7ddcb0a136c 100644 --- a/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml +++ b/tools/releaseBuild/azureDevOps/templates/release-SDKTests.yml @@ -10,7 +10,8 @@ jobs: # testing vmImage: ${{ parameters.imageName }} variables: - - group: AzDevOpsArtifacts + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess steps: - checkout: self @@ -39,9 +40,12 @@ jobs: artifact: metadata path: '$(Pipeline.Workspace)/releasePipeline/metadata' + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(Build.SourcesDirectory) + - pwsh: | Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - New-NugetConfigFile -NugetFeedUrl $(PSInternalNugetFeed) -UserName $(PSInternalNugetFeedUserName) -ClearTextPAT $(PSInternalNugetFeedPAT) -FeedName AzDevOpsFeed -Destination '$(Build.SourcesDirectory)/test/hosting' Write-Verbose -Verbose "Capture hosting folder files" Get-ChildItem '$(Build.SourcesDirectory)/test/hosting' @@ -97,7 +101,6 @@ jobs: displayName: Install .NET env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - pwsh: | @@ -136,7 +139,6 @@ jobs: displayName: Restore and execute tests env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - task: PublishTestResults@2 diff --git a/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml b/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml deleted file mode 100644 index fa42064602e..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-UpdateDepsJson.yml +++ /dev/null @@ -1,71 +0,0 @@ -jobs: -- job: UpdateDepsFiles - displayName: Update deps files - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - variables: - - group: 'Azure Blob variable group' - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '**/PowerShell*-win-x64.zip' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: BuildInfoJson - path: '$(Pipeline.Workspace)/releasePipeline/BuildInfoJson' - - - pwsh: | - $fileName = (Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/BuildInfoJson/*.json").BaseName - if ($fileName -notin 'stable','preview') - { - throw "Unexpected fileName: $fileName" - } - - $vstsCommand = "vso[task.setvariable variable=BlobPrefix]$fileName" - Write-Verbose -Verbose $vstsCommand - Write-Host "##$vstsCommand" - displayName: Determine container name - - - pwsh: | - $zipFile = Get-Item "$ENV:PIPELINE_WORKSPACE/releasePipeline/finalResults/PowerShell*-win-x64.zip" -Exclude *-symbols-* - Write-Verbose -Verbose "zipFile: $zipFile" - Expand-Archive -Path $zipFile -Destination "$ENV:PIPELINE_WORKSPACE/expanded" - - $pwshDepsFile = Get-Item "$ENV:PIPELINE_WORKSPACE/expanded/pwsh.deps.json" - $vstsCommand = "vso[task.setvariable variable=FileToUpload]$pwshDepsFile" - Write-Verbose -Verbose $vstsCommand - Write-Host "##$vstsCommand" - displayName: Determine file to upload - - - task: AzureFileCopy@4 - displayName: 'AzureBlob pwsh.deps.json file Copy' - inputs: - SourcePath: '$(FileToUpload)' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: ps-deps-json - blobPrefix: '$(BlobPrefix)' - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml deleted file mode 100644 index 1aa88af9143..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidateFxdPackage.yml +++ /dev/null @@ -1,93 +0,0 @@ -parameters: - jobName: "" - displayName: "" - imageName: "" - packageNamePattern: "" - use1ES: false - -jobs: -- job: ${{ parameters.jobName }} - displayName: ${{ parameters.displayName }} - variables: - - group: DotNetPrivateBuildAccess - pool: - ${{ if eq(parameters.use1ES, 'false') }}: - vmImage: ${{ parameters.imageName }} - ${{ else }}: - name: 'PS-MSCodeHub-ARM' # add ImageOverride to select image - steps: - - checkout: self - clean: true - - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - patterns: '${{ parameters.packageNamePattern }}' - path: '$(Pipeline.Workspace)/releasePipeline/finalResults' - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Start-PSBootstrap - Write-Verbose -Message "Installing .NET SDK completed." -Verbose - displayName: Install .NET - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults' -Recurse - displayName: Capture downloaded package - - - pwsh: | - $destPath = New-Item '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' -ItemType Directory - $packageNameFilter = '${{ parameters.packageNamePattern }}' - - if ($packageNameFilter.EndsWith('tar.gz')) { - $package = @(Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults/*.tar.gz') - Write-Verbose -Verbose "Package: $package" - if ($package.Count -ne 1) { - throw 'Only 1 package was expected.' - } - tar -xvf $package.FullName -C $destPath - } - else { - $package = @(Get-ChildItem -Path '$(Pipeline.Workspace)/releasePipeline/finalResults/*.zip') - Write-Verbose -Verbose "Package: $package" - if ($package.Count -ne 1) { - throw 'Only 1 package was expected.' - } - Expand-Archive -Path $package.FullName -Destination "$destPath" -Verbose - } - displayName: Expand fxd package - - - pwsh: | - $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - Import-Module "$(Build.SourcesDirectory)/build.psm1" -Force - Find-Dotnet -SetDotnetRoot - Write-Verbose -Verbose "DOTNET_ROOT: $env:DOTNET_ROOT" - Write-Verbose -Verbose "Check dotnet install" - dotnet --info - Write-Verbose -Verbose "Start test" - $packageNameFilter = '${{ parameters.packageNamePattern }}' - $pwshExeName = if ($packageNameFilter.EndsWith('tar.gz')) { 'pwsh' } else { 'pwsh.exe' } - $pwshPath = Join-Path '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' $pwshExeName - - if ($IsLinux) { - chmod u+x $pwshPath - } - - $pwshDllPath = Join-Path '$(Pipeline.Workspace)/releasePipeline/finalResults/fxd' 'pwsh.dll' - - $actualOutput = & dotnet $pwshDllPath -c 'Start-ThreadJob -ScriptBlock { "1" } | Wait-Job | Receive-Job' - Write-Verbose -Verbose "Actual output: $actualOutput" - if ($actualOutput -ne 1) { - throw "Actual output is not as expected" - } - displayName: Test package diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml deleted file mode 100644 index 3fd560cbd00..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageBOM.yml +++ /dev/null @@ -1,49 +0,0 @@ -steps: -- checkout: self - clean: true - -- pwsh: | - Get-ChildItem ENV: - displayName: Capture environment - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks - Write-Host $name - Write-Host "##vso[build.updatebuildnumber]$name" - displayName: Set Release Name - -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: PowerShellCore - pipeline: '696' - preferTriggeringPipeline: true - runVersion: latestFromBranch - runBranch: '$(Build.SourceBranch)' - artifact: finalResults - path: $(System.ArtifactsDirectory) - - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name - displayName: Capture Artifact Listing - -- pwsh: | - Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 - displayName: Install Pester - condition: succeededOrFailed() - -- pwsh: | - Import-module './build.psm1' - Import-module './tools/packaging' - $env:PACKAGE_FOLDER = '$(System.ArtifactsDirectory)' - $path = Join-Path -Path $pwd -ChildPath './packageReleaseTests.xml' - $results = invoke-pester -Script './tools/packaging/releaseTests' -OutputFile $path -OutputFormat NUnitXml -PassThru - Write-Host "##vso[results.publish type=NUnit;mergeResults=true;runTitle=Package Release Tests;publishRunAttachments=true;resultFiles=$path;]" - if($results.TotalCount -eq 0 -or $results.FailedCount -gt 0) - { - throw "Package Release Tests failed" - } - displayName: Run packaging release tests diff --git a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml b/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml deleted file mode 100644 index 8e41fbc4a55..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/release-ValidatePackageNames.yml +++ /dev/null @@ -1,93 +0,0 @@ -steps: -- pwsh: | - Get-ChildItem ENV: - displayName: Capture environment - -- template: release-SetReleaseTagAndContainerName.yml - -- pwsh: | - $name = "{0}_{1:x}" -f '$(releaseTag)', (Get-Date).Ticks - Write-Host $name - Write-Host "##vso[build.updatebuildnumber]$name" - displayName: Set Release Name - -- pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/* $(System.ArtifactsDirectory) --recursive - - displayName: Download Azure Artifacts - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - -- pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name - displayName: Capture Artifact Listing - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.rpm | ForEach-Object { - if($_.Name -notmatch 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1.(rh|cm).(x86_64|aarch64)\.rpm') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate RPM package names - -- pwsh: | - $message = @() - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.tar.gz | ForEach-Object { - if($_.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)') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Tar.Gz Package Names - -- 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') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate PKG Package Names - -- 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}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Zip and MSI Package Names - -- 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') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - if($message.count -gt 0){throw ($message | out-string)} - displayName: Validate Deb Package Names diff --git a/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml b/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml deleted file mode 100644 index a584e15e27c..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/sign-build-file.yml +++ /dev/null @@ -1,328 +0,0 @@ -steps: -- pwsh: | - $platform = '$(runtime)' -match '^linux' ? 'linux' : 'windows' - $vstsCommandString = "vso[task.setvariable variable=ArtifactPlatform]$platform" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Set artifact platform - -- task: DownloadPipelineArtifact@2 - inputs: - artifactName: '$(unsignedBuildArtifactContainer)' - itemPattern: '$(unsignedBuildArtifactName)' - -- pwsh: | - Get-ChildItem "$(Pipeline.Workspace)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - -- checkout: self - clean: true - path: $(repoFolder) - -- template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - -- template: cloneToOfficialPath.yml - -- pwsh: | - $zipFileFilter = '$(unsignedBuildArtifactName)' - $zipFileFilter = $zipFileFilter.Replace('**/', '') - - Write-Verbose -Verbose -Message "zipFileFilter = $zipFileFilter" - - Write-Verbose -Verbose -Message "Looking for $(Pipeline.Workspace)\$(unsignedBuildArtifactName)" - - $zipFilePath = Get-ChildItem -Path '$(Pipeline.Workspace)\$(unsignedBuildArtifactName)' -recurse - - if (-not (Test-Path $zipFilePath)) - { - throw "zip file not found: $zipfilePath" - } - - if ($zipFilePath.Count -ne 1) { - Write-Verbose "zip filename" -verbose - $zipFilePath | Out-String | Write-Verbose -Verbose - throw 'multiple zip files found when 1 was expected' - } - - $expandedFolderName = [System.io.path]::GetFileNameWithoutExtension($zipfilePath) - $expandedFolderPath = Join-Path '$(Pipeline.Workspace)' 'expanded' $expandedFolderName - - Write-Verbose -Verbose -Message "Expaning $zipFilePath to $expandedFolderPath" - - New-Item -Path $expandedFolderPath -ItemType Directory - Expand-Archive -Path $zipFilePath -DestinationPath $expandedFolderPath - - if (-not (Test-Path $expandedFolderPath\pwsh.exe) ) { - throw 'zip did not expand as expected' - } - else { - $vstsCommandString = "vso[task.setvariable variable=BinPath]$expandedFolderPath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } - - displayName: Expand zip packages - condition: eq(variables['ArtifactPlatform'], 'windows') - -- pwsh: | - $tarPackageName = '$(unsignedBuildArtifactName)' - - Write-Verbose -Verbose -Message "tarPackageName = $tarPackageName" - - $tarPackagePath = Join-Path '$(Pipeline.Workspace)' $tarPackageName - - Write-Verbose -Verbose -Message "Looking for: $tarPackagePath" - - $expandedPathFolderName = $tarPackageName -replace '.tar.gz', '' - $expandedFolderPath = Join-Path '$(Pipeline.Workspace)' 'expanded' $expandedPathFolderName - - if (-not (Test-Path $tarPackagePath)) - { - throw "tar file not found: $tarPackagePath" - } - - Write-Verbose -Verbose -Message "Expanding $tarPackagePath to $expandedFolderPath" - - New-Item -Path $expandedFolderPath -ItemType Directory - tar -xf $tarPackagePath -C $expandedFolderPath - - if (-not (Test-Path $expandedFolderPath/pwsh) ) { - throw 'tar.gz did not expand as expected' - } - else { - $vstsCommandString = "vso[task.setvariable variable=BinPath]$expandedFolderPath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } - - Write-Verbose -Verbose "File permisions after expanding" - Get-ChildItem -Path "$expandedFolderPath/pwsh" | Select-Object -Property 'unixmode', 'size', 'name' - displayName: Expand tar.gz packages - condition: eq(variables['ArtifactPlatform'], 'linux') - -- template: insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - -- pwsh: | - Set-Location $env:POWERSHELLROOT - import-module "$env:POWERSHELLROOT/build.psm1" - Sync-PSTags -AddRemoteIfMissing - displayName: SyncTags - condition: and(succeeded(), ne(variables['SkipBuild'], 'true')) - -- checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - -- template: shouldSign.yml - -- pwsh: | - $fullSymbolsFolder = '$(BinPath)' - Write-Verbose -Verbose "fullSymbolsFolder == $fullSymbolsFolder" - - Get-ChildItem -Recurse $fullSymbolsFolder | out-string | Write-Verbose -Verbose - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - - if ((Test-Path -Path $filesToSignDirectory)) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - - if ((Test-Path -Path $signedFilesDirectory)) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - } - - ## Windows only modules - - if('$(ArtifactPlatform)' -eq 'windows') { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh.exe" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - } - } - else { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh" = "" - } - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: 'Prepare files to be signed' - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Authenticode sign our binaries - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = '$(BinPath)' - Write-Verbose -Verbose -Message "BuildPath: $BuildPath" - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $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 - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - if (Test-Path $filesToSignDirectory) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force -Verbose - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - if (Test-Path $signedFilesDirectory) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force -Verbose - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - Write-Verbose -Verbose -Message "relativePath: $relativePath" - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - Write-Verbose -Verbose -Message "targetDirectory: $targetDirectory" - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force -Verbose - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - -- pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - Import-Module '$(PowerShellRoot)/build.psm1' -Force - Import-Module '$(PowerShellRoot)/tools/packaging' -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = '$(BinPath)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - $uploadFolder = '$(BinPath)' - $containerName = '$(signedArtifactContainer)' - - Write-Verbose -Verbose "File permissions after signing" - Get-ChildItem $uploadFolder\pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - $uploadTarFilePath = Join-Path '$(System.ArtifactsDirectory)' '$(signedBuildArtifactName)' - Write-Verbose -Verbose -Message "Creating tar.gz - $uploadTarFilePath" - tar -czvf $uploadTarFilePath -C $uploadFolder * - - Get-ChildItem '$(System.ArtifactsDirectory)' | Out-String | Write-Verbose -Verbose - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadTarFilePath" - displayName: Upload signed tar.gz files to artifacts - condition: eq(variables['ArtifactPlatform'], 'linux') - retryCountOnTaskFailure: 2 - - -- pwsh: | - $uploadFolder = '$(BinPath)' - $containerName = '$(signedArtifactContainer)' - - Get-ChildItem $uploadFolder -Recurse | Out-String | Write-Verbose -Verbose - - $uploadZipFilePath = Join-Path '$(System.ArtifactsDirectory)' 'PowerShell-$(Version)$(signedBuildArtifactName)' - Write-Verbose -Verbose -Message "Creating zip - $uploadZipFilePath" - Compress-Archive -Path $uploadFolder/* -DestinationPath $uploadZipFilePath -Verbose - - Get-ChildItem '$(System.ArtifactsDirectory)' | Out-String | Write-Verbose -Verbose - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadZipFilePath" - displayName: Upload signed zip files to artifacts - condition: eq(variables['ArtifactPlatform'], 'windows') - retryCountOnTaskFailure: 2 - - -- template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml b/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml deleted file mode 100644 index a7c7c640ce7..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/signBuildFiles.yml +++ /dev/null @@ -1,189 +0,0 @@ -parameters: - binLocation: '' - buildPrefixName: '' - addWindowsModules: 'false' - -steps: -- pwsh: | - $fullSymbolsFolder = Join-Path $(System.ArtifactsDirectory) "${{ parameters.binLocation }}" - - Write-Verbose -Verbose "fullSymbolsFolder == $fullSymbolsFolder" - - Get-ChildItem -Recurse $fullSymbolsFolder | out-string | Write-Verbose -Verbose - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - - if ((Test-Path -Path $filesToSignDirectory)) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - - if ((Test-Path -Path $signedFilesDirectory)) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - } - - ## Windows only modules - - if('${{ parameters.addWindowsModules }}' -ne 'false') { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh.exe" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - } - } - else { - $itemsToCopy += @{ - "$($fullSymbolsFolder)\pwsh" = "" - } - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: '${{ parameters.buildPrefixName }} - Prepare files to be signed' - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: ${{ parameters.buildPrefixName }} - Authenticode - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = Join-Path $(System.ArtifactsDirectory) '${{ parameters.binLocation }}' - Write-Verbose -Verbose -Message "BuildPath: $BuildPath" - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $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 - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - if (Test-Path $filesToSignDirectory) { - Remove-Item -Path $filesToSignDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force -Verbose - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - if (Test-Path $signedFilesDirectory) { - Remove-Item -Path $signedFilesDirectory -Recurse -Force - } - - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force -Verbose - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - Write-Verbose -Verbose -Message "relativePath: $relativePath" - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - Write-Verbose -Verbose -Message "targetDirectory: $targetDirectory" - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force -Verbose - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: ${{ parameters.buildPrefixName }} - Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - -- pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: ${{ parameters.buildPrefixName }} - Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = Join-Path $(System.ArtifactsDirectory) '${{ parameters.binLocation }}' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: ${{ parameters.buildPrefixName }} - Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - -- pwsh: | - $uploadFolder = '$(System.ArtifactsDirectory)/${{ parameters.binLocation }}' - $containerName = 'authenticode-signed' - - Write-Verbose -Verbose "File permissions after signing" - Get-ChildItem $uploadFolder\pwsh | Select-Object -Property 'unixmode', 'size', 'name' - - $uploadTarFilePath = '$(System.ArtifactsDirectory)/${{ parameters.binLocation }}.tar.gz' - Write-Verbose -Verbose -Message "Creating tar.gz - $uploadTarFilePath" - tar -czvf $uploadTarFilePath -C $uploadFolder * - - Write-Host "##vso[artifact.upload containerfolder=$containerName;artifactname=$containerName]$uploadTarFilePath" - displayName: ${{ parameters.buildPrefixName }} - Upload signed files to artifacts - retryCountOnTaskFailure: 2 - diff --git a/tools/releaseBuild/azureDevOps/templates/step/finalize.yml b/tools/releaseBuild/azureDevOps/templates/step/finalize.yml deleted file mode 100644 index 72a677fec9a..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/step/finalize.yml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - pwsh: | - throw "Jobs with an Issue will not work for release. Please fix the issue and try again." - displayName: Check for SucceededWithIssues - condition: eq(variables['Agent.JobStatus'],'SucceededWithIssues') diff --git a/tools/releaseBuild/azureDevOps/templates/testartifacts.yml b/tools/releaseBuild/azureDevOps/templates/testartifacts.yml deleted file mode 100644 index 09f5c5bce5d..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/testartifacts.yml +++ /dev/null @@ -1,128 +0,0 @@ -jobs: -- job: build_testartifacts_win - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - displayName: Build windows test artifacts - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(Build.SourcesDirectory) - - - pwsh: | - Import-Module ./build.psm1 - Start-PSBootstrap - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Import-Module ./build.psm1 - - function BuildTestPackage([string] $runtime) - { - Write-Verbose -Verbose "Starting to build package for $runtime" - - New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime - - if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) - { - throw "Test Package was not found at: $(System.ArtifactsDirectory)" - } - - switch ($runtime) - { - win7-x64 { $packageName = "TestPackage-win-x64.zip" } - win7-x86 { $packageName = "TestPackage-win-x86.zip" } - win-arm64 { $packageName = "TestPackage-win-arm64.zip" } - } - - Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName - Write-Host "##vso[artifact.upload containerfolder=testArtifacts;artifactname=testArtifacts]$(System.ArtifactsDirectory)/$packageName" - } - - BuildTestPackage -runtime win7-x64 - BuildTestPackage -runtime win7-x86 - BuildTestPackage -runtime win-arm64 - - displayName: Build test package and upload - retryCountOnTaskFailure: 1 - -- job: build_testartifacts_nonwin - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - group: DotNetPrivateBuildAccess - displayName: Build non-windows test artifacts - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMSUbuntu20.04-Secure - steps: - - checkout: self - clean: true - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(Build.SourcesDirectory) - - - pwsh: | - Import-Module ./build.psm1 - Start-PSBootstrap - displayName: Bootstrap - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Import-Module ./build.psm1 - - function BuildTestPackage([string] $runtime) - { - Write-Verbose -Verbose "Starting to build package for $runtime" - - New-TestPackage -Destination $(System.ArtifactsDirectory) -Runtime $runtime - - if (-not (Test-Path $(System.ArtifactsDirectory)/TestPackage.zip)) - { - throw "Test Package was not found at: $(System.ArtifactsDirectory)" - } - - switch ($runtime) - { - linux-x64 { $packageName = "TestPackage-linux-x64.zip" } - linux-arm { $packageName = "TestPackage-linux-arm.zip" } - linux-arm64 { $packageName = "TestPackage-linux-arm64.zip" } - osx-x64 { $packageName = "TestPackage-macOS.zip" } - linux-musl-x64 { $packageName = "TestPackage-alpine-x64.zip"} - } - - Rename-Item $(System.ArtifactsDirectory)/TestPackage.zip $packageName - Write-Host "##vso[artifact.upload containerfolder=testArtifacts;artifactname=testArtifacts]$(System.ArtifactsDirectory)/$packageName" - } - - BuildTestPackage -runtime linux-x64 - BuildTestPackage -runtime linux-arm - BuildTestPackage -runtime linux-arm64 - BuildTestPackage -runtime osx-x64 - BuildTestPackage -runtime linux-musl-x64 - - displayName: Build test package and upload - retryCountOnTaskFailure: 1 - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml b/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml deleted file mode 100644 index 596b61fb6ed..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/upload-final-results.yml +++ /dev/null @@ -1,17 +0,0 @@ -parameters: - artifactPath: - artifactFilter: '*' - condition: succeeded() - artifactName: finalResults - -steps: - - powershell: | - Get-ChildItem -Path '${{ parameters.artifactPath }}' -Recurse -File -filter '${{ parameters.artifactFilter }}' -ErrorAction SilentlyContinue | - Select-Object -ExpandProperty FullName | - ForEach-Object { - Write-Host "##vso[artifact.upload containerfolder=${{ parameters.artifactName }};artifactname=${{ parameters.artifactName }}]$_" - } - displayName: Upload ${{ parameters.artifactName }} Artifacts ${{ parameters.artifactFilter }} from ${{ parameters.artifactPath }} - condition: ${{ parameters.condition }} - retryCountOnTaskFailure: 2 - diff --git a/tools/releaseBuild/azureDevOps/templates/upload.yml b/tools/releaseBuild/azureDevOps/templates/upload.yml deleted file mode 100644 index c745a02c2a4..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/upload.yml +++ /dev/null @@ -1,83 +0,0 @@ -parameters: - architecture: x86 - version: 6.2.0 - msi: yes - msix: yes - pdb: no - -steps: -- template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\signed - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}*.zip - -- task: AzureFileCopy@4 - displayName: 'upload signed zip to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.zip' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - resourceGroup: '$(StorageResourceGroup)' - condition: succeeded() - retryCountOnTaskFailure: 2 - -- task: AzureFileCopy@4 - displayName: 'upload signed min-size package (for Guest Config) to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}-gc.zip' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-gc' - resourceGroup: '$(StorageResourceGroup)' - condition: and(eq('${{ parameters.architecture }}', 'x64'), succeeded()) - retryCountOnTaskFailure: 2 - -- template: upload-final-results.yml - parameters: - artifactPath: $(System.ArtifactsDirectory)\signedPackages - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.exe - condition: and(succeeded(), eq('${{ parameters.msi }}', 'yes')) - -- task: AzureFileCopy@4 - displayName: 'upload signed exe to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(System.ArtifactsDirectory)\signedPackages\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.exe' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: and(succeeded(), eq('${{ parameters.msi }}', 'yes')) - retryCountOnTaskFailure: 2 - -# Disable upload task as the symbols package is not currently used and we want to avoid publishing this in releases -#- task: AzureFileCopy@4 -# displayName: 'upload pbd zip to Azure - ${{ parameters.architecture }}' -# inputs: -# SourcePath: '$(System.ArtifactsDirectory)\signed\PowerShell-Symbols-${{ parameters.version }}-win-${{ parameters.architecture }}.zip' -# azureSubscription: '$(AzureFileCopySubscription)' -# Destination: AzureBlob -# storage: '$(StorageAccount)' -# ContainerName: '$(AzureVersion)' -# condition: and(succeeded(), eq('${{ parameters.pdb }}', 'yes')) - -- template: upload-final-results.yml - parameters: - artifactPath: $(Build.StagingDirectory)\signedPackages - artifactFilter: PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.msix - condition: and(succeeded(), eq('${{ parameters.msix }}', 'yes')) - -- task: AzureFileCopy@4 - displayName: 'upload signed msix to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\PowerShell-${{ parameters.version }}-win-${{ parameters.architecture }}.msix' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)-private' - resourceGroup: '$(StorageResourceGroup)' - condition: and(succeeded(), eq('${{ parameters.msix }}', 'yes'), eq(variables['SHOULD_SIGN'], 'true')) - retryCountOnTaskFailure: 2 diff --git a/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml b/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml deleted file mode 100644 index 83779c75aa0..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/vpackReleaseJob.yml +++ /dev/null @@ -1,113 +0,0 @@ -parameters: - architecture: x64 - -jobs: -- job: vpack_${{ parameters.architecture }} - variables: - - group: vPack - - group: ReleasePipelineSecrets - - displayName: Build and Publish VPack - ${{ parameters.architecture }} - condition: succeeded() - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - steps: - - checkout: self - clean: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.ToolsDirectory)/dotnet - - - template: ./SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - Install-AzCopy - displayName: Install AzCopy - retryCountOnTaskFailure: 2 - - - pwsh: | - Import-module '$(BUILD.SOURCESDIRECTORY)/build.psm1' - $azcopy = Find-AzCopy - Write-Verbose -Verbose "Found AzCopy: $azcopy" - - Write-Host "running: $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory)" - - & $azcopy cp https://$(StorageAccount).blob.core.windows.net/$(AzureVersion)/PowerShell-$(Version)-win-${{ parameters.architecture }}.zip $(System.ArtifactsDirectory) - displayName: 'Download Azure Artifacts' - retryCountOnTaskFailure: 2 - env: - AZCOPY_AUTO_LOGIN_TYPE: MSI - - - pwsh: 'Get-ChildItem $(System.ArtifactsDirectory)\* -recurse | Select-Object -ExpandProperty Name' - displayName: 'Capture Artifact Listing' - - - 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}') - { - $messageInstance = "$($_.Name) is not a valid package name" - $message += $messageInstance - Write-Warning $messageInstance - } - } - - if($message.count -gt 0){throw ($message | out-string)} - displayName: 'Validate Zip and MSI Package Names' - - - pwsh: | - Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -include *.zip, *.msi | ForEach-Object { - if($_.Name -match 'PowerShell-\d+\.\d+\.\d+\-([a-z]*.\d+\-)?win\-(${{ parameters.architecture }})\.(zip){1}') - { - $destDir = "$(System.ArtifactsDirectory)\vpack${{ parameters.architecture }}" - $null = new-item -ItemType Directory -Path $destDir - Expand-Archive -Path $_.FullName -DestinationPath $destDir - $vstsCommandString = "vso[task.setvariable variable=vpackDir]$destDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - } - } - displayName: 'Extract Zip' - - - pwsh: | - $vpackVersion = '$(version)' - - if('$(VPackPublishOverride)' -ne '' -and '$(VPackPublishOverride)' -ne 'None' ) - { - Write-Host "Using VPackPublishOverride varabile" - $vpackVersion = '$(VPackPublishOverride)' - } - - $vstsCommandString = "vso[task.setvariable variable=vpackVersion]$vpackVersion" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Set vpackVersion' - - - pwsh: | - Get-ChildItem -Path env: - displayName: Capture Environment - condition: succeededOrFailed() - - - task: PkgESVPack@12 - displayName: 'Package ES - VPack ' - inputs: - sourceDirectory: '$(vpackDir)' - description: PowerShell ${{ parameters.architecture }} $(version) - pushPkgName: 'PowerShell.${{ parameters.architecture }}' - configurations: Release - platforms: x64 - target: '$(System.ArtifactsDirectory)' - owner: tplunk - provData: true - version: '$(vpackVersion)' - vpackToken: $(vPackPat) - condition: and(succeeded(), eq(variables['Build.Reason'], 'Manual')) diff --git a/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml b/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml deleted file mode 100644 index 53947655d90..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-component-governance.yml +++ /dev/null @@ -1,71 +0,0 @@ - -jobs: -- job: ComponentRegistrationJob - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - displayName: Component Registration - condition: succeeded() - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - powershell: | - docker container prune --force - docker container ls --all --format '{{ json .ID }}' | ConvertFrom-Json | ForEach-Object {docker container rm --force --volumes $_} - displayName: 'Remove all containers' - # Cleanup is not critical it passes every time it runs - continueOnError: true - - - powershell: | - docker image ls --format '{{ json .}}'|ConvertFrom-Json| ForEach-Object { - if($_.tag -eq '') - { - $formatString = 'yyyy-MM-dd HH:mm:ss zz00' - $createdAtString = $_.CreatedAt.substring(0,$_.CreatedAt.Length -4) - $createdAt = [DateTime]::ParseExact($createdAtString, $formatString,[System.Globalization.CultureInfo]::InvariantCulture) - if($createdAt -lt (Get-Date).adddays(-1)) - { - docker image rm $_.ID - } - } - } - exit 0 - displayName: 'Remove old images' - # Cleanup is not critical it passes every time it runs - continueOnError: true - - - powershell: | - Write-verbose "--docker info---" -verbose - docker info - Write-verbose "--docker image ls---" -verbose - docker image ls - Write-verbose "--docker container ls --all---" -verbose - docker container ls --all - displayName: 'Capture Docker Info' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - template: insert-nuget-config-azfeed.yml - - - powershell: | - ./tools/releaseBuild/vstsbuild.ps1 -ReleaseTag $(ReleaseTagVar) -Name win-x64-component-registration - displayName: 'Build Windows Universal - Component Registration' - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(componentregistration)' - snapshotForceEnabled: true diff --git a/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml b/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml deleted file mode 100644 index b533061178f..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-hosted-build.yml +++ /dev/null @@ -1,85 +0,0 @@ -parameters: - - name: BuildConfiguration - default: release - - name: BuildPlatform - default: any cpu - - name: Architecture - default: x64 - - name: parentJob - default: '' - -jobs: -- job: build_windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} - displayName: Build Windows - ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - condition: succeeded() - dependsOn: ${{ parameters.parentJob }} - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: runCodesignValidationInjection - value: false - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: BuildConfiguration - value: ${{ parameters.BuildConfiguration }} - - name: BuildPlatform - value: ${{ parameters.BuildPlatform }} - - name: Architecture - value: ${{ parameters.Architecture }} - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: DotNetPrivateBuildAccess - - steps: - - - checkout: self - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: cloneToOfficialPath.yml - - - template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml - parameters: - repoRoot: $(PowerShellRoot) - - - pwsh: | - - $runtime = switch ($env:Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - "fxdependent" { "fxdependent" } - "fxdependentWinDesktop" { "fxdependent-win-desktop" } - } - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 -location '$(PowerShellRoot)' -destination '$(Build.ArtifactStagingDirectory)/Symbols_$(Architecture)' -Runtime $runtime -ReleaseTag '$(ReleaseTagVar)' -Symbols @params - displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols zip' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - $packageName = (Get-ChildItem '$(Build.ArtifactStagingDirectory)\Symbols_$(Architecture)').FullName - $vstsCommandString = "vso[artifact.upload containerfolder=results;artifactname=results]$packageName" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Upload symbols package - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml b/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml deleted file mode 100644 index fdff7af73b1..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-package-signing.yml +++ /dev/null @@ -1,132 +0,0 @@ -parameters: - parentJobs: [] - -jobs: -- job: WinPackageSigningJob - displayName: Windows Package signing and upload - dependsOn: - ${{ parameters.parentJobs }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: ESRP - - name: repoFolder - value: PowerShell - - name: repoRoot - value: $(Agent.BuildDirectory)\$(repoFolder) - - name: complianceRepoFolder - value: compliance - - steps: - - checkout: self - clean: true - path: $(repoFolder) - - - checkout: ComplianceRepo - clean: true - path: $(complianceRepoFolder) - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - task: DownloadBuildArtifacts@0 - displayName: 'Download artifacts' - inputs: - buildType: current - downloadType: single - artifactName: signed - downloadPath: '$(System.ArtifactsDirectory)' - - - powershell: | - dir "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Downloaded Artifacts' - # Diagnostics is not critical it passes every time it runs - continueOnError: true - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\signed - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: $(MSIX_CERT) - pattern: | - **\*.msix - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign msix - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\signed - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: $(AUTHENTICODE_CERT) - pattern: | - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign exe - - - powershell: | - new-item -itemtype Directory -path '$(Build.StagingDirectory)\signedPackages' - Get-ChildItem "$(System.ArtifactsDirectory)\signed\PowerShell-$(Version)-win-*.msi*" | copy-item -Destination '$(Build.StagingDirectory)\signedPackages' - displayName: 'Fake msi* Signing' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\signed\PowerShell-$(Version)-win-*.exe" | copy-item -Destination '$(Build.StagingDirectory)\signedPackages' - displayName: 'Fake exe Signing' - condition: and(succeeded(), ne(variables['SHOULD_SIGN'], 'true')) - - - template: upload.yml - parameters: - architecture: x86 - version: $(version) - - - template: upload.yml - parameters: - architecture: x64 - version: $(version) - pdb: yes - - - template: upload.yml - parameters: - architecture: arm64 - version: $(version) - msi: no - - - template: upload.yml - parameters: - architecture: fxdependent - version: $(version) - msi: no - msix: no - - - template: upload.yml - parameters: - architecture: fxdependentWinDesktop - version: $(version) - msi: no - msix: no - - - template: EsrpScan.yml@ComplianceRepo - parameters: - scanPath: $(Build.StagingDirectory) - pattern: | - **\*.msix - **\*.msi - **\*.zip - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\tools' - snapshotForceEnabled: true - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml b/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml deleted file mode 100644 index 91a5c15f112..00000000000 --- a/tools/releaseBuild/azureDevOps/templates/windows-packaging.yml +++ /dev/null @@ -1,370 +0,0 @@ -parameters: - - name: BuildConfiguration - default: release - - name: BuildPlatform - default: any cpu - - name: Architecture - default: x64 - - name: parentJob - default: '' - -jobs: -- job: sign_windows_${{ parameters.Architecture }}_${{ parameters.BuildConfiguration }} - displayName: Package Windows - ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - condition: succeeded() - pool: - name: $(windowsPool) - demands: - - ImageOverride -equals PSMMS2019-Secure - variables: - - name: BuildConfiguration - value: ${{ parameters.BuildConfiguration }} - - name: BuildPlatform - value: ${{ parameters.BuildPlatform }} - - name: Architecture - value: ${{ parameters.Architecture }} - - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE - value: 1 - - group: ESRP - - group: DotNetPrivateBuildAccess - - steps: - - - checkout: self - clean: true - - - checkout: ComplianceRepo - clean: true - - - template: SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - template: shouldSign.yml - - - pwsh: | - $pkgFilter = '$(Architecture)' - if ($env:BuildConfiguration -eq 'minSize') { $pkgFilter += '-gc' } - - $vstsCommandString = "vso[task.setvariable variable=PkgFilter]$pkgFilter" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Set packageName variable - - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'results' - itemPattern: '**/*$(PkgFilter).zip' - downloadPath: '$(System.ArtifactsDirectory)\Symbols' - - - template: cloneToOfficialPath.yml - - - pwsh: | - $zipPathString = '$(System.ArtifactsDirectory)\Symbols\results\*$(PkgFilter).zip' - Write-Verbose -Verbose "Zip Path: $zipPathString" - $zipPath = Get-Item $zipPathString - if(@($zipPath).Count -eq 0) { - throw "No files found at '$zipPathString'" - } - elseif(@($zipPath).Count -ne 1) { - $names = $zipPath.Name -join "', '" - throw "multiple files '${names}' found with '${zipPathString}'" - } - - $expandedFolder = $zipPath.BaseName - Write-Host "sending.. vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - Write-Host "##vso[task.setvariable variable=SymbolsFolder]$expandedFolder" - - Expand-Archive -Path $zipPath -Destination "$(System.ArtifactsDirectory)\$expandedFolder" -Force - displayName: Expand symbols zip - - - pwsh: | - $fullSymbolsFolder = "$(System.ArtifactsDirectory)\$($env:SYMBOLSFOLDER)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\toBeSigned" - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\signed" - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $itemsToCopyWithRecurse = @( - "$($fullSymbolsFolder)\*.ps1" - "$($fullSymbolsFolder)\Microsoft.PowerShell*.dll" - ) - - $itemsToCopy = @{ - "$($fullSymbolsFolder)\*.ps1" = "" - "$($fullSymbolsFolder)\Microsoft.Management.Infrastructure.CimCmdlets.dll" = "" - "$($fullSymbolsFolder)\Microsoft.WSMan.*.dll" = "" - "$($fullSymbolsFolder)\Modules\CimCmdlets\CimCmdlets.psd1" = "Modules\CimCmdlets" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Diagnostics.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Event.format.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\GetEvent.types.ps1xml" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Diagnostics\Microsoft.PowerShell.Diagnostics.psd1" = "Modules\Microsoft.PowerShell.Diagnostics" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Host\Microsoft.PowerShell.Host.psd1" = "Modules\Microsoft.PowerShell.Host" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" = "Modules\Microsoft.PowerShell.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Security\Security.types.ps1xml" = "Modules\Microsoft.PowerShell.Security" - "$($fullSymbolsFolder)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" = "Modules\Microsoft.PowerShell.Utility" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\Microsoft.WSMan.Management\WSMan.format.ps1xml" = "Modules\Microsoft.WSMan.Management" - "$($fullSymbolsFolder)\Modules\PSDiagnostics\PSDiagnostics.ps?1" = "Modules\PSDiagnostics" - "$($fullSymbolsFolder)\pwsh.dll" = "" - "$($fullSymbolsFolder)\System.Management.Automation.dll" = "" - "$($fullSymbolsFolder)\pwsh.exe" = "" - } - - $itemsToExclude = @( - # This package is retrieved from https://www.github.com/powershell/MarkdownRender - "$($fullSymbolsFolder)\Microsoft.PowerShell.MarkdownRender.dll" - ) - - Write-Verbose -verbose "recusively copying $($itemsToCopyWithRecurse | out-string) to $filesToSignDirectory" - Copy-Item -Path $itemsToCopyWithRecurse -Destination $filesToSignDirectory -Recurse -verbose -exclude $itemsToExclude - - foreach($pattern in $itemsToCopy.Keys) { - $destinationFolder = Join-Path $filesToSignDirectory -ChildPath $itemsToCopy.$pattern - $null = New-Item -ItemType Directory -Path $destinationFolder -Force - Write-Verbose -verbose "copying $pattern to $destinationFolder" - Copy-Item -Path $pattern -Destination $destinationFolder -Recurse -verbose - } - displayName: 'Prepare files to be signed' - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\toBeSigned - signOutputPath: $(System.ArtifactsDirectory)\signed - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.dll - **\*.psd1 - **\*.psm1 - **\*.ps1xml - **\*.ps1 - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign our binaries - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\signed\' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - $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 - - Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)" - - $filesToSignDirectory = "$(System.ArtifactsDirectory)\thirdPartyToBeSigned" - $null = New-Item -ItemType Directory -Path $filesToSignDirectory -Force - - $signedFilesDirectory = "$(System.ArtifactsDirectory)\thirdPartySigned" - $null = New-Item -ItemType Directory -Path $signedFilesDirectory -Force - - $missingSignatures | ForEach-Object { - $pathWithoutLeaf = Split-Path $_ - $relativePath = $pathWithoutLeaf.replace($BuildPath,'') - $targetDirectory = Join-Path -Path $filesToSignDirectory -ChildPath $relativePath - if(!(Test-Path $targetDirectory)) - { - $null = New-Item -ItemType Directory -Path $targetDirectory -Force - } - Copy-Item -Path $_ -Destination $targetDirectory - } - - displayName: Create ThirdParty Signing Folder - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\thirdPartyToBeSigned - signOutputPath: $(System.ArtifactsDirectory)\thirdPartySigned - certificateId: "CP-231522" - pattern: | - **\*.dll - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign ThirdParty binaries - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\thirdPartySigned\*' - displayName: Capture ThirdParty Signed files - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - $signedFilesPath = '$(System.ArtifactsDirectory)\thirdPartySigned' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - Update-PSSignedBuildFolder -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath - if ($env:BuildConfiguration -eq 'minSize') { - ## Remove XML files when making a min-size package. - Remove-Item "$BuildPath/*.xml" -Force - } - displayName: Merge ThirdParty signed files with Build - condition: and(succeeded(), eq(variables['SHOULD_SIGN'], 'true')) - - - template: Sbom.yml@ComplianceRepo - parameters: - BuildDropPath: '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - Build_Repository_Uri: $(Github_Build_Repository_Uri) - PackageName: PowerShell Windows ${{ parameters.Architecture }} ${{ parameters.BuildConfiguration }} - PackageVersion: $(Version) - sourceScanPath: '$(PowerShellRoot)\tools' - - - pwsh: | - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $destFolder = '$(System.ArtifactsDirectory)\signedZip' - $BuildPath = '$(System.ArtifactsDirectory)\$(SymbolsFolder)' - - New-Item -ItemType Directory -Path $destFolder -Force - - $BuildPackagePath = New-PSBuildZip -BuildPath $BuildPath -DestinationFolder $destFolder - - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - - $vstsCommandString = "vso[task.setvariable variable=BuildPackagePath]$BuildPackagePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Compress signed files - retryCountOnTaskFailure: 2 - - - - pwsh: | - $runtime = switch ($env:Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - "fxdependent" { "fxdependent" } - "fxdependentWinDesktop" { "fxdependent-win-desktop" } - } - - $signedPkg = "$(BuildPackagePath)" - Write-Verbose -Verbose -Message "signedPkg = $signedPkg" - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - $(PowerShellRoot)/tools/releaseBuild/Images/microsoft_powershell_windowsservercore/PowerShellPackage.ps1 -BuildZip $signedPkg -location '$(PowerShellRoot)' -destination '$(System.ArtifactsDirectory)\pkgSigned' -Runtime $runtime -ReleaseTag '$(ReleaseTagVar)' @params - displayName: 'Build Windows Universal - $(Architecture) Package' - env: - __DOTNET_RUNTIME_FEED: $(RUNTIME_SOURCEFEED) - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\pkgSigned' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=signed;artifactname=signed]$packagePath" - } - displayName: Upload unsigned packages - retryCountOnTaskFailure: 2 - - - ${{ if and(ne(variables['BuildConfiguration'],'minSize'), in(variables['Architecture'], 'x64', 'x86')) }}: - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\pkgSigned - signOutputPath: $(Build.StagingDirectory)\signedPackages - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.msi - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign MSI - alwaysCopy: true - - - pwsh: | - Get-ChildItem '$(System.ArtifactsDirectory)\signedPackages' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=finalResults;artifactname=finalResults]$packagePath" - } - displayName: Upload signed MSI to finalResults - retryCountOnTaskFailure: 2 - - - task: AzureFileCopy@4 - displayName: 'upload signed msi to Azure - ${{ parameters.architecture }}' - inputs: - SourcePath: '$(Build.StagingDirectory)\signedPackages\PowerShell-$(version)-win-${{ parameters.architecture }}.msi' - azureSubscription: '$(AzureFileCopySubscription)' - Destination: AzureBlob - storage: '$(StorageAccount)' - ContainerName: '$(AzureVersion)' - resourceGroup: '$(StorageResourceGroup)' - retryCountOnTaskFailure: 2 - - - pwsh: | - cd $(PowerShellRoot) - Import-Module $(PowerShellRoot)/build.psm1 -Force - Import-Module $(PowerShellRoot)/tools/packaging -Force - - $msiPath = '$(Build.StagingDirectory)\signedPackages\PowerShell-$(version)-win-${{ parameters.architecture }}.msi' - - New-ExePackage -ProductVersion '$(version)' -MsiLocationPath $msiPath -ProductTargetArchitecture ${{ parameters.architecture }} - $exePath = Get-ChildItem '.\PowerShell-*.exe' | Select-Object -First 1 -ExpandProperty fullname - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - # Expand Burn Engine so we can sign it. - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath - displayName: Create exe wrapper - - - template: EsrpSign.yml@ComplianceRepo - parameters: - buildOutputPath: $(System.ArtifactsDirectory)\unsignedEngine - signOutputPath: $(System.ArtifactsDirectory)\signedEngine - certificateId: "$(AUTHENTICODE_CERT)" - pattern: | - **\*.exe - useMinimatch: true - shouldSign: $(SHOULD_SIGN) - displayName: Sign Burn Engine - alwaysCopy: true - - - pwsh: | - cd '$(PowerShellRoot)' - Import-Module '$(PowerShellRoot)/build.psm1' -Force - Import-Module '$(PowerShellRoot)/tools/packaging' -Force - - $exePath = Get-ChildItem '.\PowerShell-*.exe' | Select-Object -First 1 -ExpandProperty fullname - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\signedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath - displayName: Re-attach the signed Burn engine in exe wrapper - - - pwsh: | - cd '$(PowerShellRoot)' - Get-ChildItem '.\PowerShell-*.exe' | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=signed;artifactname=signed]$packagePath" - } - displayName: Upload unsigned exe - retryCountOnTaskFailure: 2 - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(PowerShellRoot)\tools' - snapshotForceEnabled: true - - - pwsh: | - if ((Test-Path "\PowerShell")) { - Remove-Item -Path "\PowerShell" -Force -Recurse -Verbose - } - else { - Write-Verbose -Verbose -Message "No cleanup required." - } - displayName: Clean up local Clone - condition: always() - - - template: /tools/releaseBuild/azureDevOps/templates/step/finalize.yml diff --git a/tools/releaseBuild/azureDevOps/vpackRelease.yml b/tools/releaseBuild/azureDevOps/vpackRelease.yml deleted file mode 100644 index 14368ffb8f8..00000000000 --- a/tools/releaseBuild/azureDevOps/vpackRelease.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: vpack-$(Build.BuildId) -trigger: - branches: - include: - - master - - release* -pr: - branches: - include: - - master - - release* - -variables: - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - - group: Azure Blob variable group - # adds the pat to publish the vPack - # instructions to create are in the description of the library - - group: vPack - -stages: -- stage: prep - displayName: Create buildInfo and name the Pipeline - jobs: - - job: rename - displayName: Name the build - condition: succeeded() - - pool: - name: PowerShell1ES - demands: - - ImageOverride -equals PSMMS2019-Secure - - steps: - - checkout: self - clean: true - - - template: ./templates/SetVersionVariables.yml - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no - - - powershell: | - if($env:RELEASETAGVAR -match '-') { - throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" - } - displayName: Stop any preview release - - - powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhss"))" - displayName: Set Build Name for Non-PR - condition: ne(variables['Build.Reason'], 'PullRequest') - -- stage: release - displayName: Release - jobs: - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: x64 - - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: x86 - - - template: ./templates/vpackReleaseJob.yml - parameters: - architecture: arm64 diff --git a/tools/releaseBuild/build.json b/tools/releaseBuild/build.json deleted file mode 100644 index fe2f9d96f17..00000000000 --- a/tools/releaseBuild/build.json +++ /dev/null @@ -1,336 +0,0 @@ -{ - "Windows": [ - { - "Name": "win7-x64", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\DockerFile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win7-x86", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-component-registration", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_ -ComponentRegistration", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "componentregistration", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_x64", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x86-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_x86", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_arm", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm64-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm64 -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_arm64", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x64-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 4, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-x86-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win7-x86 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 4, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 2, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-arm64-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime win-arm64 -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 2, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependent-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_fxdependent", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependent-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 1, - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependentWinDesktop-symbols", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent-win-desktop -ReleaseTag _ReleaseTag_ -Symbols", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "results", - "ArtifactsExpected": 1, - "VariableForExtractedBinariesPath": "Symbols_fxdependentWinDesktop", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "win-fxdependentWinDesktop-package", - "RepoDestinationPath": "C:\\PowerShell", - "BuildCommand": "C:\\PowerShellPackage.ps1 -BuildZip _RepoDestinationPath_\\_BuildPackageName_ -location _RepoDestinationPath_ -destination _DockerVolume_ -Runtime fxdependent-win-desktop -ReleaseTag _ReleaseTag_", - "BuildDockerOptions": [ - "-m", - "3968m" - ], - "DockerFile": ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\Dockerfile", - "AdditionalContextFiles" :[ - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\PowerShellPackage.ps1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\wix.psm1", - ".\\tools\\releaseBuild\\Images\\microsoft_powershell_windowsservercore\\dockerInstall.psm1" - ], - "DockerImageName": "ps-winsrvcore", - "BinaryBucket": "signed", - "ArtifactsExpected": 1, - "EnableFeature": [ "ArtifactAsFolder" ] - } - ], - "Linux": [ - { - "Name": "deb", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -TarX64 -TarArm -TarArm64 -TarMinSize", - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_ubuntu18.04/Dockerfile", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerImageName": "ps-ubunutu-18-04", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "rpm", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile", - "DockerImageName": "ps-centos-7", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "alpine", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -Alpine", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_alpine3/Dockerfile", - "DockerImageName": "ps-alpine-3", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - }, - { - "Name": "fxdependent", - "RepoDestinationPath": "/PowerShell", - "BuildCommand": "/PowerShellPackage.ps1 -location _RepoDestinationPath_ -destination _DockerVolume_ -ReleaseTag _ReleaseTag_ -FxDependent", - "AdditionalContextFiles" :[ "./tools/releaseBuild/Images/GenericLinuxFiles/PowerShellPackage.ps1"], - "DockerFile": "./tools/releaseBuild/Images/microsoft_powershell_centos7/Dockerfile", - "DockerImageName": "ps-centos-7", - "BinaryBucket": "release", - "EnableFeature": [ "ArtifactAsFolder" ] - } - ] -} diff --git a/tools/releaseBuild/createComplianceFolder.ps1 b/tools/releaseBuild/createComplianceFolder.ps1 deleted file mode 100644 index c462a09ebdb..00000000000 --- a/tools/releaseBuild/createComplianceFolder.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [Parameter(HelpMessage="Artifact folder to find compliance files in.")] - [string[]] - $ArtifactFolder, - [Parameter(HelpMessage="VSTS Variable to set path to complinance Files.")] - [string] - $VSTSVariableName -) - -$compliancePath = $null -foreach($folder in $ArtifactFolder) -{ - # Find Symbols zip which contains compliance files - Write-Host "ArtifactFolder: $folder" - $filename = Join-Path -Path $folder -ChildPath 'symbols.zip' - - $parentName = Split-Path -Path $folder -Leaf - - # Use simplified names because some of the compliance tools didn't like the full names - # decided not to use hashes because the names need to be consistent otherwise the tool also has issues - # which is another problem with the full name, it includes version. - if ($parentName -match 'x64' -or $parentName -match 'amd64') - { - $name = 'x64' - } - elseif ($parentName -match 'x86') { - $name = 'x86' - } - elseif ($parentName -match 'fxdependent') { - $name = 'fxd' - } - else - { - throw "$parentName could not be classified as x86 or x64" - } - - # Throw is compliance zip does not exist - if (!(Test-Path $filename)) - { - throw "symbols.zip for $VSTSVariableName does not exist" - } - - # make sure we have a single parent for everything - if (!$compliancePath) - { - $parent = Split-Path -Path $folder - $compliancePath = Join-Path -Path $parent -ChildPath 'compliance' - } - - # Extract complance files to individual folder to avoid overwriting files. - $unzipPath = Join-Path -Path $compliancePath -ChildPath $name - Write-Host "Symbols-zip: $filename ; unzipPath: $unzipPath" - Expand-Archive -Path $fileName -DestinationPath $unzipPath -} - -# set VSTS variable with path to compliance files -Write-Host "##vso[task.setvariable variable=$VSTSVariableName]$unzipPath" diff --git a/tools/releaseBuild/generatePackgeSigning.ps1 b/tools/releaseBuild/generatePackgeSigning.ps1 deleted file mode 100644 index ff848892097..00000000000 --- a/tools/releaseBuild/generatePackgeSigning.ps1 +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [Parameter(Mandatory)] - [string] $Path, - [string[]] $AuthenticodeDualFiles, - [string[]] $AuthenticodeFiles, - [string[]] $NuPkgFiles, - [string[]] $MacDeveloperFiles, - [string[]] $LinuxFiles, - [string[]] $ThirdPartyFiles, - [string[]] $MsixFiles, - [ValidateSet('release','preview')] - [string] $MsixCertType = 'preview' -) - -if ((!$AuthenticodeDualFiles -or $AuthenticodeDualFiles.Count -eq 0) -and - (!$AuthenticodeFiles -or $AuthenticodeFiles.Count -eq 0) -and - (!$NuPkgFiles -or $NuPkgFiles.Count -eq 0) -and - (!$MacDeveloperFiles -or $MacDeveloperFiles.Count -eq 0) -and - (!$LinuxFiles -or $LinuxFiles.Count -eq 0) -and - (!$MsixFiles -or $MsixFiles.Count -eq 0) -and - (!$ThirdPartyFiles -or $ThirdPartyFiles.Count -eq 0)) -{ - throw "At least one file must be specified" -} - -function New-Attribute -{ - param( - [Parameter(Mandatory)] - [string]$Name, - [Parameter(Mandatory)] - [object]$Value, - [Parameter(Mandatory)] - [System.Xml.XmlElement]$Element - ) - - $attribute = $signingXml.CreateAttribute($Name) - $attribute.Value = $value - $null = $fileElement.Attributes.Append($attribute) -} - -function New-FileElement -{ - param( - [Parameter(Mandatory)] - [string]$File, - [Parameter(Mandatory)] - [string]$SignType, - [Parameter(Mandatory)] - [System.Xml.XmlDocument]$XmlDoc, - [Parameter(Mandatory)] - [System.Xml.XmlElement]$Job - ) - - if(Test-Path -Path $file) - { - $name = Split-Path -Leaf -Path $File - $fileElement = $XmlDoc.CreateElement("file") - New-Attribute -Name 'src' -value $file -Element $fileElement - New-Attribute -Name 'signType' -value $SignType -Element $fileElement - New-Attribute -Name 'dest' -value "__OUTPATHROOT__\$name" -Element $fileElement - $null = $job.AppendChild($fileElement) - } - else - { - Write-Warning -Message "Skipping $SignType; $File because it does not exist" - } -} - -[xml]$signingXml = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath 'packagesigning.xml') -$job = $signingXml.SignConfigXML.job - -foreach($file in $AuthenticodeDualFiles) -{ - New-FileElement -File $file -SignType 'AuthenticodeDual' -XmlDoc $signingXml -Job $job -} - -foreach($file in $AuthenticodeFiles) -{ - New-FileElement -File $file -SignType 'AuthenticodeFormer' -XmlDoc $signingXml -Job $job -} - -foreach($file in $NuPkgFiles) -{ - New-FileElement -File $file -SignType 'NuGet' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $MacDeveloperFiles) { - New-FileElement -File $file -SignType 'MacDeveloper' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $LinuxFiles) { - New-FileElement -File $file -SignType 'LinuxPack' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $ThirdPartyFiles) { - New-FileElement -File $file -SignType 'ThirdParty' -XmlDoc $signingXml -Job $job -} - -foreach ($file in $MsixFiles) { - # 'CP-459155' is supposed to work for the store - # AuthenticodeFormer works for sideloading and via a workaround, through the store - # ---------------------------------------------- - # update releasePublisher in packaging.psm1 when this is changed - New-FileElement -File $file -SignType 'AuthenticodeFormer' -XmlDoc $signingXml -Job $job -} - -$signingXml.Save($path) -$updateScriptPath = Join-Path -Path $PSScriptRoot -ChildPath 'updateSigning.ps1' -& $updateScriptPath -SigningXmlPath $path diff --git a/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 b/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 deleted file mode 100644 index acedbdd3388..00000000000 --- a/tools/releaseBuild/macOS/PowerShellPackageVsts.ps1 +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -# PowerShell Script to build and package PowerShell from specified form and branch -# Script is intented to use in Docker containers -# Ensure PowerShell is available in the provided image - -param ( - # Set default location to where VSTS cloned the repository locally. - [string] $location = $env:BUILD_REPOSITORY_LOCALPATH, - - # Destination location of the package on docker host - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [string] $destination = '/mnt', - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [ValidateNotNullOrEmpty()] - [string]$ReleaseTag, - - [Parameter(ParameterSetName = 'packageSigned')] - [Parameter(ParameterSetName = 'IncludeSymbols')] - [Parameter(ParameterSetName = 'Build')] - [ValidateSet("zip", "tar")] - [string[]]$ExtraPackage, - - [Parameter(Mandatory, ParameterSetName = 'Bootstrap')] - [switch] $BootStrap, - - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [switch] $Build, - - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [switch] $Symbols, - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [ValidatePattern("-signed.zip$")] - [string]$BuildZip, - - [Parameter(Mandatory, ParameterSetName = 'packageSigned')] - [Parameter(Mandatory, ParameterSetName = 'IncludeSymbols')] - [Parameter(Mandatory, ParameterSetName = 'Build')] - [ValidateSet('osx-x64', 'osx-arm64')] - [string]$Runtime, - - [string]$ArtifactName = 'result', - - [switch]$SkipReleaseChecks -) - -$repoRoot = $location - -if ($Build -or $PSCmdlet.ParameterSetName -eq 'packageSigned') { - $releaseTagParam = @{} - if ($ReleaseTag) { - $releaseTagParam['ReleaseTag'] = $ReleaseTag - - #Remove the initial 'v' from the ReleaseTag - $version = $ReleaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version - - $metadata = Get-Content "$location/tools/metadata.json" -Raw | ConvertFrom-Json - - $LTS = $metadata.LTSRelease.Package - - Write-Verbose -Verbose -Message "LTS is set to: $LTS" - } -} - -Push-Location -try { - $pspackageParams = @{ SkipReleaseChecks = $SkipReleaseChecks; MacOSRuntime = $Runtime } - Write-Verbose -Message "Init..." -Verbose - Set-Location $repoRoot - Import-Module "$repoRoot/build.psm1" - Import-Module "$repoRoot/tools/packaging" - Sync-PSTags -AddRemoteIfMissing - - if ($BootStrap) { - Start-PSBootstrap -Package - } - - if ($PSCmdlet.ParameterSetName -eq 'packageSigned') { - Write-Verbose "Expanding signed build $BuildZip ..." -Verbose - Expand-PSSignedBuild -BuildZip $BuildZip - - Remove-Item -Path $BuildZip - - Start-PSPackage @pspackageParams @releaseTagParam - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam } - } - - if ($LTS) { - Start-PSPackage @pspackageParams @releaseTagParam -LTS - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam -LTS } - } - } - } - - if ($Build) { - if ($Symbols) { - Start-PSBuild -Clean -Configuration 'Release' -NoPSModuleRestore @releaseTagParam -Runtime $Runtime - $pspackageParams['Type']='zip' - $pspackageParams['IncludeSymbols']=$Symbols.IsPresent - Write-Verbose "Starting powershell packaging(zip)..." -Verbose - Start-PSPackage @pspackageParams @releaseTagParam - } else { - Start-PSBuild -Configuration 'Release' -PSModuleRestore @releaseTagParam -Runtime $Runtime - Start-PSPackage @pspackageParams @releaseTagParam - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam } - } - - if ($LTS) { - Start-PSPackage @releaseTagParam -LTS - switch ($ExtraPackage) { - "tar" { Start-PSPackage -Type tar @pspackageParams @releaseTagParam -LTS } - } - } - } - } -} finally { - Pop-Location -} - -if ($Build -or $PSCmdlet.ParameterSetName -eq 'packageSigned') { - $macPackages = Get-ChildItem "$repoRoot/powershell*" -Include *.pkg, *.tar.gz, *.zip - foreach ($macPackage in $macPackages) { - $filePath = $macPackage.FullName - $extension = (Split-Path -Extension -Path $filePath).Replace('.', '') - Write-Verbose "Copying $filePath to $destination" -Verbose - Write-Host "##vso[artifact.upload containerfolder=$ArtifactName;artifactname=$ArtifactName]$filePath" - Write-Host "##vso[task.setvariable variable=Package-$extension]$filePath" - Copy-Item -Path $filePath -Destination $destination -Force - } -} diff --git a/tools/releaseBuild/macOS/PowerShellPackageVsts.sh b/tools/releaseBuild/macOS/PowerShellPackageVsts.sh deleted file mode 100644 index b7bfa7315d8..00000000000 --- a/tools/releaseBuild/macOS/PowerShellPackageVsts.sh +++ /dev/null @@ -1 +0,0 @@ -pwsh -command ".\PowerShellPackageVsts.ps1 $*" diff --git a/tools/releaseBuild/macOS/createPowerShell.sh b/tools/releaseBuild/macOS/createPowerShell.sh deleted file mode 100644 index 5b0b681716c..00000000000 --- a/tools/releaseBuild/macOS/createPowerShell.sh +++ /dev/null @@ -1,8 +0,0 @@ -# print version for diags -sw_vers -productVersion - -# create folder -sudo mkdir /PowerShell - -# make the current user the owner -sudo chown $USER /PowerShell diff --git a/tools/releaseBuild/packagesigning.xml b/tools/releaseBuild/packagesigning.xml deleted file mode 100644 index a243e5fbd98..00000000000 --- a/tools/releaseBuild/packagesigning.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/tools/releaseBuild/setReleaseTag.ps1 b/tools/releaseBuild/setReleaseTag.ps1 index 8d6a8c3eefe..c5f2f016554 100644 --- a/tools/releaseBuild/setReleaseTag.ps1 +++ b/tools/releaseBuild/setReleaseTag.ps1 @@ -41,6 +41,7 @@ function New-BuildInfoJson { ReleaseTag = $ReleaseTag ReleaseDate = $dateTime BlobName = $blobName + BaseUrl = 'https://powershellinfraartifacts-gkhedzdeaghdezhr.z01.azurefd.net/install' } | ConvertTo-Json | Out-File -Encoding ascii -Force -FilePath $filename $resolvedPath = (Resolve-Path -Path $filename).ProviderPath @@ -48,7 +49,21 @@ function New-BuildInfoJson { Write-Verbose -Message "$vstsCommandString" -Verbose Write-Host -Object "##$vstsCommandString" + # Upload for ADO pipelines Write-Host "##vso[artifact.upload containerfolder=BuildInfoJson;artifactname=BuildInfoJson]$resolvedPath" + + # Copy to location where OneBranch Pipelines uploads from + + # if the environment variable does not exist, we are not in OneBranch. So just return. + if (-not $env:ob_outputDirectory) { + return + } + + if (-not (Test-Path $env:ob_outputDirectory)) { + $null = New-Item -Path $env:ob_outputDirectory -ItemType Directory -Force -Verbose + } + + Copy-Item $resolvedPath -Destination $env:ob_outputDirectory -Force -Verbose } # Script to set the release tag based on the branch name if it is not set or it is "fromBranch" diff --git a/tools/releaseBuild/updateSigning.ps1 b/tools/releaseBuild/updateSigning.ps1 deleted file mode 100644 index bace3aec2b7..00000000000 --- a/tools/releaseBuild/updateSigning.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -param( - [string] $SigningXmlPath = (Join-Path -Path $PSScriptRoot -ChildPath 'signing.xml'), - [switch] $SkipPwshExe -) -# Script for use in VSTS to update signing.xml - -if ($SkipPwshExe) { - ## This is required for fxdependent package as no .exe is generated. - $xmlContent = Get-Content $SigningXmlPath | Where-Object { $_ -notmatch '__INPATHROOT__\\pwsh.exe' } -} else { - ## We skip the global tool shim assembly for regular builds. - $xmlContent = Get-Content $signingXmlPath | Where-Object { $_ -notmatch '__INPATHROOT__\\Microsoft.PowerShell.GlobalTool.Shim.dll' } -} - -# Parse the signing xml -$signingXml = [xml] $xmlContent - -# Get any variables to updating 'signType' in the XML -# Define a varabile named `SignType' in VSTS to updating that signing type -# Example: $env:AuthenticodeSignType='newvalue' -# will cause all files with the 'Authenticode' signtype to be updated with the 'newvalue' signtype -$signTypes = @{} -Get-ChildItem -Path env:/*SignType | ForEach-Object -Process { - $signType = $_.Name.ToUpperInvariant().Replace('SIGNTYPE','') - Write-Host "Found SigningType $signType with value $($_.value)" - $signTypes[$signType] = $_.Value -} - -# examine each job in the xml -$signingXml.SignConfigXML.job | ForEach-Object -Process { - # examine each file in the job - $_.file | ForEach-Object -Process { - # if the sign type is one of the variables we found, update it to the new value - $signType = $_.SignType.ToUpperInvariant() - if($signTypes.ContainsKey($signType)) - { - $newSignType = $signTypes[$signType] - Write-Host "Updating $($_.src) to $newSignType" - $_.signType = $newSignType - } - } -} - -$signingXml.Save($signingXmlPath) diff --git a/tools/releaseBuild/vstsbuild.ps1 b/tools/releaseBuild/vstsbuild.ps1 deleted file mode 100644 index 1c2d740c418..00000000000 --- a/tools/releaseBuild/vstsbuild.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -[cmdletbinding(DefaultParameterSetName='Build')] -param( - [Parameter(ParameterSetName='packageSigned')] - [Parameter(ParameterSetName='Build')] - [ValidatePattern("^v\d+\.\d+\.\d+(-\w+(\.\d{1,2})?)?$")] - [string]$ReleaseTag, - - # full paths to files to add to container to run the build - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [string] - $BuildPath, - - [Parameter(Mandatory,ParameterSetName='packageSigned')] - [string] - $SignedFilesPath -) - -DynamicParam { - # Add a dynamic parameter '-Name' which specifies the name of the build to run - - # Get the names of the builds. - $buildJsonPath = (Join-Path -Path $PSScriptRoot -ChildPath 'build.json') - $build = Get-Content -Path $buildJsonPath | ConvertFrom-Json - $names = @($build.Windows.Name) - foreach($name in $build.Linux.Name) - { - $names += $name - } - - # Create the parameter attributs - $ParameterAttr = New-Object "System.Management.Automation.ParameterAttribute" - $ValidateSetAttr = New-Object "System.Management.Automation.ValidateSetAttribute" -ArgumentList $names - $Attributes = New-Object "System.Collections.ObjectModel.Collection``1[System.Attribute]" - $Attributes.Add($ParameterAttr) > $null - $Attributes.Add($ValidateSetAttr) > $null - - # Create the parameter - $Parameter = New-Object "System.Management.Automation.RuntimeDefinedParameter" -ArgumentList ("Name", [string], $Attributes) - $Dict = New-Object "System.Management.Automation.RuntimeDefinedParameterDictionary" - $Dict.Add("Name", $Parameter) > $null - return $Dict -} - -Begin { - $Name = $PSBoundParameters['Name'] -} - -End { - $ErrorActionPreference = 'Stop' - - $additionalFiles = @() - $buildPackageName = $null - # If specified, Add package file to container - if ($BuildPath) - { - Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '..\..\build.psm1') - Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '..\packaging') - - # Use temp as destination if not running in VSTS - $destFolder = $env:temp - if($env:BUILD_STAGINGDIRECTORY) - { - # Use artifact staging if running in VSTS - $destFolder = $env:BUILD_STAGINGDIRECTORY - } - - $BuildPackagePath = New-PSSignedBuildZip -BuildPath $BuildPath -SignedFilesPath $SignedFilesPath -DestinationFolder $destFolder - Write-Verbose -Verbose "New-PSSignedBuildZip returned `$BuildPackagePath as: $BuildPackagePath" - Write-Host "##vso[artifact.upload containerfolder=results;artifactname=results]$BuildPackagePath" - $buildPackageName = Split-Path -Path $BuildPackagePath -Leaf - $additionalFiles += $BuildPackagePath - } - - $psReleaseBranch = 'master' - $psReleaseFork = 'PowerShell' - $location = Join-Path -Path $PSScriptRoot -ChildPath 'PSRelease' - if(Test-Path $location) - { - Remove-Item -Path $location -Recurse -Force - } - - $gitBinFullPath = (Get-Command -Name git).Source - if (-not $gitBinFullPath) - { - throw "Git is required to proceed. Install from 'https://git-scm.com/download/win'" - } - - Write-Verbose "cloning -b $psReleaseBranch --quiet https://github.com/$psReleaseFork/PSRelease.git" -Verbose - & $gitBinFullPath clone -b $psReleaseBranch --quiet https://github.com/$psReleaseFork/PSRelease.git $location - - Push-Location -Path $PWD.Path - - $unresolvedRepoRoot = Join-Path -Path $PSScriptRoot '../..' - $resolvedRepoRoot = (Resolve-Path -Path $unresolvedRepoRoot).ProviderPath - - try - { - Write-Verbose "Starting build at $resolvedRepoRoot ..." -Verbose - Import-Module "$location/vstsBuild" -Force - Import-Module "$location/dockerBasedBuild" -Force - Clear-VstsTaskState - - $buildParameters = @{ - ReleaseTag = $ReleaseTag - BuildPackageName = $buildPackageName - } - - Invoke-Build -RepoPath $resolvedRepoRoot -BuildJsonPath './tools/releaseBuild/build.json' -Name $Name -Parameters $buildParameters -AdditionalFiles $AdditionalFiles - } - catch - { - Write-VstsError -Error $_ - } - finally{ - Write-VstsTaskState - exit 0 - } -} diff --git a/tools/releaseBuild/vstsbuild.sh b/tools/releaseBuild/vstsbuild.sh deleted file mode 100644 index d7d0363745f..00000000000 --- a/tools/releaseBuild/vstsbuild.sh +++ /dev/null @@ -1 +0,0 @@ -pwsh -command ".\vstsbuild.ps1 $*" diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index 86b04ac6b50..c69542e360b 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -43,6 +43,7 @@ $Script:powershell_team = @( "Patrick Meinecke" "Steven Bucher" "PowerShell Team Bot" + "Justin Chung" ) # They are very active contributors, so we keep their email-login mappings here to save a few queries to Github. @@ -150,13 +151,20 @@ function Get-ChangeLog [Parameter(Mandatory = $true)] [string]$ThisReleaseTag, - [Parameter(Mandatory)] + [Parameter(Mandatory = $false)] [string]$Token, [Parameter()] [switch]$HasCherryPick ) + if(-not $Token) { + $Token = Get-GHDefaultAuthToken + if(-not $Token) { + throw "No GitHub Auth Token provided" + } + } + $tag_hash = git rev-parse "$LastReleaseTag^0" $format = '%H||%P||%aN||%aE||%s' $header = @{"Authorization"="token $Token"} @@ -360,6 +368,29 @@ function Get-ChangeLog Write-Output "[${version}]: https://github.com/PowerShell/PowerShell/compare/${LastReleaseTag}...${ThisReleaseTag}`n" } +function Get-GHDefaultAuthToken { + $IsGHCLIInstalled = $false + if (Get-command -CommandType Application -Name gh -ErrorAction SilentlyContinue) { + $IsGHCLIInstalled = $true + } else { + Write-Error -Message "GitHub CLI is not installed. Please install it from https://cli.github.com/" -ErrorAction Stop + } + + if ($IsGHCLIInstalled) { + try { + $Token = & gh auth token + } catch { + Write-Error -Message "Please login to GitHub CLI using 'gh auth login'" + } + } + + if (-not $Token) { + $Token = Read-Host -Prompt "Enter GitHub Auth Token" + } + + return $Token +} + function PrintChangeLog($clSection, $sectionTitle, [switch] $Compress) { if ($clSection.Count -gt 0) { "### $sectionTitle`n" diff --git a/tools/super-linter/config/super-linter.env b/tools/super-linter/config/super-linter.env new file mode 100644 index 00000000000..e7324b0feb9 --- /dev/null +++ b/tools/super-linter/config/super-linter.env @@ -0,0 +1,8 @@ +VALIDATE_ALL_CODEBASE=false +DEFAULT_BRANCH=master +FILTER_REGEX_INCLUDE=.*\.md +VALIDATE_EDITORCONFIG=false +VALIDATE_JSCPD=false +VALIDATE_CHECKOV=false +FIX_MARKDOWN_PRETTIER=true +FIX_MARKDOWN=true diff --git a/tools/super-linter/super-linter.ps1 b/tools/super-linter/super-linter.ps1 new file mode 100644 index 00000000000..571ba9c7f8d --- /dev/null +++ b/tools/super-linter/super-linter.ps1 @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +param( + [string]$RepoRoot = (Join-Path -Path $PSScriptRoot -ChildPath '../..'), + [string]$Platform +) + +$resolvedPath = (Resolve-Path $RepoRoot).ProviderPath +$platformParam = @() +if ($Platform) { + $platformParam = @("--platform", $Platform) +} + +docker run $platformParam -e RUN_LOCAL=true --env-file "$PSScriptRoot/config/super-linter.env" -v "${resolvedPath}:/tmp/lint" ghcr.io/super-linter/super-linter:latest diff --git a/tools/wix/Microsoft.PowerShell.Packaging.csproj b/tools/wix/Microsoft.PowerShell.Packaging.csproj new file mode 100644 index 00000000000..3f59a225100 --- /dev/null +++ b/tools/wix/Microsoft.PowerShell.Packaging.csproj @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/tools/NamedPipeConnection/nuget.config b/tools/wix/nuget.config similarity index 61% rename from test/tools/NamedPipeConnection/nuget.config rename to tools/wix/nuget.config index 6548586147e..ce91b13c60b 100644 --- a/test/tools/NamedPipeConnection/nuget.config +++ b/tools/wix/nuget.config @@ -2,7 +2,7 @@ - + diff --git a/tools/wix/wix.psm1 b/tools/wix/wix.psm1 new file mode 100644 index 00000000000..8d4dd45fdc9 --- /dev/null +++ b/tools/wix/wix.psm1 @@ -0,0 +1,108 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +function Append-Path +{ + param + ( + $path + ) + $machinePathString = [System.Environment]::GetEnvironmentVariable('path',[System.EnvironmentVariableTarget]::Machine) + $machinePath = $machinePathString -split ';' + + if($machinePath -inotcontains $path) + { + $newPath = "$machinePathString;$path" + Write-Verbose "Adding $path to path..." -Verbose + [System.Environment]::SetEnvironmentVariable('path',$newPath,[System.EnvironmentVariableTarget]::Machine) + Write-Verbose "Added $path to path." -Verbose + } + else + { + Write-Verbose "$path already in path." -Verbose + } +} + +# Install using Wix Zip because the MSI requires an older version of dotnet +# which was large and unstable in docker +function Install-Wix +{ + param($arm64 = $false) + + $targetRoot = $arm64 ? "${env:ProgramFiles(x86)}\Arm Support WiX Toolset xcopy" : "${env:ProgramFiles(x86)}\WiX Toolset xcopy" + # cleanup previous install + if(Test-Path $targetRoot) { + Remove-Item $targetRoot -Recurse -Force + } + $binPath = Join-Path -Path $targetRoot -ChildPath 'bin' + + $psresourceGet = Get-Module -ListAvailable -Name 'Microsoft.PowerShell.PSResourceGet' -ErrorAction SilentlyContinue + + if (-not $psresourceGet) { + Install-Module -Name 'Microsoft.PowerShell.PSResourceGet' -Force -AllowClobber -Scope CurrentUser + } + + $respository = Get-PSResourceRepository -Name 'dotnet-eng' -ErrorAction SilentlyContinue + + if (-not $respository) { + Write-Verbose -Verbose "Registering dotnet-eng repository..." + Register-PSResourceRepository -Name 'dotnet-eng' -Uri 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' -Trusted + } + + # keep version in sync with Microsoft.PowerShell.Packaging.csproj + + if (-not (Test-Path $binPath)) { + $null = New-Item -ItemType Directory -Path $binPath + Write-Verbose -Verbose "Created bin directory for WIX at $binPath" + } + + try { + Save-PSResource -Name 'Microsoft.Signed.Wix' -Repository 'dotnet-eng' -path "$binPath/" -Prerelease + } + finally { + Write-Verbose -Verbose "Unregistering dotnet-eng repository..." + Unregister-PSResourceRepository -Name 'dotnet-eng' + } + + $docExpandPath = Join-Path -Path "$binPath\Microsoft.Signed.Wix\3.14.1\tools\" -ChildPath 'doc' + $sdkExpandPath = Join-Path -Path "$binPath\Microsoft.Signed.Wix\3.14.1\tools\" -ChildPath 'sdk' + $x86ExpandPath = Join-Path -Path "$binPath\Microsoft.Signed.Wix\3.14.1\tools\" -ChildPath 'x86' + + $docTargetPath = Join-Path -Path $targetRoot -ChildPath 'doc' + + if (-not (Test-Path $docTargetPath)) { + $null = New-Item -ItemType Directory -Path $docTargetPath + Write-Verbose -Verbose "Created doc directory for WIX at $docTargetPath" + } + + $sdkTargetPath = Join-Path -Path $targetRoot -ChildPath 'sdk' + + if (-not (Test-Path $sdkTargetPath)) { + $null = New-Item -ItemType Directory -Path $sdkTargetPath + Write-Verbose -Verbose "Created sdk directory for WIX at $sdkTargetPath" + } + + $binTargetPath = Join-Path -Path $targetRoot -ChildPath 'bin' + + if (-not (Test-Path $binTargetPath)) { + $null = New-Item -ItemType Directory -Path $binTargetPath + Write-Verbose -Verbose "Created bin directory for WIX at $binTargetPath" + } + + $x86TargetPath = Join-Path -Path $binPath -ChildPath 'x86' + + if (-not (Test-Path $x86TargetPath)) { + $null = New-Item -ItemType Directory -Path $x86TargetPath + Write-Verbose -Verbose "Created x86 directory for WIX at $x86TargetPath" + } + + Write-Verbose "Fixing folder structure ..." -Verbose + Copy-Item -Path $docExpandPath -Destination $docTargetPath -Force + Copy-Item -Path $sdkExpandPath -Destination $sdkTargetPath -Force + Copy-Item -Path "$binPath\Microsoft.Signed.Wix\3.14.1\tools\*" -Destination $binTargetPath -Force + Copy-Item -Path $x86ExpandPath -Destination $x86TargetPath -Force -Recurse -Verbose + Copy-Item -Path "$x86ExpandPath\burn.exe" -Destination "$x86TargetPath\burn.exe" -Force -Verbose + + Append-Path -path $binPath + Write-Verbose "Done installing WIX!" +}