Home > Software design >  Powershell DataContext variable set to false returns true
Powershell DataContext variable set to false returns true

Time:06-28

I'm using a datacontext in my powershell app (a first for me) and from what I can tell all datacontext properties and values are set with JSON and all values are strings. Example:

$DataObject =  ConvertFrom-Json @"

{
    "myproperty":"false"
}

But I'm having an issue where that false up there is not always evaluation to false. When I bind a control's enable property to myproperty, it properly disables as it's set to false.

But if I try to evaluate that property as a bool, it returns true:

If($state.myproperty){$true} Else {$false}
True

I don't understand why it registers as a boolean false, for purposes of the control, but I cannot reference it as such in code.

Please school me on what I'm missing.

EDIT I've come to understand Powershell will register any string over 0 characters as true. However, I'm still curious as to why when bound to a control property, this doesn't seem to be an issue.

EDIT2 I worked around this by not actually setting a default value in the JSON and simply setting the $state.myproperty to $false near the beginning of the script and set it to $true when my condition required.

Again still curious as to why the control binding properly evaluates the string "false". Also if I wanted to initialize this in JSON, can you do so without use of quotes? E.g. "myproperty":false ?

CodePudding user response:

On the JSON side:

  • false and true - note the absence of quoting - are Boolean JSON values that represent the values their names imply.

  • By contrast, "false" and "true" are JSON strings whose value happens to be false and true, respectively - a string value has no intrinsic meaning, except by convention that the consumer of a JSON document must be aware of.

    • (An example of such a convention is that ConvertTo-Json and ConvertFrom-Json use specially formatted strings such as "2022-06-27T15:31:38.935539-04:00" to represent date/time ([datetime]) values, to compensate for the absence of a date/time data type in JSON itself - see this answer)

Thus, you should use the following to create an object whose .myproperty value contains an actual Boolean value - note that false is unquoted:

$DataObject =  ConvertFrom-Json @"
{
    "myproperty": false
}
"@

Generally, aside from strings, which are always double-quoted (e.g., "foo"), JSON supports the following unquoted primitive data types as values:

  • Booleans: true and false
  • Null values: null
  • Numbers: e.g., 42, -42, 1.0 and 1e2
    • Note: The standard doesn't permit prefix or .1 as shorthand for 0.1, and supports decimal number representations only; specific implementations, however, may be less strict.

On the PowerShell / .NET side:

PowerShell's ConvertFrom-Json maps these values to their analogous .NET data types, [string] (System.String) and [bool] (System.Boolean):

(' false ' | ConvertFrom-Json).GetType().FullName   # -> System.Boolean
# vs. 
(' "false" ' | ConvertFrom-Json).GetType().FullName # -> System.String

In terms of interpreting these values as Booleans, this means:

  • Only unquoted false and true values map directly onto their [bool] counterparts (expressed as $false and $true in PowerShell).

  • As you've observed, when PowerShell evaluates a string in a Boolean context, it considers any non-empty string $true, irrespective of its content, so that [bool] "false" yields $true as well.

    • If you're dealing with string that you know to contain either "true" or "false" (or any case variation thereof) and you want to parse it as a Boolean, use the [bool]::Parse() method; e.g., [bool]::Parse("false") yields $false, as intended.
  • PowerShell generally implements its own, automatic to-Boolean conversions[1] (such as the one described above), which do not apply to .NET APIs.

    • Given that .NET has no built-in string-to-Boolean conversion, it is up to the DataContext type to interpret strings as Booleans, though the use of [bool]::Parse() is a logical candidate (in C# syntax, e.g.: bool.Parse("false"))

[1] For a summary of the conversion rules, see the bottom section of this answer.

  • Related