Skip to content

[release/v7.5.6] Build, package, and create VPack for the PowerShell-LTS store package within the same msixbundle-vpack pipeline (#150)#27240

Merged
daxian-dbw merged 2 commits intoPowerShell:release/v7.5.6from
daxian-dbw:backport/release/v7.5.6/27209-073f4d61b
Apr 9, 2026
Merged

[release/v7.5.6] Build, package, and create VPack for the PowerShell-LTS store package within the same msixbundle-vpack pipeline (#150)#27240
daxian-dbw merged 2 commits intoPowerShell:release/v7.5.6from
daxian-dbw:backport/release/v7.5.6/27209-073f4d61b

Conversation

@daxian-dbw
Copy link
Copy Markdown
Member

Backport of #27209 to release/v7.5.6

Triggered by @daxian-dbw on behalf of @daxian-dbw

Original CL Label: CL-BuildPackaging

/cc @PowerShell/powershell-maintainers

Impact

REQUIRED: Choose either Tooling Impact or Customer Impact (or both). At least one checkbox must be selected.

Tooling Impact

  • Required tooling change
  • Optional tooling change (include reasoning)

Updates the release/v7.5.6 VPack pipeline so the PowerShell-LTS store package is built, packaged, and prepared for VPack creation within the same official pipeline, including related packaging and symbol publication changes required for compliance.

Customer Impact

  • Customer reported
  • Found internally

Regression

REQUIRED: Check exactly one box.

  • Yes
  • No

This is not a regression.

Testing

Cherry-pick completed on release/v7.5.6 after resolving one resource-file conflict in TabCompletionStrings.resx. Validation included confirming the incoming resource entries were preserved, all conflict markers were removed, and the remaining changes applied cleanly across the pipeline, packaging, and source files. Release branch CI will provide end-to-end verification.

Risk

REQUIRED: Check exactly one box.

  • High
  • Medium
  • Low

Medium risk because the change touches official packaging pipeline configuration and several packaging-related source files, but the conflict resolution was narrowly scoped to a single .resx resource block and the overall backport remains aligned with the original PR intent.

Merge Conflicts

Conflict in src/System.Management.Automation/resources/TabCompletionStrings.resx. Cause: the target release branch and the original PR both changed the same resource region. Resolution: accepted the incoming PR resource entries and preserved the surrounding release branch file structure.

@daxian-dbw daxian-dbw added the CL-BuildPackaging Indicates that a PR should be marked as a build or packaging change in the Change Log label Apr 9, 2026
Copilot AI review requested due to automatic review settings April 9, 2026 18:38
@daxian-dbw daxian-dbw added the CL-BuildPackaging Indicates that a PR should be marked as a build or packaging change in the Change Log label Apr 9, 2026
@daxian-dbw daxian-dbw requested a review from a team as a code owner April 9, 2026 18:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Backport updating the msixbundle-vpack official pipeline on release/v7.5.6 to build/sign LTS MSIX packages from source in the same pipeline run, then bundle/sign and prepare a VPack payload, with symbol publication and a few related string/resource updates.

Changes:

  • Refactors .pipelines/MSIXBundle-vPack-Official.yml into multi-stage build/package/bundle-sign flow (x64 + arm64) and adds a symbols publish stage.
  • Updates console host banner resource key usage and a couple of resource strings.
  • Minor cleanup in packaging and telemetry code.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
.pipelines/MSIXBundle-vPack-Official.yml Reworks the pipeline to build/sign MSIX from source, bundle/sign MSIXBundle, create VPack, and publish symbols.
tools/packaging/packaging.psm1 Minor comment/format cleanup in MSIX packaging function.
src/System.Management.Automation/utils/Telemetry.cs Small refactor/cleanup in telemetry property initialization and internal call sites.
src/System.Management.Automation/resources/TabCompletionStrings.resx Adds tab-completion help strings for hashtable keys / #requires and related keywords.
src/System.Management.Automation/resources/RemotingErrorIdStrings.resx Updates a remoting error string to “PowerShell 7+”.
src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx Renames the banner resource key.
src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs Updates banner resource reference and minor local variable style.
src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs Adjusts stdout-redirection flag assignment style.
PowerShell.Common.props Minor condition formatting tweak.

Comment on lines +358 to +366
$cmd = Get-Command makeappx.exe -ErrorAction Ignore
if ($cmd) {
Write-Verbose -Verbose 'makeappx available in PATH'
$exePath = $cmd.Source
} else {
$makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' |
Where-Object { $_.DirectoryName -match 'x64' } |
Select-Object -Last 1
$exePath = $makeappx.FullName
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the makeappx discovery step, if makeappx.exe is not in PATH and the Windows Kits search returns no results (or the Kits path doesn’t exist), $makeappx will be $null and $exePath = $makeappx.FullName will throw. Add explicit checks and fail with a clear error if makeappx can’t be located (and consider using -ErrorAction Stop/SilentlyContinue appropriately on Get-ChildItem).

Suggested change
$cmd = Get-Command makeappx.exe -ErrorAction Ignore
if ($cmd) {
Write-Verbose -Verbose 'makeappx available in PATH'
$exePath = $cmd.Source
} else {
$makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' |
Where-Object { $_.DirectoryName -match 'x64' } |
Select-Object -Last 1
$exePath = $makeappx.FullName
$cmd = Get-Command makeappx.exe -ErrorAction SilentlyContinue
if ($cmd) {
Write-Verbose -Verbose 'makeappx available in PATH'
$exePath = $cmd.Source
} else {
$windowsKitsRoot = 'C:\Program Files (x86)\Windows Kits\10'
$makeAppxExe = $null
if (Test-Path -Path $windowsKitsRoot) {
$makeAppxExe = Get-ChildItem -Path $windowsKitsRoot -Filter makeappx.exe -File -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.DirectoryName -match 'x64' } |
Select-Object -Last 1
}
if (-not $makeAppxExe) {
throw "Unable to locate makeappx.exe. It was not found in PATH and no suitable copy was found under '$windowsKitsRoot'."
}
$exePath = $makeAppxExe.FullName

Copilot uses AI. Check for mistakes.
Comment on lines +379 to +385
$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]
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create MsixBundle assumes at least one .msix was downloaded and that $file.BaseName contains -win. If no .msix files are present (or naming differs), $file will be $null and bundle naming/prefix extraction will fail. Consider validating the .msix count (expected 2: x64 + arm64), filtering Get-ChildItem to *.msix, and throwing a descriptive error when expectations aren’t met.

Suggested change
$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]
$msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads" -Filter '*.msix' -Recurse -File
foreach ($msixFile in $msixFiles) {
$null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose
}
$copiedMsixFiles = Get-ChildItem -Path $sourceDir -Filter '*.msix' -File
if ($copiedMsixFiles.Count -ne 2) {
$discoveredMsixNames = if ($copiedMsixFiles) { $copiedMsixFiles.Name -join ', ' } else { '<none>' }
throw "Expected exactly 2 .msix files (x64 + arm64) in '$sourceDir', but found $($copiedMsixFiles.Count): $discoveredMsixNames"
}
$bundleSourceFile = $copiedMsixFiles | Select-Object -First 1
if ($bundleSourceFile.BaseName -notmatch '-win') {
throw "Unable to derive msixbundle name from '$($bundleSourceFile.Name)' because the base name does not contain '-win'."
}
$prefix = ($bundleSourceFile.BaseName -split '-win', 2)[0]
if ([string]::IsNullOrWhiteSpace($prefix)) {
throw "Unable to derive a valid msixbundle prefix from '$($bundleSourceFile.Name)'."
}

Copilot uses AI. Check for mistakes.
Comment on lines +286 to +287
$msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File
$msixPkgPath = $msixPkgFile.FullName
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packaging step uses Get-ChildItem $repoRoot -Filter "PowerShell*.msix" and then immediately accesses .FullName without validating results. If packaging fails to produce an MSIX (or produces more than one match), this will either throw later or copy the wrong file(s). Add a check that exactly one expected MSIX is found (or tighten the filter to the expected LTS MSIX naming pattern).

Suggested change
$msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File
$msixPkgPath = $msixPkgFile.FullName
$msixPkgFiles = @(Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File)
if ($msixPkgFiles.Count -eq 0) {
throw "No MSIX package matching '$msixPkgNameFilter' was found in '$repoRoot' after packaging."
}
if ($msixPkgFiles.Count -gt 1) {
$msixPkgFileList = ($msixPkgFiles | ForEach-Object { $_.FullName }) -join [Environment]::NewLine
throw "Expected exactly one MSIX package matching '$msixPkgNameFilter' in '$repoRoot', but found $($msixPkgFiles.Count):$([Environment]::NewLine)$msixPkgFileList"
}
$msixPkgPath = $msixPkgFiles[0].FullName

Copilot uses AI. Check for mistakes.
Comment on lines +413 to +415
$signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File
Write-Verbose -Verbose "Signed bundle: $signedBundle"

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$signedBundle = Get-ChildItem ... -Filter "*.msixbundle" can return 0 or multiple files; the subsequent .FullName and signature verification will then fail or behave unpredictably. Treat this as an invariant and validate you found exactly one bundle before proceeding.

Suggested change
$signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File
Write-Verbose -Verbose "Signed bundle: $signedBundle"
$signedBundles = @(Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File)
Write-Verbose -Verbose "Found $($signedBundles.Count) signed bundle(s) in $(BundleDir)"
if ($signedBundles.Count -ne 1) {
$bundlePaths = if ($signedBundles.Count -gt 0) { ($signedBundles.FullName -join ', ') } else { '<none>' }
throw "Expected exactly one signed .msixbundle in $(BundleDir), but found $($signedBundles.Count): $bundlePaths"
}
$signedBundle = $signedBundles[0]
Write-Verbose -Verbose "Signed bundle: $($signedBundle.FullName)"

Copilot uses AI. Check for mistakes.
Write-Host ("sending " + $vstsCommandString)
Write-Host "##$vstsCommandString"
displayName: Create MsixBundle
retryCountOnTaskFailure: 1
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job performs signing, but the steps that prepare inputs for the first signing operation (artifact downloads + bundle creation) aren’t marked with env: ob_restore_phase: true. In other signing jobs (e.g. .pipelines/templates/packaging/windows/sign.yml), pre-sign steps run in restore phase to keep signing setup/validation scoped to the signing portion and reduce overhead. Consider moving those pre-sign steps into restore phase and leaving only post-sign steps in build phase.

Suggested change
retryCountOnTaskFailure: 1
retryCountOnTaskFailure: 1
env:
ob_restore_phase: true

Copilot uses AI. Check for mistakes.
</data>
<data name="LabelHashtableKeyDescription" xml:space="preserve">
<value>[string]
Specifies the name of the property being created.</value>
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LabelHashtableKeyDescription duplicates the NameHashtableKeyDescription text (“Specifies the name…”). This looks like a copy/paste error and will show incorrect help text for the Label hashtable key in tab completion; update it to describe the label/display name semantics instead of the property name.

Suggested change
Specifies the name of the property being created.</value>
Specifies the label or display name for the property.</value>

Copilot uses AI. Check for mistakes.
<data name="DataHashtableKeyDescription" xml:space="preserve">
<value>[string[]]
Selects events with any of the specified values in the EventData section.</value>
</data>
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line has trailing whitespace after </data>; please remove to keep the .resx clean and avoid churn in future diffs.

Suggested change
</data>
</data>

Copilot uses AI. Check for mistakes.
- name: WindowsContainerImage
value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest'
- name: Codeql.Enabled
value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment for Codeql.Enabled says this pipeline “is not building artifacts; it repackages existing artifacts”, but this pipeline now builds and signs MSIX packages from source. Please update/remove the comment so it reflects current behavior (and confirm the intended Codeql.Enabled value given CodeQL tasks are enabled later).

Suggested change
value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack
value: true

Copilot uses AI. Check for mistakes.
@daxian-dbw daxian-dbw merged commit c3999de into PowerShell:release/v7.5.6 Apr 9, 2026
38 checks passed
@daxian-dbw daxian-dbw deleted the backport/release/v7.5.6/27209-073f4d61b branch April 9, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-BuildPackaging Indicates that a PR should be marked as a build or packaging change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants