Why is an empty PowerShell pipeline not the same as null?

Expanding on Frode F.’s answer, “nothing” is a mostly magical value in PowerShell – it’s called [System.Management.Automation.Internal.AutomationNull]::Value. The following will work similarly:

$y = 1,2,3,4 | ? { $_ -ge 5 }
$y = [System.Management.Automation.Internal.AutomationNull]::Value

PowerShell treats the value AutomationNull.Value like $null in most places, but not everywhere. One notable example is in a pipeline:

$null | % { 'saw $null' }
[System.Management.Automation.Internal.AutomationNull]::Value | % { 'saw AutomationNull.Value' }

This will only print:

saw $null

Note that expressions are themselves pipelines even if you don’t have a pipeline character, so the following are roughly equivalent:

@($y)
@($y | Write-Output)

Understanding this, it should be clear that if $y holds the value AutomationNull.Value, nothing is written to the pipeline, and hence the array is empty.

One might ask why $null is written to the pipeline. It’s a reasonable question. There are some situations where scripts/cmdlets need to indicate “failed” without using exceptions – so “no result” must be different, $null is the obvious value to use for such situations.

I’ve never run across a scenario where one needs to know if you have “no value” or $null, but if you did, you could use something like this:

function Test-IsAutomationNull
{
    param(
        [Parameter(ValueFromPipeline)]
        $InputObject)

    begin
    {
        if ($PSBoundParameters.ContainsKey('InputObject'))
        {
            throw "Test-IsAutomationNull only works with piped input"
        }
        $isAutomationNull = $true
    }
    process
    {
        $isAutomationNull = $false
    }
    end
    {
        return $isAutomationNull
    }
}

dir nosuchfile* | Test-IsAutomationNull
$null | Test-IsAutomationNull

Leave a Comment