Aug 12 2022 12:29 PM - edited Aug 12 2022 12:33 PM
Highlighted , how is $ True is equal to false?
Same way, why does typecasting 'False' to boolean is evaluating to true?
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"}
Aug 12 2022 06:18 PM
Solution
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:
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:
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
Aug 13 2022 06:09 AM
Aug 13 2022 09:03 AM
No worries at all!
Taking a brief look at some of your final points:
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:
Before getting to answering that, here's another reference image.
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):
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:
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.
Slightly modifying our earlier single-line function to require a [string] input, we can see a degree of progress.
But we're still not there yet since a string-to-string comparison isn't what I would call robust.
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
TryParse()
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:
Either of these approaches should yield consistent results.
As I mentioned before, Booleans can be deceptive in PowerShell under certain circumstances.
Cheers,
Lain
Aug 13 2022 05:33 PM
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.
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.
Cheers,
Lain
Aug 20 2022 04:16 AM
Aug 20 2022 06:16 AM
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
Aug 12 2022 06:18 PM
Solution
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:
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:
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