microsoft / microsoft/SdnDiagnostics
Simplify duplicate-key handling in Copy-ObjectWithPropertyOverride
Nobody has claimed this yet.
- Dominant language
- PowerShell
- Stars
- 34
- Forks
- 6
- Avg merge
- 5d 14h
- Merged PRs (30d)
- 5
Description
Follow-up to review feedback on #630 (comment).
Context
Copy-ObjectWithPropertyOverride in src/modules/SdnDiag.Utilities.psm1 currently guards against an override hashtable containing more than one key that matches the same property name:
$matchingKeys = @($PropertyOverride.Keys | Where-Object { $_ -ieq $property.Name })
if ($matchingKeys.Count -gt 1) {
throw New-Object System.ArgumentException("PropertyOverride contains multiple keys that match the property '$($property.Name)'.")
}
@andrwli flagged this as likely dead code, on the grounds that hashtable literals are case-insensitive.
Assessment
The premise is correct — a hashtable literal genuinely cannot hold case-variant duplicate keys. It fails at parse time on both Windows PowerShell 5.1 and PowerShell 7:
Duplicate keys 'NAME' are not allowed in hash literals.
The branch is not strictly unreachable, however. The parameter is typed [System.Collections.Hashtable], and a hashtable built through the constructor uses the default case-sensitive comparer:
| Construction | Holds name + NAME? |
Binds to the parameter? |
|---|---|---|
@{ ... } literal |
No (parse error) | n/a |
[System.Collections.Hashtable]::new() |
Yes | Yes |
[System.Collections.Hashtable]::new([StringComparer]::Ordinal) |
Yes | Yes |
The existing Pester test "Throws when more than one override key matches the same property" constructs exactly that and passes, so the branch does execute today.
That said, @andrwli is right in practice:
Copy-ObjectWithPropertyOverrideis not inFunctionsToExport, so it is private with no external callers.- Both call sites pass literals —
@{ 'properties' = $modifiedProperties }, and$updatedPropertieswhich is@{}populated with the hardcoded keys'routes'and'networkConnections'.
No production path can reach the throw.
Why the guard was added
It was not arbitrary. The original implementation used ... | Select-Object -First 1, which with case-variant duplicate keys silently returned a different value depending on the engine — value 2 on PowerShell 5.1 versus value 1 on PowerShell 7.6.5. The throw replaced silent, engine-dependent behavior with a loud failure.
Note the surrounding case-insensitive -ieq scan is worth keeping regardless: it lets an override key of 'properties' match a property named 'Properties', which matters for Network Controller REST objects where JSON casing varies.
Proposed change
Remove the throw and instead make the selection deterministic by preferring an exact-case match, falling back to the case-insensitive match:
- Resolves the real casing-mismatch scenario deterministically
- Handles duplicates sensibly without raising an exception
- Leaves no unreachable branch for the next reader to flag
Alternatively, simply drop the guard and index $matchingKeys[0], accepting the latent cross-engine nondeterminism given no caller can trigger it.
Acceptance criteria
-
Copy-ObjectWithPropertyOverrideno longer contains a branch unreachable from any caller - Behavior is deterministic and identical on Windows PowerShell 5.1 and PowerShell 7
- Case-insensitive property-name matching is preserved
- The
.PARAMETER PropertyOverridehelp text is updated to drop the "An exception is raised..." sentence - The corresponding Pester test in
tests/offline/Utilities.Tests.ps1is updated or removed - Offline Pester suite passes
Notes
Deferred rather than fixed in #630 because the PR was already approved and required_review_thread_resolution is false on main, so the open thread does not gate the merge.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Copy-ObjectWithPropertyOverride in src/modules/SdnDiag.Utilities.psm1 and its .PARAMETER PropertyOverride help text. Read the related test in tests/offline/Utilities.Tests.ps1, then run the offline Pester suite on Windows PowerShell 5.1 and PowerShell 7. Done means deterministic case handling, preserved case-insensitive matching, updated documentation and tests, with the suite passing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- powershell
- Domain
- testing, tooling
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100