Question

I have the powershell code

$target_dir = "\\server\share\"
$DelTmpStatus = "init value"
if ( Test-Path ( $target_dir + "receivals.tmp") )
{
    del ( $target_dir + "receivals.tmp")
    $DelTmpStatus = "Present and delete status $?"
} else {
    $DelTmpStatus = "NA"
}

and sometimes it makes it through this section with $DelTmpStatus still set to "init value".

How can the if-else structure not follow either path? Does the if-else structure in powershell not do anything when the if function is given an error instead of true or false?

$PSVersionTable.psversion is 3.0

Edit: I never have any errors or this problem when I run it myself, either fully or step-by-step. But sometimes the scheduled job will run and $DelTmpStatus will still be "init value" I imagine it happens when the \\server\share\ path is unavailable due to server in low power mode overnight taking too long to respond and the test-path function times out. Though I can't be sure if that is the cause or not.

Edit: the results of doing the tests

  • using a non existent server for $target_dir makes it follow the else path and sets $DelTmpStatus to "NA"
  • using an invalid path like $target_dir = "C:\..\..\invalid\" results in test-path writing an error to stderr and returning true (not ideal but whatever), making the program flow down the attempt to delete the file (again there's an error) then it sets $DelTmpStatus to "Present and delete status False". This is not a particularly helpful thing to do but at least the code in the if-else statement is executed.
Was it helpful?

Solution

It seems that if the command inside the condition area fails to execute and doesn't return a value, the entire if-else block is not executed and the continue on error chooses to continue below the if-else block.

How to Simulate the Problem

While this is not exactly what is going on in my real code, it does produce the same problem of the if-else block not being executed. It even does it every time.

if ( Test-Path -invalid-switch )
{
    write-output "true path of if statement"
} else {
    write-output "false path of if statement"
}
write-output "finished if statement"

has the output

Test-Path : A parameter cannot be found that matches parameter name 'invalid-switch'.
At C:\scripts\test.ps1:1 char:16
+ if ( Test-Path -invalid-switch )
+                ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Test-Path], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.TestPathCommand

finished if statement

The Fix

To fix the issue the code that may have an error needs to be taken out of the if() condition tested beforehand, and logic added to the if-statement to deal with a potential failure. To fix up the actual code to not suffer from this problem I have now changed the code to

$err = $false
try { $tmpStatus = Test-Path ( $target_dir + "receivals.tmp") }
catch
{
    $tmpStatus = $error | foreach { $_.Exception }
    $err = $true
}
if ( $err -or $tmpStatus ) 
{
    del ( $target_dir + "receivals.tmp")
    $DelTmpStatus = $?
} else {
    $DelTmpStatus = "NA"
}

The astute will realise that I could just replace all of that with just the lines

$tmpStatus = test-path ( $target_dir + "receivals.tmp")
del ( $target_dir + "receivals.tmp")
$DelTmpStatus = $?

since I try and delete the file even if it has an error finding the file. The only difference will be that the shorter code will have errors more often but still perform the same function.

However having the longer code with more error checking sheds a bit more light on the situation as $tmpStatus has come through with the value

System.Management.Automation.CommandNotFoundException: The term 'Test-Path' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

Unfortunately this still leaves me wondering what is going on...? How can 'Test-Path' be a valid cmdlet some days but not others, with exactly the same script running on the same computer from the same scheduled job. As an extra bonus, on the days when 'Test-Path' is not a valid cmdlet, when I use it again later on in the same script it works fine every time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top