Updated 29 Sep 2016: Fixed a bug in IsNull where Bruno Martins pointed out it returned True for 0. This said… this post is super old… and should be ignored.
When you're checking for a null in PowerShell there are 4 different kinds that can crop up (either expectedly or unexpectedly). Here of course the real null:
$a = $null
$a -eq $null
# True
But there's also a .NET type which is a placeholder for the null you'd get when pulling data from a database:
$a = [DBNull]::Value
$a -eq $null
# False
$a -eq [DBNull]::Value
# True
And then there's this when you're looking for null in strings, it might just be an empty string.
[string] $a = $null
$a -eq $null
# False
$a -eq "" -and $a -eq [String]::Empty
# True
if (!$a) {
Write-Host "True"
} else {
Write-Host "False"
}
# True
That is insidious because if you write a function that explicitly types its argument as [string] PowerShell will prevent you from passing in $null, always converting it to [String]::Empty.
Which is how the fourth kind of "null" was made. People complained about the above on Microsoft Connect so in PowerShell v4 the team added a special null type for strings:
[string] $a = [System.Management.Automation.Language.NullString]::Value
$a -eq $null
# True
$a -eq "" -and $a -eq [String]::Empty
# False
if (!$a) {
Write-Host "True"
} else {
Write-Host "False"
}
# True
Gross. This appears to work for other explicitly declared types too; whatever you assign to it is going to come out the other end as $null. Kind of.
[int] $a = [System.Management.Automation.Language.NullString]::Value
$a -eq $null
# True
if (!$a) {
Write-Host "True"
} else {
Write-Host "False"
}
# True
Oddly though if you assign it to an untyped variable it won't be considered a real $null. It takes on the type of the class.
$b = [System.Management.Automation.Language.NullString]::Value
$b -eq $null
# False
if (!$b) {
Write-Host "True"
} else {
Write-Host "False"
}
# False
$b.GetType()
# IsPublic IsSerial Name BaseType
# -------- -------- ---- --------
# True False NullString System.Object
For the sake of being pedantic here's a function to check for all of them.
function IsNull($objectToCheck) {
if ($objectToCheck -eq $null) {
return $true
}
if ($objectToCheck -is [String] -and $objectToCheck -eq [String]::Empty) {
return $true
}
if ($objectToCheck -is [DBNull] -or $objectToCheck -is [System.Management.Automation.Language.NullString]) {
return $true
}
return $false
}
IsNull($null)
# True
IsNull($c) # Where $c wasn't declared yet
# True
IsNull([string] $c)
# True
IsNull("")
# True
IsNull([DBNull]::Value)
# True
IsNull(1)
# False
IsNull(New-Object System.DateTime)
# False
IsNull("Looking Good")
# False
IsNull(0)
# False