ConvertTo-Json depth is a quiet source of broken automation
PowerShell defaults to a JSON depth of two. Make serialization depth explicit, fail on warnings, and test the actual payload shape.
ConvertTo-Json defaults to a depth of 2. That is enough for flat command output and too shallow for many API payloads, configuration documents, and nested request bodies.
When the input object exceeds the selected depth, PowerShell can produce JSON that is syntactically valid but no longer represents the object you intended to send. Current PowerShell versions emit a warning, but warnings are easy to miss in scheduled jobs and noisy pipelines.
Make depth part of the payload contract
Microsoft’s documentation defines -Depth as the number of contained object levels included in the JSON representation. The supported range is 0 to 100, with a default of 2.
Use an explicit value whenever the schema is nested:
$payload = [ordered]@{
device = @{
settings = @{
updateRing = @{
channel = "stable"
deferralDays = 7
}
}
}
}
$json = $payload | ConvertTo-Json -Depth 6
The number 6 is not a universal recommendation. It is an assertion that this payload is expected to fit within six levels. Choose a value that covers the known schema with a small margin, then keep the schema under test.
Using -Depth 100 everywhere suppresses one class of failure but also makes accidental serialization of large object graphs harder to notice. Explicit and bounded is easier to review.
Turn truncation warnings into failures
PowerShell 7.1 and later warns when the input exceeds the selected depth. For automation, promote that warning to a terminating error so the job cannot quietly continue with a damaged payload:
$json = $payload | ConvertTo-Json -Depth 6 -WarningAction Stop
This is especially useful before Invoke-RestMethod, where an API may accept the JSON and reject only a deeply nested field with an unhelpful validation message.
Windows PowerShell and older PowerShell versions can behave differently around warnings, so do not rely on warning handling as the only test. Validate the serialized result itself.
Test the string that leaves the process
Inspecting $payload proves that the PowerShell object is correct. It does not prove that serialization preserved it. Parse the final JSON and assert required nested values:
$roundTrip = $json | ConvertFrom-Json
if ($roundTrip.device.settings.updateRing.channel -ne "stable") {
throw "Serialized payload lost updateRing.channel"
}
if ($roundTrip.device.settings.updateRing.deferralDays -ne 7) {
throw "Serialized payload lost updateRing.deferralDays"
}
For reusable automation, put these assertions in Pester tests and keep a representative payload fixture beside the code. Test arrays, empty collections, nulls, dates, enums, and any property whose type matters to the receiving API.
Keep conversion at the boundary
Build and validate native PowerShell objects through most of the script. Convert to JSON once, immediately before writing the file or sending the request. Passing JSON strings through several functions encourages double encoding and makes it unclear which layer owns serialization options.
Log payload structure carefully. A redacted fixture is usually safer than recording production request bodies that may contain tokens, identifiers, or user data.
Verification note
The nested-object and round-trip examples were checked as local PowerShell behavior. Version-specific warning behavior and API handling still need verification in the PowerShell edition and target service used by your automation.
// source record
Sources
- ConvertTo-Json Microsoft Learn · checked 12 June 2026