Friday, October 1, 2010

When is an empty string not an empty string?

Man, it’s been a long time since I took the time to post something for which I apologize.  It’s been a busy few months.  But today we’ll get back into the swing of things with a mystery to solve.  We start with a distilled version of an advanced function a friend of mine was working with:
function Test-Mystery
{
    [CmdletBinding()]
    param
    (
        [ValidateNotNullOrEmpty()]
        $paramOne
    )
    
    $paramOne
    $paramOne.length
}
Pretty straightforward advanced function stuff, we have a parameter that we need to validate. It can be anything it wants as long as it’s not null, and is not an empty string. If we test this, we’ll find that it works. Mostly.

PS > $x = "HELLO WORLD"
PS > Test-Mystery -paramOne $x
HELLO WORLD
11


PS > $x = ""
PS > Test-Mystery -paramOne $x
Test-Mystery : Cannot validate argument on parameter 'paramOne'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
At line:2 char:23
+ Test-Mystery -paramOne <<<<  $x
    + CategoryInfo          : InvalidData: (:) [Test-Mystery], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Mystery


Okay, that works as expected.  But let’s try that with input from the Read-Host cmdlet.  First we’ll enter in a string, then we’ll just hit Enter to return nothing (in theory).

PS > $x = Read-Host "Test "
PS > Test-Mystery -paramOne $x
Test: HELLO WORLD
HELLO WORLD
11


PS > $x = Read-Host "Test "
PS > Test-Mystery -paramOne $x
Test:

0

Uhh….what?  That totally should have exploded, and yet it doesn’t.  Adding to the mystery is that the variable being assigned the return value from Read-Host is indeed a [System.String] variable and it is assigned the value of ‘’ (or an empty string).  At least that’s what PSDebug tells us:

PS > $x = read-host 'test '
DEBUG:    1+ $x = <<<<  read-host 'test '
test :
DEBUG:     ! SET $x = ''.


PS > $x.gettype() 
IsPublic IsSerial Name    BaseType
-------- -------- ------  --------
True     True     String  System.Object


PS > $x –eq “”
True


And so thus is given to us the mystery:  when is an empty string not an empty string?  Evidently, when it’s created by Read-Host.  But, thankfully there is a fairly straight forward solution.  We strongly type the variable being assigned the output from Read-Host.

PS > [string]$x = Read-Host 'Test '
Test :

PS > Test-Mystery $x
Test-Mystery : Cannot validate argument on parameter 'paramOne'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
At line:2 char:13
+ Test-Mystery <<<<  $x
    + CategoryInfo          : InvalidData: (:) [Test-Mystery], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Mystery


I’ll pose this question on the PowerShell Technet Forums, and see if it this is ‘as designed’ or a genuine bug that we need to file on Connect.  Until then, case (almost) closed.