microsoft / microsoft/SdnDiagnostics

Simplify duplicate-key handling in Copy-ObjectWithPropertyOverride

Open
#633 0 comments 0 reactions 0 assignees View on GitHub

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-ObjectWithPropertyOverride is not in FunctionsToExport, so it is private with no external callers.
  • Both call sites pass literals — @{ 'properties' = $modifiedProperties }, and $updatedProperties which 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-ObjectWithPropertyOverride no 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 PropertyOverride help text is updated to drop the "An exception is raised..." sentence
  • The corresponding Pester test in tests/offline/Utilities.Tests.ps1 is 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.