Why does [NullString]::Value evaluate differently with a breakpoint? Why does [NullString]::Value evaluate differently with a breakpoint? powershell powershell

Why does [NullString]::Value evaluate differently with a breakpoint?


PetSerAl, as many times before, has provided the crucial pointer in a comment on the question:

A known optimization bug is the most likely cause (as of Windows PowerShell v5.1 / PowerShell Core v6.1.0), and that bug just happens to be masked when the code is run in the Visual Studio Code or ISE debugger.

You can therefore use the same workaround mentioned in the linked bug report: place a call to Remove-Variable anywhere in the function body (its presence is enough - the call needn't actually be made at runtime):

function demo {    param(        [string] $value = [NullString]::Value    )    # Workaround for optimization bug    if ($False) { Remove-Variable }    if ($null -eq $value) {        "NULL"    } elseif ($value -eq '') {        "EMPTY"    } else {        "$value"    }}demo

Now you consistently get "NULL" as the output, whether debugging or not.

However, it's best to restrict use of [NullString]::Value to what it was designed for: passing null to string-typed parameters of .NET methods - see below.


As for why use of [NullString]::Value is needed at all in order to pass $null to a string parameter / store $null in a [string] variable, given that .NET strings can normally store null ($null) directly:

By (historical) design, PowerShell converts $null to '' (the empty string) when you assign it to a [string] variable; here's the rationale:

From https://github.com/PowerShell/PowerShell/issues/4616#issuecomment-323530442:

The thinking behind the design was that in most ways, $null and the empty string both represent the same error condition and that in the rare case where a distinction was important, $PSBoundParameters would be sufficient to distinguish between knowing a value was provided or not.

Given that even passing $null directly performs conversion to '' when passing arguments to string-typed .NET methods, you couldn't pass null to such methods up to v2.
To remedy that, version 3 introduced [NullString]::Value, which explicitly signals the desire to pass $null in a string context.
(The alternative - making PowerShell strings default to $null and allowing direct assignment of $null - was considered a change that would break too many existing scripts.)

Using [NullString]::Value beyond its intended purpose - i.e., for passing null to string parameters in .NET methods - is problematic, given that PowerShell doesn't expect [string] variables to contain $null in other contexts.

Fixing the above-mentioned optimization bug would help in the scenario in the question, but there may be other pitfalls.


Difference between $null and ""

Empty string is not the same as null; you'd need to test specifically for that. Null is the non-existence of an object, Whereas a string is an object even if it's empty.

That's a common gotcha in PowerShell. For whatever reason, it won't let you assign a $null value to a string variable (or a string parameter to a .NET type); it gets converted to an empty string. This can cause some headaches when calling .NET methods that treat null and empty strings differently, which is why they later added (in v3, if I remember correctly), the [System.Management.Automation.NullString] class. If you want to call such a method, you do this:

[SomeClass]::SomeMethod([nullstring]::Value)

[string]$camp = $null

Will assign $Null to $Camp, but since the [string]-part forces $camp to be of the type string, $Camp will be assigned the value of [String]$Null

[String]$Null will force a conversion of $Null (which is basically a non-existing object) to a string and in PowerShell that results in an empty string.

As far as PowerShell is concerned, that's basically correct. However, in the .NET Framework, strings really can be null, and there's a difference between a null string reference and an empty string. Sometimes that causes confusion when you're looking at .NET documentation and wondering why it doesn't seem to work properly from PowerShell.

Use [string]::IsNullOrEmpty($variable)

https://powershell.org/forums/topic/difference-between-null-and/

See also...

How can I check if a string is null or empty in PowerShell? [string]::IsNullOrEmpty(...)

How can I check if a string is null or empty in PowerShell?

* Update *

Changing your code to this...

function demo {    param(        [string]$value    )    if ([string]::IsNullOrEmpty($value))    {        "NULL"    } elseif ($value -eq '') {        "EMPTY"    } else {        "$value"    }}

With or without debug (breakpoint set on 'NULL' and 'EMPTY') effort, the results returned are the same on my system ISE/VSCode

# Results demoNULLdemo -value ''NULLdemo -value ' 'demo -value testtest

* Modification to show the elseif handling whitespace *

With or with the conditions previously stated

 function demo {    param(        [string]$value    )    if ([string]::IsNullOrEmpty($value))    {        "NULL"    } elseif ([string]::IsNullOrWhiteSpace($value)) {        "EMPTY or a White Space"    } else {        "$value"    }}# ResultsdemoNULLdemo -value ''NULLdemo -value ' 'EMPTY or a White Spacedemo -value testtest