1
Param(
    [String] $foo
)

$foo ??= "bar" # does not work
$foo = $foo ?? "bar" # does not work
$foo = $foo ? $foo : "bar" # works

write-host $foo

I am using Powershell 7.4.5

What am I doing wrong here?

3
  • 3
    The operator works just fine, $foo just never happens to be $null Commented Oct 4, 2024 at 8:31
  • 1
    Your parameter is typed string a null value passed as argument to this script will be coerced to empty string and an empty string is never null. Commented Oct 4, 2024 at 12:28
  • As for why the ternary operator works: it isn't based on $null, but on coercing the first operand to a Boolean (which PowerShell implicitly supports for instances of any data type). Thus, given the - undoubtedly surprising - coercion of $null to '' (the empty string) when assigning to [string]-typed (parameter) variables, your ternary expression is the equivalent of '' ? '' : "bar", which predictably yiels "bar", given that '' is coerced to $false (whereas any non-empty string is $true). Commented May 2 at 13:36

2 Answers 2

2

The following script without parameters works just fine:

$foo=$null
$foo ??= "bar"

Write-Host $foo

The problem seems to be the way Powershell handles string parameters in scripts. When omitting a string parameter or setting its default value to $null, Powershell will convert the value to an empty string (see How can I prevent a string argument changing from null to empty when bound to a parameter?).

Consider the following script:

Param(
    [String]
    $foo
)

if ($null -eq $foo) {
  Write-Host "The parameter 'foo' is null."
} else {
  Write-Host "The parameter 'foo' is not null."
}

if ("" -eq $foo) {
  Write-Host "The parameter 'foo' is an empty string."
} else {
  Write-Host "The parameter 'foo' is not an empty string."
}

Running the script:

PS C:\src\dummy-6\scripts> .\my-script.ps1 -foo $null
The parameter 'foo' is not null.
The parameter 'foo' is an empty string.


PS C:\src\dummy-6\scripts> .\my-script.ps1
The parameter 'foo' is not null.
The parameter 'foo' is an empty string.
PS C:\src\dummy-6\scripts> 

Even if you set the default value of the parameter to $null it won't work as expected.

Also, the AllowNull validation attribute doesn't work if the type converter is set to string as the string type won't accept a null value.

Changing slightly the script:

Param(
    [String] 
    [AllowNull()]
    $foo=$null
)

if ($null -eq $foo) {
  Write-Host "The parameter 'foo' is null."
} else {
  Write-Host "The parameter 'foo' is not null."
}

if ("" -eq $foo) {
  Write-Host "The parameter 'foo' is an empty string."
} else {
  Write-Host "The parameter 'foo' is not an empty string."
}

Running the script:

PS C:\src\dummy-6\scripts> .\my-script.ps1
The parameter 'foo' is not null.
The parameter 'foo' is an empty string.


PS C:\src\dummy-6\scripts> .\my-script.ps1 -foo $null
The parameter 'foo' is not null.
The parameter 'foo' is an empty string.
Sign up to request clarification or add additional context in comments.

1 Comment

Nice; for the sake of completeness it is worth noting that the behavior also applies to regular variables with type constraints; e.g. [string] $foo = $null in the body of a function of a script stores the empty string too.
0

If you set it to string, powershell is likely interpreting it as an empty string. You need to do this

if ([string]::IsNullOrEmpty($foo)) {
    $foo = "bar"
}

1 Comment

Isn't this overkill when something like if (!$foo) {$foo = "bar"} works. Also, the ternary operator also works just fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.