4

I've started using PowerShell to get some things done and played with the variable $null in PowerShell.

I've encountered the problem that when I assign the variable $null to a variable defined in a class, the test returns false not true.

Example Code:

class test {
    [string]$test1
}

$test = [test]::new()

$test.test1 = $null

$null -eq $test2 # tests true

$null -eq $test.test1 # tests false

Now the test of the undefinded variable $test2 returns true as every undefined variable in PowerShell is assigned $null.

But if I test the property test1 of the object test which I assigned $null tests false for $null

Is it because in PowerShell $null is an object with the value $null and now the property of the object is not $null as it has the object $null assigned to it with an empty value?

I've read into the docs of Microsoft "Everything you wanted to know about $null", but it does not enlighten me.

If I do not initialize the variable, then it will test true for $null.

3 Answers3

4

$test.test1 is not $null, it's empty string (because you explicitely defined it's value to be [string]):

C:\> $test.test1.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Proof:

C:\> $test.test1 -eq ""
True
Robert Dyjas
  • 4,979
  • 3
  • 19
  • 34
4

To elaborate on robdy's helpful answer:

  • By design, [string]-typed variables, parameter variables, and custom-class properties in PowerShell do not store $null[1], only actual string values. Assigning $null always converts to '' (the empty string).

    • Below, $var receives '', not $null, due to being [string]-typed; therefore, the first -eq test fails and the second succeeds.

    • [string] $var = $null; $null -eq $var; '' -eq $var

    • Note that other .NET reference types (as opposed to value types, which fundamentally cannot be null) are not affected in PowerShell; that is, you can assign $null to them. Notably, this also applies to [object]. Note that not type-constraining a variable / parameter / property is the same as [object]-typing it.

  • That an uninitialized [string] property in a PowerShell class nonetheless currently defaults to $null should be considered a bug - see GitHub issue #7294.

    • The inconsistency becomes obvious if you explicitly initialize to $null, which again converts to '' and makes the test fail.

    • class test { [string]$test1=$null }; $null -eq [test]::new().test1

    • Should the bug be fixed and you truly need a $null value in a [string]-typed property - which is ill-advised in the context of PowerShell code - you'd have to use [NullString]::Value, as shown in the answer linked to below:
      class test { [string]$test1 = [NullString]::Value }; $null -eq [test]::new().test1

For more information, see this answer.


[1] The inability to store $null is a limitation that PowerShell imposes, in the interest of simplification. The underlying .NET type, System.String, typically does not have this limitation in other languages, notably not in C#.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • that was one thing that got my attention. But i thought that it would be like that, because you did not initialize the variable and so it does not have the type constraint or anything as it is `$null`. As in following example: ````class test { [string]$test1 } $test = [test]::new() $test.test1 $null -eq $test2 # tests true $null -eq $test.test1 # tests true $test.test1 | gm #comes back with an error "gm : You must specify an object for the Get-Member cmdlet"```` – toodumbtocode Dec 16 '20 at 20:10
  • @toodumbtocode, it's an inconsistency that I'm hoping they'll fix. Note that in a _parameter variable_ the same lack of initialization does result in `''`, as in regular variables; e.g., `& { param([string] $test1) $null -eq $test1 }` yields `$false`. Should the inconsistency be removed and you truly need a `$null` value - which is ill-advised in the context of PowerShell code - you'd have to use `[NullString]::Value`, as shown in the linked answer: `class test { [string]$test1 = [NullString]::Value } $null -eq [test]::new().test1` – mklement0 Dec 16 '20 at 20:23
3

If you're using a type contstraint like [string] or [int] Powershell initializes members at null-assignment with the default of the contrained type.

As @robdy states in above answer you've either check for the types default value or remove the constraint.

This may become more obvious if you're using a [int] type contstraint:

class test {
    [int]$i1 = 42
}
    
$test = [test]::new()
Write-Host $test.i1
$test.i1 = $null
Write-Host $test.i1
    

Output:

42
0
Moerwald
  • 10,448
  • 9
  • 43
  • 83