1

I am working on a script in PowerShell 5.1 and I got a issue that I cannot really make sense of :

@{test=@() | Where-Object {$_ -ne $null}} | ConvertTo-Json -Compres

returns

{"test":{}}

Yet

$null -eq (@() | Where-Object {$_ -ne $null})

is True

Why does ConvertTo-Json returns an empty object on a null pipe result ?

Nathan
  • 13
  • 3
  • Because PowerShell and `$null` have a weird relationship. An empty enumeration isn't quite, precisely, exactly the same as `$null` in all circumstances, even though PowerShell will usually pretend quite adequately that it is. Instead it's really a `System.Management.Automation.Internal.AutomationNull`. Explicitly converting to `[psobject]` will coerce it to a true `$null` (so `@{test=[psobject] (@() | Where-Object {$_ -ne $null})}`). Note that this is fixed in PowerShell 7.2.5 without requiring an explicit conversion (and probably earlier, but I can't find the issue). – Jeroen Mostert Aug 03 '22 at 12:54
  • this by itself isn't proper to being with: `test=@() | Where-Object {$_ -ne $null}`. – Abraham Zinala Aug 03 '22 at 13:23
  • 1
    @AbrahamZinala: but that's not what's being used here -- `@{test=@() | Where-Object {$_ -ne $null}}` is a perfectly valid expression that creates a hash table with a single key named `test` (and a value that's an `AutomationNull`). – Jeroen Mostert Aug 03 '22 at 13:36
  • @JeroenMostert, the original bug report is https://github.com/PowerShell/PowerShell/issues/9231, and it seems the issue was fixed in 7.0. I encourage you to write up your comment as an answer. – mklement0 Aug 03 '22 at 14:18
  • 1
    @mklement0: I might have known that would be one of yours. :) – Jeroen Mostert Aug 03 '22 at 14:29
  • @JeroenMostert :) – mklement0 Aug 03 '22 at 14:33

1 Answers1

1

Two issues at play here. First, an empty pipeline is not the same thing as $null, as explained in "Why is an empty PowerShell pipeline not the same as null?" @{test=@() | Where-Object {$_ -ne $null}} produces a hash table with a test key that has an AutomationNull value, not $null.

Second, there's a bug in PowerShell prior to 7.0 where AutomationNull is serialized as an empty object rather than $null, as reported in "ConvertTo-Json unexpectedly serializes AutomationValue.Null as an empty object, not null" (powershell#9231).

To work around this bug in older versions, you can coerce the AutomationNull to a real $null by inserting a psobject cast, which will then result in the value serializing properly:

@{test=[psobject](@() | Where-Object {$_ -ne $null})} | ConvertTo-Json -Compres
Jeroen Mostert
  • 27,176
  • 2
  • 52
  • 85