The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it evaluates the right-hand operand and returns its result.
% is an alias for the ForEach-Object cmdlet. An alias is just another name by which you can reference a cmdlet or function.
$null is one of the automatic variables in PowerShell, which represents NULL. You can use the -eq parameter to check if a string variable equals $null . It returns True if the variable is equal to $null and False if the variable is not equal to $null .
$null is an automatic variable in PowerShell used to represent NULL. You can assign it to variables, use it in comparisons and use it as a place holder for NULL in a collection. PowerShell treats $null as an object with a value of NULL. This is different than what you may expect if you come from another language.
Powershell 7 introduces native null coalescing, null conditional assignment, and ternary operators in Powershell.
Null Coalescing
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
Null Conditional Assignment
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
Ternary Operator
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
No need for the Powershell Community Extensions, you can use the standard Powershell if statements as an expression:
variable = if (condition) { expr1 } else { expr2 }
So to the replacements for your first C# expression of:
var s = myval ?? "new value";
becomes one of the following (depending on preference):
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
or depending on what $myval might contain you could use:
$s = if ($myval) { $myval } else { "new value" }
and the second C# expression maps in a similar way:
var x = myval == null ? "" : otherval;
becomes
$x = if ($myval -eq $null) { "" } else { $otherval }
Now to be fair, these aren't very snappy, and nowhere near as comfortable to use as the C# forms.
You might also consider wrapping it in a very simple function to make things more readable:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
or possibly as, IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
As you can see a very simple function can give you quite a bit of freedom of syntax.
UPDATE: One extra option to consider in the mix is a more generic IsTrue function:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
Then combine that is Powershell's ability to declare aliases that look a bit like operators, you end up with:
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
Clearly this isn't going to be to everyone's taste, but may be what you're looking for.
As Thomas notes, one other subtle difference between the C# version and the above is that C# performs short-circuiting of the arguments, but the Powershell versions involving functions/aliases will always evaluate all arguments. If this is a problem, use the if
expression form.
PowerShell 7 introduces many new features and migrates from .NET Framework to .NET Core. As of mid-2020, it hasn't completely replaced legacy versions of PowerShell due to the reliance on .NET Core, but Microsoft has indicated that they intend for the Core family to eventually replace the legacy Framework family. By the time you read this, a compatible version of PowerShell may come pre-installed on your system; if not, see https://github.com/powershell/powershell.
Per the documentation, the following operators are supported out-of-the-box in PowerShell 7.0:
??
??=
... ? ... : ...
These work as you would expect for null coalescing:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
Since a ternary operator has been introduced, the following is now possible, though it's unnecessary given the addition of a null coalescing operator:
$x = $a -eq $null ? $b : $a
As of 7.0, the following are also available if the PSNullConditionalOperators
optional feature is enabled, as explained in the docs (1, 2):
?.
?[]
These have a few caveats:
${}
if followed by one of the experimental operators because question marks are permitted in variable names. It's unclear if this will be the case if/when the features graduate from experimental status (see issue #11379). For example, ${x}?.Test()
uses the new operator, but $x?.Test()
runs Test()
on a variable named $x?
.?(
operator as you might expect if you're coming from TypeScript. The following won't work: $x.Test?()
PowerShell versions prior to 7 do have an actual null coalescing operator, or at least an operator that is capable of such behavior. That operator is -ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
It's a bit more versatile than a null coalescing operator, since it makes an array of all non-null items:
$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false
$instances = $items -ne $null
[string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() }))
# Result:
System.String, System.Int32, System.Int32, System.String, System.Object[],
System.Boolean, System.Boolean
-eq
works similarly, which is useful for counting null entries:
($null, 'a', $null -eq $null).Length
# Result:
2
But anyway, here's a typical case to mirror C#'s ??
operator:
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
This explanation is based on an edit suggestion from an anonymous user. Thanks, whoever you are!
Based on the order of operations, this works in following order:
,
operator creates an array of values to be tested.-ne
operator filters out any items from the array that match the specified value--in this case, null. The result is an array of non-null values in the same order as the array created in Step 1.[0]
is used to select the first element of the filtered array.Simplifying that:
Unlike C#'s null coalescing operator, every possible expression will be evaluated, since the first step is to create an array.
This is only half an answer to the first half of the question, so a quarter answer if you will, but there is a much simpler alternative to the null coalescing operator provided the default value you want to use is actually the default value for the type:
string s = myval ?? "";
Can be written in Powershell as:
([string]myval)
Or
int d = myval ?? 0;
translates to Powershell:
([int]myval)
I found the first of these useful when processing an xml element that might not exist and which if it did exist might have unwanted whitespace round it:
$name = ([string]$row.td[0]).Trim()
The cast to string protects against the element being null and prevents any risk of Trim()
failing.
$null, $null, 3 | Select -First 1
returns
3
If you install the Powershell Community Extensions Module then you can use:
?? is the alias for Invoke-NullCoalescing.
$s = ?? {$myval} {"New Value"}
?: is the alias for Invoke-Ternary.
$x = ?: {$myval -eq $null} {""} {$otherval}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With