Skip to content

fix: unwrap PSObject-wrapped values when serializing Invoke-MgGraphRequest dictionary bodies#3658

Draft
Virgil-Bulens wants to merge 1 commit into
microsoftgraph:mainfrom
Virgil-Bulens:fix/3654-psobject-body-serialization
Draft

fix: unwrap PSObject-wrapped values when serializing Invoke-MgGraphRequest dictionary bodies#3658
Virgil-Bulens wants to merge 1 commit into
microsoftgraph:mainfrom
Virgil-Bulens:fix/3654-psobject-body-serialization

Conversation

@Virgil-Bulens

Copy link
Copy Markdown

Fixes #3654

Changes proposed in this pull request

  • Add PSObjectJsonConverter, a Newtonsoft JsonConverter that unwraps PSObject-wrapped values to their BaseObject during serialization, at any nesting depth. Pure PSCustomObjects (which have no underlying CLR object) are projected into JSON objects from their properties.
  • Pass the converter at the single JsonConvert.SerializeObject call site in InvokeMgGraphRequest.SetRequestContent(HttpRequestMessage, IDictionary), so idiomatic hashtable bodies containing pipeline-produced values (bare $_ in ForEach-Object) serialize the underlying CLR values instead of failing with Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'.
  • Add xUnit tests covering PSObject-wrapped strings/primitives/dictionaries, PSCustomObject bodies, and the SetRequestContent wiring (made internal; the assembly already has InternalsVisibleTo for the test project).
  • Pin the test project's Microsoft.PowerShell.SDK reference to 7.4.17. 7.5.x targets net9.0 only and contributes no assemblies to the net8.0 test build, which silently left the PowerShellStandard.Library stub (whose APIs return null) as the runtime System.Management.Automation. This is why the existing ShouldReturnPsObject tests fail on net8.0, and it made the new PSObject-dependent tests impossible to run. With the pin, the pre-existing StringUtilTests.ShouldReturnPsObject failures on net8.0 are also resolved.

Verification

  • dotnet test src/Authentication/Authentication.Test -f net8.0: 84/85 pass on Linux; the one failure (AuthenticationHelpersTests.ShouldThrowIfNonExistentCertNameIsProvidedAsync) is pre-existing on an unmodified checkout of main and unrelated (certificate store).
  • The exact repro from Invoke-MgGraphRequest -Body serialization fails on PSObject-wrapped pipeline strings #3654 was run in PowerShell 7.6 against the patched assembly and now produces:
    {"message":{"toRecipients":[{"emailAddress":{"address":"recipient@example.com"}}]},"saveToSentItems":true}
  • A nested [pscustomobject]@{ address = "..." } body value, which previously failed the same way, serializes to {"emailAddress":{"address":"recipient@example.com"}}.

Other links

…quest dictionary bodies

Invoke-MgGraphRequest -Body serializes IDictionary bodies with
Newtonsoft.Json. Values that came from the PowerShell pipeline (e.g.
bare $_ in ForEach-Object) are PSObject wrappers, so Newtonsoft
reflected over PowerShell adapted members (such as the Chars indexed
property on strings) and failed with a self-referencing loop error
before the request was sent.

Add a PSObjectJsonConverter that serializes the underlying BaseObject
of PSObject-wrapped values at any depth, and projects pure
PSCustomObjects into JSON objects, and pass it at the single
JsonConvert.SerializeObject call site for dictionary bodies.

Also pin the test project's Microsoft.PowerShell.SDK reference to the
latest 7.4.x release: 7.5.x targets net9.0 and contributes no
assemblies to the net8.0 test build, which silently left the
PowerShellStandard.Library stub (whose APIs return null) as the
runtime System.Management.Automation, making PSObject-dependent tests
impossible.

Fixes microsoftgraph#3654
@Virgil-Bulens

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

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.

Invoke-MgGraphRequest -Body serialization fails on PSObject-wrapped pipeline strings

1 participant