diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs index b72c348ffd9..3becd07437e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Management.Automation; +using System.Management.Automation.Language; using System.Reflection; using System.Text.RegularExpressions; using System.Threading; @@ -496,6 +497,11 @@ private static object ProcessValue(object obj, int currentDepth, in ConvertToJso { context.CancellationToken.ThrowIfCancellationRequested(); + if (LanguagePrimitives.IsNull(obj)) + { + return null; + } + PSObject pso = obj as PSObject; if (pso != null) @@ -507,18 +513,21 @@ private static object ProcessValue(object obj, int currentDepth, in ConvertToJso bool isPurePSObj = false; bool isCustomObj = false; - if (obj == null - || DBNull.Value.Equals(obj) - || obj is string - || obj is char - || obj is bool - || obj is DateTime - || obj is DateTimeOffset - || obj is Guid - || obj is Uri - || obj is double - || obj is float - || obj is decimal) + if (obj == NullString.Value + || obj == DBNull.Value) + { + rv = null; + } + else if (obj is string + || obj is char + || obj is bool + || obj is DateTime + || obj is DateTimeOffset + || obj is Guid + || obj is Uri + || obj is double + || obj is float + || obj is decimal) { rv = obj; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 index 371aff5b9ce..1f09ea4a0ef 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.Tests.ps1 @@ -69,4 +69,38 @@ Describe 'ConvertTo-Json' -tags "CI" { ConvertTo-Json -Compress $null | Should -Be 'null' 1, $null, 2 | ConvertTo-Json -Compress | Should -Be '[1,null,2]' } + + It "Should handle 'AutomationNull.Value' and 'NullString.Value' correctly" { + [ordered]@{ + a = $null; + b = [System.Management.Automation.Internal.AutomationNull]::Value; + c = [System.DBNull]::Value; + d = [NullString]::Value + } | ConvertTo-Json -Compress | Should -BeExactly '{"a":null,"b":null,"c":null,"d":null}' + + ConvertTo-Json ([System.Management.Automation.Internal.AutomationNull]::Value) | Should -BeExactly 'null' + ConvertTo-Json ([NullString]::Value) | Should -BeExactly 'null' + + ConvertTo-Json -Compress @( + $null, + [System.Management.Automation.Internal.AutomationNull]::Value, + [System.DBNull]::Value, + [NullString]::Value + ) | Should -BeExactly '[null,null,null,null]' + } + + It "Should handle the ETS properties added to 'DBNull.Value' and 'NullString.Value'" { + try + { + $p1 = Add-Member -InputObject ([System.DBNull]::Value) -MemberType NoteProperty -Name dbnull -Value 'dbnull' -PassThru + $p2 = Add-Member -InputObject ([NullString]::Value) -MemberType NoteProperty -Name nullstr -Value 'nullstr' -PassThru + + $p1, $p2 | ConvertTo-Json -Compress | Should -BeExactly '[{"value":null,"dbnull":"dbnull"},{"value":null,"nullstr":"nullstr"}]' + } + finally + { + $p1.psobject.Properties.Remove('dbnull') + $p2.psobject.Properties.Remove('nullstr') + } + } }