2

I'm having a bit of trouble preventing a certain error message from bubbling up from a function to my main routine's 'Catch'. I would like to have my function react to a particular error, then do something, and continue processing as usual without alerting my main routine that there was an error. Currently, if the file this script is trying to read is in use (being written to), it will write a System.IO.IOException error to my log. But sometimes I expect this error to occur and it isn't an issue and I don't want to fill my log with these type of errors. I would expect from the code below that the checkFileLock function would catch the error, return 0 to the findErrorInFile function, and no error would be caught to my error log.

Function findErrorsInFile{
    param(
        [string]$dir,
        [string]$file,
        [String]$errorCode
    )
    If((Get-Item $($dir + "`\" + $file)) -is [System.IO.DirectoryInfo]){ #we dont want to look at directories, only files
    }Else{
        If($(checkFileLock -filePath $($dir + "`\" + $file))){
            $reader = New-Object System.IO.StreamReader($($dir + "`\" + $file))
            $content = $reader.ReadToEnd()
            $results = $content | select-string -Pattern $errorCode #if there is no regex match (no matching error code found), then the string $results will be == $null
                If($results){
                    Return 1 #we found the error in the file
                }Else{
                    Return 0 #no error found in the file
                }
        }Else{
            Return 0 #The file was being written to, we will skip it and assume no error. This is rare. 
        }
    }
}

Function checkFileLock{
    param(
    [String]$filePath
    )

    try{
        $openFile = New-Object System.IO.FileInfo $filePath
        $testStream = $openFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) #try to open a filestream 
        If($testStream){ #If the filestream opens, then it isn't locked
            $testStream.Close() #close the filestream
        }
        return $false #File is not locked 
    }

    catch{
        return $true #File is locked 
    }
}

#### START MAIN PROCESS ####

Try{

  if($(findErrorsInFile -dir 'somepath' -file 'somefilename' -errorcode 'abc')){
    write-host "found something"
  }else{
    write-host "didn't find anything"
  }
}

Catch{
  $_.Exception.ToString() >> mylogfile.txt
}
2
  • It looks like your brackets are a little screwy, is that due to the copy/pasting here or are they actually messed up in your code? Commented Jun 7, 2017 at 15:54
  • @Nick Probably copy/paste error. The script executes without any issue for me Commented Jun 7, 2017 at 15:57

2 Answers 2

4

try/catch blocks only catch terminating errors. Is your code generating a terminating or non-terminating error?

ArcSet has highlighted essentially what is required: force a non-terminating error to be a terminating error. I suspect it needs to be added to this line, if allowed:

$testStream = $openFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) -ErrorAction Stop

Edit - solution as -ErrorAction not an accepted parameter
I tried the above and it's not allowed. An alternative is to set the $ErrorActionPreference to Stop. This will affect all errors, so recommend reverting. Someone with more experience using System.IO.FileInfo objects may have a more elegant solution.

try{
    $currentErrorSetting = $ErrorActionPreference
    $ErrorActionPreference = "Stop"

    $openFile = New-Object System.IO.FileInfo $filePath
    $testStream = $openFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) #try to open a filestream 
    If($testStream){ #If the filestream opens, then it isn't locked
        $testStream.Close() #close the filestream
    }
    $ErrorActionPreference = $currentErrorSetting
    return $false #File is not locked 
}

catch{
    $ErrorActionPreference = $currentErrorSetting
    return $true #File is locked 
}
Sign up to request clarification or add additional context in comments.

3 Comments

I expect this is the issue I was having catching the error as it was a non-terminating error. Although your solution would be illegal in an assignment.
@Christopher Please see edit. I thought it was syntactically funny and $thing.Method() -parameter may not work. Variable assignment part isn't an issue - e..g this is allowed `try{$test = Get-ChildItem randomfilename -ErrorAction Stop}catch{"File doesn't exist yo"}.
The Boolean returns are swapped >.< can't believe I didn't catch that. I also figured out that a pipe at the end of the statement will do the trick... "$testStream = $openFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) | -ErrorAction Stop" accepting as an answer because the code above is also valid.
4

Use to force a catch

-ErrorAction Stop

use to suppress a error

[Command with error] | out-null

3 Comments

How is this done on an assignment operation? Simply $testStream = $openFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) -ErrorAction Stop creates an unexpected token error.
Thats command throws a error without the need for -ErrorAction so use a basic Try{}Catch{}
>.< My boolean returns were swapped. So when a file was locked it would try to open it! -ErrorAction Stop is valid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.