SOLVED

Powershell: how to use an if condition with true false

Microsoft

pooja520_0-1660332044457.png

 

Highlighted , how is $ True is equal to false? 

Same way, why does typecasting 'False' to boolean is evaluating to true?

pooja520_1-1660332319389.png

 

What is the right way to use if condition that can receive $True or 'True or $False or 'False'

 

$Stat = $True
if($Stat -eq 'fal'){Write-Host "if executed"}else{Write-Host "else block"}

if($Stat -eq $False){Write-Host "if executed"}else{Write-Host "else block"}

if($Stat -eq 'False'){Write-Host "if executed"}else{Write-Host "else block"}

$Stat = 'True'
 if($Stat -eq 'False'){Write-Host "if executed"}else{Write-Host "else block"}

 if($Stat -eq 'True'){Write-Host "if executed"}else{Write-Host "else block"}

if($Stat -eq $True){Write-Host "if executed"}else{Write-Host "else block"}

 if($Stat -eq $False){Write-Host "if executed"}else{Write-Host "else block"}

$Stat = $False
 if($Stat){Write-Host "if executed"}else{Write-Host "else block"}

$Stat = 'False'
 if($Stat){Write-Host "if executed"}else{Write-Host "else block"}

 if([bool]$Stat){Write-Host "if executed"}else{Write-Host "else block"}

 $dd = [bool]$Stat
 if($dd){Write-Host "if executed"}else{Write-Host "else block"}


6 Replies
best response confirmed by pooja520 (Microsoft)
Solution

@pooja520 

 

PowerShell is not strongly-typed language like C#, where the compiler wouldn't even let you run a test like [bool] -eq [string]. Where PowerShell does allow such operations, they come with behaviours you need to know about.

 

What your first test ($Stat -eq 'fal') is testing is for the existence (i.e. present and not null) of the right of the operator - since the types themselves don't match - and comparing that to the value on the left. So, rather than:

 

$Stat -eq 'fal';

 

You're actually comparing (since 'fal' both exists and is not null):

 

$Stat -eq $true;

 

Hence the result is $true.

 

Here's my own example illustrating this very point using an even more complex type on the right-hand side:

 

LainRobertson_0-1660352359544.png

 

Now, if you swap the values around, you'd expect to get the same outcome, but you don't. This is because PowerShell is now testing for equality against the complex ActiveDirectorySite class, which the Boolean isn't going to match (since the test is something called a reference equality test - but this isn't important.)

 

So, this brings me to the crux of your issue: how can you reliably test a Boolean against another Boolean? (as distinct from your example that is a Boolean against a String.)

 

I'd posit two basic ways though there are more:

 

  1. Swap the Boolean to be on the right side of the operator, with the object you're comparing to the left;
  2. Use the .NET .Equals() method on the Boolean object to assess the object being checked.

 

LainRobertson_1-1660353356559.png

 

PowerShell's implicit existence testing can be quite a handy feature, but in the case of working with the Boolean type also requires a bit more care - and testing - to avoid unintended outcomes.

 

Cheers,

Lain

Thanks a bunch Lain for taking time explaining this. This definitely saves some of my hairs been pulled out trying figure what's going on. Thanks a ton again for taking time helping out with understandable examples.
Understood why below is dangerous:

$Stat = 'False' #simulation of variable value can be of type string at times and so a direct 'if' on it yields wrong result.
if($Stat){Write-Host "if executed"}else{Write-Host "else block"}

