PowerShell Conditional Pipeline: Handle Nulls and Empty Results

PowerShell Conditional Pipeline: Handle Nulls and Empty Results

PowerShell Tips Editor 3 min read
PowerShell Conditional Pipeline: Handle Nulls and Empty Results

The most surprising runtime errors in PowerShell come from commands that return nothing — not an error, just silence followed by a NullReferenceException when your code tries to use the result. Learning to PowerShell handle null empty pipeline results with defensive patterns prevents the “Cannot index into a null array” error that no one expects until it happens in a 3 AM production script.

Quick Answer / TL;DR

Use if ($result) { ... } for null/empty checks, $result ?? 'default' (PS7) for null coalescing, and if ($result.Count -eq 0) { ... } to distinguish an empty array from $null.

Check If Result Is Null or Empty

A command that finds nothing returns $null. A command that finds one match returns that object directly (not an array). A command that finds multiple matches returns an array. Your defensive code must handle all three cases. The simplest check is a truthy if ($result), which handles $null, empty string, and zero.

# Get-ADUser returns $null when user not found
$user = Get-ADUser -Filter "SamAccountName -eq 'jsmith'" -ErrorAction SilentlyContinue

if ($null -ne $user) {
    Write-Host "Found: $($user.DisplayName)"
} else {
    Write-Host 'User not found'
}

# Check for null or empty string
$value = Get-ItemPropertyValue 'HKLM:\SOFTWARE\MyApp' -Name 'Version' -ErrorAction SilentlyContinue
if ([string]::IsNullOrWhiteSpace($value)) {
    Write-Warning 'Version value not set'
}

Default Value Pattern

When a null result should fall back to a default value, the conditional assignment pattern keeps code concise. This is the classic null coalescing pattern available in all PowerShell versions.

# Classic default value pattern (works in all PS versions)
$config = Get-Content C:\Config\settings.json -ErrorAction SilentlyContinue
if ($null -eq $config) { $config = '{}' }

# Or as one expression
$logDir = $env:LOG_PATH
if (-not $logDir) { $logDir = 'C:\Logs' }

# Parse JSON with fallback
$settings = try {
    Get-Content C:\Config\app.json -ErrorAction Stop | ConvertFrom-Json
} catch {
    [PSCustomObject]@{ Timeout = 30; MaxRetries = 3 }
}

Null Coalescing in PS7

PowerShell 7 introduced the ?? null-coalescing operator, which returns the left operand if it is not null, or the right operand if it is. It is syntactic sugar for the if/null pattern but reads more naturally in expressions.

# Null coalescing operator (PowerShell 7+)
$server = $env:TARGET_SERVER ?? 'localhost'
$port   = $env:APP_PORT ?? 8080

# Null coalescing assignment ??= (assigns only if null)
$connection = $null
$connection ??= Get-SqlConnection -Server $server

# Works with function results
$user = Get-ADUser -Filter "SamAccountName -eq 'jsmith'" -ErrorAction SilentlyContinue
$displayName = $user?.DisplayName ?? 'Unknown User'

Empty Collection vs $null Difference

An empty array @() is not $null — it is a collection with zero elements. In a boolean context, an empty array is $false, but $null -eq @() is $false. Use .Count -eq 0 to explicitly distinguish “no results” from “command returned null.”

# Empty array vs null
$null -eq @()          # False — they are different
[bool]@()              # False — empty array is falsy
[bool]$null            # False

# The correct check for an empty collection
$results = @()
if ($results.Count -eq 0) {
    Write-Host 'No results returned'
}

# Handle both null and empty consistently
if (-not $results -or $results.Count -eq 0) {
    Write-Host 'Nothing to process'
    return
}

If @() Count Check Pattern

When a cmdlet may return one object (not an array), $null, or multiple objects, wrap the result in @() to normalize it to always be an array. The @() array subexpression forces PowerShell to wrap single objects in an array, making .Count consistent.

# @() normalizes: null -> empty array, single object -> single-element array
$users = @(Get-ADUser -Filter "Department -eq 'IT'" -ErrorAction SilentlyContinue)

Write-Host "Found $($users.Count) IT users"

if ($users.Count -eq 0) {
    Write-Warning 'No IT users found — check department name'
    return
}

foreach ($user in $users) {
    # Safe: $users is always an array, even if only one user returned
    Write-Host $user.SamAccountName
}

Safe Navigation Operator ?.

PowerShell 7 introduced the null-conditional member access operator ?.. It returns $null instead of throwing when the left side is $null, preventing null reference errors when chaining property access.

# Without safe navigation — throws if $user is null
# $user.Department.ToUpper()    ← NullReferenceException if user or Department is null

# With safe navigation — returns null safely
$department = $user?.Department?.ToUpper()

# Practical example: get manager's email safely
$user     = Get-ADUser -Identity 'jsmith' -Properties Manager -ErrorAction SilentlyContinue
$manager  = if ($user?.Manager) { Get-ADUser -Identity $user.Manager -Properties Mail } else { $null }
$email    = $manager?.Mail ?? '[email protected]'
Write-Host "Manager email: $email"

Common Errors and Fixes

  • Get-ADUser returns $null for no results — check before accessing properties. Unlike Get-ChildItem which returns nothing (empty enumerable), Get-ADUser -Filter returns $null when no users match. Always check if ($null -ne $user) or @($users).Count -gt 0 before accessing .DisplayName or other properties.
  • Empty array is truthy in PowerShell — use .Count -eq 0 check. if ($emptyArray) evaluates to $false as expected. But if ($null -ne $emptyArray) evaluates to $true because @() is not null. When you need to distinguish “null” from “empty array,” explicitly check .Count rather than truthy/falsy evaluation.

Related Cmdlets / See Also

Wrapping Up

Defensive null handling is not optional in production scripts. Use @() to normalize results to arrays, .Count -eq 0 to check for empty collections, ?? 'default' (PS7) for null coalescing, and ?. for safe property chain access. These patterns eliminate the most common class of PowerShell runtime errors before they reach production.

Send-Item -To