C# and other languages have null-conditionals usually ?.
A?.B?.Do($C);
Will not error out when A or B are null. How do I achieve something similar in powershell, what's a nicer way to do:
if ($A) {
if ($B) {
$A.B.Do($C);
}
}
Powershell 7 Preview 5 has operators that deal with nulls. https://devblogs.microsoft.com/powershell/powershell-7-preview-5/
$a = $null
$a ?? 'is null' # return $a or string if null
is null
$a ??= 'no longer null' # assign if null
$a ?? 'is null'
no longer null
EDIT: Powershell 7 Preview 6 piles on more new operators: https://devblogs.microsoft.com/powershell/powershell-7-preview-6/. Since variable names can have a '?' in the name, you have to surround the variable name with curly braces:
${A}?.${B}?.Do($C)
PowerShell doesn't have the null-conditional operator, but it silently ignores property references on null-value expressions, so you can just "skip" to the method call at the end of the chain:
if($null -ne $A.B){
$A.B.Do($C)
}
Works at any depth:
if($null -ne ($target = $A.B.C.D.E)){
$target.Do($C)
}
As Mathias R. Jessen's answer points out, PowerShell by default has null-conditional access behavior (null-soaking) with respect to property access[1]; e.g., $noSuchVar.Prop
quietly returns $null
js2010's answer shows the related null-coalescing operator (??
) / null-conditional-assignment operators (??=
), which are available in PowerShell [Core] v 7.1+
However, up to PowerShell 7.0:
There is no way to null-conditionally ignore method calls: $noSuchVar.Foo()
always fails.
Similarly, there's no way to null-conditionally ignore (array) indexing: $noSuchVar[0]
always fails.
If you opt into more rigorous behavior with Set-StrictMode
, even the property-access null-soaking is no longer an option: with Set-StrictMode -Version 1
or higher, $noSuchVar.Prop
results in an error.
In PowerShell [Core] 7.1+, null-conditional (null-soaking) operators are available:
The new operators:
have the same form as in C# in principle: ?.
and ?[...]
but - as of v7.1 - require enclosing the variable name in {...}
That is, you currently cannot use just $noSuchVar?.Foo()
, $A?.B
, or $A?[1]
, you have to use
${noSuchVar}?.Foo()
, ${A}?.B
, or ${A}?[1]
The reason for this cumbersome syntax is that there are backward-compatibility concerns, because ?
is a legitimate character in variable names, so hypothetical existing code such as $var? = @{ one = 1}; $var?.one
could break without using the {...}
to disambiguate the variable name; in practice, such use is vanishingly rare.
If you think that not encumbering the new syntax is more important than potentially breaking scripts with variable names ending in ?
, make your voice heard at this GitHub issue.
[1] PowerShell's default behavior even offers existence-conditional property access; e.g., $someObject.NoSuchProp
quietly returns $null
.