A followup:
Though the swap trick seems to work however the "equals" method is not usable for my case because, my variable at times can have string at times (it's fetched from another source and by the time it reaches my code block, it can be either string or boolean and that's where ".Equals" doesn't give the desired result.
I understand from .NET's point of view, they both are different so it's all right. However the swap trick also yields undesired result

$Stat = 'False'
$True -eq $Stat
> True #how do I get here False?

Typecasting also doesn't help as
[bool]'False' is also True

Whether my variable value comes a string or boolean, I want the 'if' block to be executed only if it's really True (irrespective of the data type)

@pooja520 

 

No worries at all!

 

Taking a brief look at some of your final points:

 

The .Equals() method

Looking at the reference documentation (below), you can see there's two overrides for the .Equals() method: one that accepts an actual Boolean value and another that accepts any object type.

 

 

Without going into depth here, only the .Equals() that takes the Boolean parameter is of use in the majority of cases.

 

This is necessary to remember when looking at the example you provided - which uses mixed types, which I'll do again before bringing things together.

 

First, here's your example again as the reference point.

 

$Stat = 'False'
$True -eq $Stat
> True #how do I get here False?

 

Here's the important takeaways in short form:

 

  • Your first statement is a String assignment, not a Boolean assignment;
  • Your second statement is comparing a Boolean type on the left to a string type on the right, which should be read as:

    $True -eq ($null -ne $Stat)

    And since $Stat is indeed not a null reference, this leads to the assessment of $True -eq $True, which of course is true, which brings you to your third point of:
  • "How can we get a false instead?"

 

Before getting to answering that, here's another reference image.

 

LainRobertson_0-1660400956079.png

 

This picture should help illustrate the difference between what I said before as well as speak to why you get $true and not $false for your third line.

 

The if() statement highlights what I said in my previous post which is that the value held in the string, $Stat, is not implicitly converted to its Boolean equivalent. Rather, PowerShell sees some random old string and performs an existence - or "not null" - check.

 

So, where you are expecting this assessment:

 

$True -eq (implied conversion of string 'false' to $false)

 

What PowerShell is actually doing is this:

 

$True -eq ($Stat -ne $null)

 

Which is how you get to the assessment of $True -eq $True, which of course produces the result you see of True.

 

So, this gets us as far as explaining the result you saw but not yet how to do what you want, which is to assess a string as if it were a Boolean.

 

It's important to mention at this point that you cannot implicitly convert a string into a Boolean value - as you noted in your comment where you tried to typecast using the [bool] prefix. This is actually one instance where PowerShell and it's cousin, C#, are consistent, since you can't do it that way there, either.

 

Here's a very simple, single-line function that shows you how PowerShell responds to the implied string-to-Boolean conversion scenario (i.e. it throws an exception saying it cannot):

 

LainRobertson_4-1660404475232.png

 

So, now that we've seen PowerShell's "reluctance" to perform implicit casting from a string to a Boolean, how do we move forward with a proper Boolean value-to-value comparison?

 

We're getting closer to answering that, but we're not there yet!

 

While we cannot implicitly convert a string to a Boolean, we can implicitly convert a Boolean to a string. This behaviour explains what you see below:

 

LainRobertson_2-1660403337255.png

 

The first line equates to:

 

$false -eq ($null -ne [string])

 

Which is why you get a result of false where you might have been excused for expecting a true. In this example, the left and the right sides of the operand are of Boolean type.

 

The second line, however, involves strings on both sides of the operand. In other words, the second line equates to:

 

"false" -eq ($false.ToString())

 

Which of course produces the expected result of true.

 

LainRobertson_3-1660403908970.png

 

Slightly modifying our earlier single-line function to require a [string] input, we can see a degree of progress.

 

LainRobertson_5-1660404697466.png

 

But we're still not there yet since a string-to-string comparison isn't what I would call robust.

 

Enter the .Parse() and .TryParse() methods

The Boolean structure defines a .Parse() method - well two, actually, but there's no need for discussing both.

 

 

The key point of difference with these two is that for Parse, you should wrap that in your own try ... catch block, where TryParse avoids the need for the try ... catch block at the expense of creating an additional clause in your "if" statement.

 

Parse() with try ... catch

LainRobertson_6-1660405579175.png

 

TryParse()

LainRobertson_7-1660406130327.png

 

 

Summary

That's a much deeper dive than is generally needed for most situations but the general gist is to pick a data type to compare and adjust accordingly:

 

  • Compare a string to a string by placing the static string on the left and the string or Boolean variable to the right of the operand, or;
  • Compare a Boolean to a Boolean by suitably parsing the supplied string variable into a Boolean.

 

Either of these approaches should yield consistent results.

 

As I mentioned before, Booleans can be deceptive in PowerShell under certain circumstances.

 

Cheers,

Lain

@pooja520 

 

Getting away from the topic of why you get the opposite result to what you may have expected and answering the question you raised of:

 

"What is the right way to use if condition that can receive $True or 'True or $False or 'False'"

 

There's a number of ways, but I would recommend keeping a string constant to the left, with the variable being checked to the right of the operand, like this:

 

if ("true" -eq $MyVariable)

 

This forces the right-hand side to be implicitly converted to the data type of the left hand side, which if you recall is possible because the Boolean data type contains a .ToString() method (but you cannot convert in the opposite direction.)

 

As you can see from the example below, this produces reliable outcomes.

 

LainRobertson_0-1660436790329.png

 

If you are quite fussy about your data type standards and prefer to use the Boolean data for the actual comparison, and you want to cope gracefully with receiving a string variable, then I'd recommend the Boolean.TryParse() approach.

 

LainRobertson_1-1660437169447.png

 

Cheers,

Lain

This thread is an eye opener. Brilliant teaching in there. Learnt important internal and now lesser anxious with 'what the heck is going on'. Thanks for being such knowledgeable, humble and an amazing teacher all at the same time.
However, the reasons also makes me think whether to stick to powershell or go for more clearer langs.
Eg. I have one more weird behavior related to function returning, that would never happen in an programming lang. Will create a separate thread on it with the mini snippet.

Thanks a ton for your time and efforts explaining current one.

@pooja520 

 

Anytime!

 

There's not many scenarios as obscure as the Boolean one, and in a similar spirit to JavaScript, it's become incredibly pervasive over the years. So, I'd say play with and get to know it, and treat it like the Swiss army knife you pull out to get short tasks taken care of - particularly if you're coming from a C# background.

 

It's not my go-to choice for larger bodies of work, but for short projects and general administration, it's a pretty handy tool to be able to call upon.

 

Cheers,

Lain

1 best response

Accepted Solutions
best response confirmed by pooja520 (Microsoft)
Solution

@pooja520 

 

PowerShell is not strongly-typed language like C#, where the compiler wouldn't even let you run a test like [bool] -eq [string]. Where PowerShell does allow such operations, they come with behaviours you need to know about.

 

What your first test ($Stat -eq 'fal') is testing is for the existence (i.e. present and not null) of the right of the operator - since the types themselves don't match - and comparing that to the value on the left. So, rather than:

 

$Stat -eq 'fal';

 

You're actually comparing (since 'fal' both exists and is not null):

 

$Stat -eq $true;

 

Hence the result is $true.

 

Here's my own example illustrating this very point using an even more complex type on the right-hand side:

 

LainRobertson_0-1660352359544.png

 

Now, if you swap the values around, you'd expect to get the same outcome, but you don't. This is because PowerShell is now testing for equality against the complex ActiveDirectorySite class, which the Boolean isn't going to match (since the test is something called a reference equality test - but this isn't important.)

 

So, this brings me to the crux of your issue: how can you reliably test a Boolean against another Boolean? (as distinct from your example that is a Boolean against a String.)

 

I'd posit two basic ways though there are more:

 

  1. Swap the Boolean to be on the right side of the operator, with the object you're comparing to the left;
  2. Use the .NET .Equals() method on the Boolean object to assess the object being checked.

 

LainRobertson_1-1660353356559.png

 

PowerShell's implicit existence testing can be quite a handy feature, but in the case of working with the Boolean type also requires a bit more care - and testing - to avoid unintended outcomes.

 

Cheers,

Lain

View solution in original post