Skip to content

Fix mocking commands with [OrderedDictionary] parameters on PowerShell 7#2886

Merged
nohwnd merged 1 commit into
mainfrom
nohwnd-fix-ordered-dictionary-mock-param
Jul 17, 2026
Merged

Fix mocking commands with [OrderedDictionary] parameters on PowerShell 7#2886
nohwnd merged 1 commit into
mainfrom
nohwnd-fix-ordered-dictionary-mock-param

Conversation

@nohwnd

@nohwnd nohwnd commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

Mocking a function that has a parameter typed [System.Collections.Specialized.OrderedDictionary] threw a ParseException on PowerShell 7, even though it worked on Windows PowerShell 5.1.

[System.Management.Automation.ProxyCommand]::GetParamBlock() — used to build the mock bootstrap function — serializes an OrderedDictionary parameter using the [ordered] type accelerator on PowerShell 7+. That accelerator is only valid as a cast on a hash literal ([ordered]@{}), not as a parameter type constraint, so the [scriptblock]::Create(...) that finalises the bootstrap function threw:

The ordered attribute can be specified only on a hash literal node.

before the test even ran. Windows PowerShell 5.1 emits the full type name instead, which is why it was unaffected.

Fix

Add a Repair-OrderedType helper (mirroring the existing Repair-EnumParameters) that rewrites the generated param-block, replacing the [ordered] / [ordered[]] accelerator in type-constraint position (the token immediately preceding ${ParameterName} for parameters the metadata reports as OrderedDictionary) with the full [System.Collections.Specialized.OrderedDictionary] type name. It is called right after Repair-EnumParameters. The match is bounded to the specific parameter variable so any legitimate [ordered]@{} cast is left untouched, and it early-returns when no [ordered] accelerator is present (e.g. on Windows PowerShell).

Tests

Added a regression Describe block in tst/functions/Mock.Tests.ps1 covering a scalar OrderedDictionary parameter, one mixed with other parameters, an OrderedDictionary[] array, and an end-to-end mock invoked through a wrapper with Should -Invoke. Confirmed these fail with the original ParseException before the fix and pass after it, on PowerShell 7.

Verification

  • ./build.ps1 succeeds.
  • ./test.ps1 -File tst/functions/Mock.Tests.ps1 -SkipPTests → 254 passed, 0 failed.
  • Invoke-ScriptAnalyzer -Path ./src -Recurse -Settings ./.github/workflows/PSScriptAnalyzerSettings.psd1 → no new findings on the changed lines.

Fix #2370

ProxyCommand.GetParamBlock serializes [System.Collections.Specialized.OrderedDictionary]
parameters using the [ordered] type accelerator on PowerShell 7+. That accelerator is
only valid as a cast on a hash literal ([ordered]@{}), not as a parameter type
constraint, so [scriptblock]::Create threw a ParseException while building the mock
bootstrap function before the test ran.

Add a Repair-OrderedType helper (mirroring Repair-EnumParameters) that rewrites the
generated param-block, replacing the [ordered] / [ordered[]] accelerator in
type-constraint position with the full System.Collections.Specialized.OrderedDictionary
type name. Windows PowerShell 5.1 already emits the full name, so it is unaffected.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nohwnd nohwnd added this to the 6.1.0 milestone Jul 17, 2026
@nohwnd
nohwnd merged commit a4b5f78 into main Jul 17, 2026
13 checks passed
@nohwnd
nohwnd deleted the nohwnd-fix-ordered-dictionary-mock-param branch July 17, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mocking a function with OrderedDictionary parameter throws error with PowerShell 7, runs fine with PowerShell 5

1 participant