Norrin Rad
Norrin Rad

Reputation: 991

True/false test returning unexpected results

Basically I want to do a check if a directory exists then run this section, if not exit.

The script I have is:

$Path = Test-Path  c:\temp\First

if ($Path -eq "False")
{
  Write-Host "notthere" -ForegroundColor Yellow
}
elseif ($Path -eq "true")
{
  Write-Host " what the smokes"
}

But it returns nothing.

Upvotes: 8

Views: 41442

Answers (4)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200523

In a comparison operation PowerShell automatically converts the second operand to the type of the first operand. Since you're comparing a boolean value to a string, the string will be cast to a boolean value. Empty strings will be cast to $false and non-empty strings will be cast to $true. Jeffrey Snover wrote an article "Boolean Values and Operators" about these automatic conversions that you can check for further details.

As a result this behavior has the (seemingly paradox) effect that each of your comparisons will evaluate to the value of your variable:

PS C:\> $false -eq 'False'
False
PS C:\> $false -eq 'True'
False
PS C:\> $true -eq 'False'
True
PS C:\> $true -eq 'True'
True

Essentially that means that if your Test-Path statements evaluates to $false neither of your conditions will match.

As others have pointed out you can fix the issue by comparing your variable to actual boolean values, or by just using the variable by itself (since it already contains a boolean value that can be evaluated directly). However, you need to be careful with the latter approach. In this case it won't make a difference, but in other situations automatic conversion of different values to the same boolean value might not be the desired behavior. For instance, $null, 0, empty string and empty array are all interpreted as a boolean value $false, but can have quite different semantics depending on the logic in your code.

Also, there is no need to store the result of Test-Path in a variable first. You can put the expression directly into the condition. And since there are only two possible values (a file/folder either exists or doesn't exist), there is no need to compare twice, so your code could be reduced to something like this:

if (Test-Path 'C:\temp\First') {
    Write-Host 'what the smokes'
} else {
    Write-Host 'notthere' -ForegroundColor Yellow
}

Upvotes: 5

Mike Q
Mike Q

Reputation: 7337

To make some things clear, always use Test-Path (or Test-Path with Leaf to check for a file).

Examples I've tested:

$File = "c:\path\file.exe"
$IsPath = Test-Path -Path $File -PathType Leaf

# using -Not or ! to check if a file doesn't exist
if (-Not(Test-Path -Path $File -PathType Leaf)) {
    Write-Host "1 Not Found!"
}

if (!(Test-Path -Path $File -PathType Leaf)) {
    Write-Host "2 Not Found!"
}

# using -Not or ! to check if a file doesn't exist with the result of Test-Path on a file
If (!$IsPath) {
    Write-Host "3 Not Found!"
}

If (-Not $IsPath) {
    Write-Host "4 Not Found!"
}

# $null checks must be to the left, why not keep same for all?
If ($true -eq $IsPath) {
    Write-Host "1 Found!"
}

# Checking if true shorthand method    
If ($IsPath) {
    Write-Host "2 Found!"
}

if (Test-Path -Path $File -PathType Leaf) {
    Write-Host "3 Found!"
}

Upvotes: 0

Swift
Swift

Reputation: 1711

If I'm not mistaken, one can simple say:

if($Path) OR if(!$Path)

But I might be wrong as I can't test atm.

Additionally there is the Test-Path cmdlet available. Unfortunately I cannot describe the difference or suggest the most suitable method without knowing the case and scenario.

[EDITED TO CLARIFY ANSWER]

$Path = "C:\"
if($Path)
    {
    write-host "The path or file exists"
    }
else
    {
    write-host "The path or file isn't there silly bear!"
    }

Hope that adds clarity. With this method, no cmdlets needed. The returned boolean is interpreted for you automatically and runs code blocks if it meets the criteria of the test, in this case if the path C:\ exists. This would be true of files in longer file paths, C:\...\...\...\...\file.txt

Upvotes: 1

scharette
scharette

Reputation: 10017

The error comes from the fact that the return value of Test-Path is a Boolean type.

Hence, don't compare it to strings representation of Boolean but rather to the actual $false/$true values. Like so,

$Path = Test-Path  c:\temp\First

if ($Path -eq $false)
{
    Write-Host "notthere" -ForegroundColor Yellow
}
elseif ($Path -eq $true)
{
    Write-Host " what the smokes"
}

Also, note that here you could use an else statement here.

Alternatively, you could use the syntax proposed in @user9569124 answer,

$Path = Test-Path  c:\temp\First

if (!$Path)
{
    Write-Host "notthere" -ForegroundColor Yellow
}
elseif ($Path)
{
    Write-Host " what the smokes"
}

Upvotes: 17

Related Questions