Powershell catches wrong exception? What am I doing wrong?

帅比萌擦擦* 提交于 2019-12-12 03:17:33

问题


Last week I ran into a strange issue.
I modified code that should test if a file is locked and which I once found on the Internet (essentially similar to https://superuser.com/questions/876288/how-do-i-detect-and-skip-locked-files-in-a-powershell-script) to
1) deal with timeout and
2) to handle non existing files (and directories) correctly.

So here is my code:

function Test-IsFileLocked {
[CmdletBinding()]
Param (
    [Parameter(Mandatory = $True, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [System.IO.FileInfo] $File

  , [ref] $MSecsPassed
)

try {
    $Stream = $File.Open([System.IO.FileMode]"Open", [System.IO.FileAccess]"Read", [System.IO.FileShare]"None")
}
# The follwing catch block seems to cause the problem that the 'IO.FileNotFoundException' gets caught after some time (although it is still a simple 'IO.IOException.)
# Outcomment it by removing the '#' in front of '<# ...' to see how all works nicely...
#<#
  catch [System.IO.DirectoryNotFoundException] {
    Write-Host "System.IO.DirectoryNotFoundException: '$($_.Exception)'`nType = '$($_.Exception.GetType().FullName)'`nType = '$($_.GetType().FullName)'" -ForegroundColor:Yellow
    return $False
}
#>
  catch [System.IO.FileNotFoundException] {
    Write-Host "Caught a 'FileNotFoundException' exception, although the exception still is of type of a simple 'System.IO.IOException'! MSecs passed: $($MSecsPassed.Value)" -ForegroundColor:Red
    Write-Host "FileNotFoundException: '$($_.Exception)'`nType = '$($_.Exception.GetType().FullName)'`nType = '$($_.GetType().FullName)'" -ForegroundColor:Yellow
    #if ($_.Exception.GetType().FullName -eq 'System.IO.IOException') {
    #    return $True
    #} else {
        return $False
    #}
} catch [System.IO.IOException] {
    #Write-Host "System.IO.IOException: '$($_.Exception)'`nType = '$($_.Exception.GetType().FullName)'`nType = '$($_.GetType().FullName)'"
    if ($_.Exception.GetType().FullName -eq 'System.IO.IOException') {
        return $True
    } else {
        return $False
    }
} catch {
    Write-Host "Any Exception: '$($_.Exception)'`nType = '$($_.Exception.GetType().FullName)'`nType = '$($_.GetType().FullName)'" -ForegroundColor:Yellow
    if ($_.Exception.GetType().FullName -eq 'System.IO.IOException') {
        return $True
    } else {
        return $False
    }
} finally {
    if ($Stream) {
        $Stream.Dispose()
    }
}
return $False
}

function Wait-UntilFileIsAccessible {
[CmdletBinding()]
Param (
    [Parameter(Mandatory = $True, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [System.IO.FileInfo] $File

  , [Parameter(Position = 1)]
    [uint32] $CheckIntervalInMSecs

  , [Parameter(Position = 2)]
    [uint32] $Timeout
)

if (!$CheckIntervalInMSecs) {
    $CheckIntervalInMSecs = 500
}

[double] $SecondsPassed = 0.0
[double] $SecondsAdder = [double]$CheckIntervalInMSecs / 1000.0
[uint32] $MSecsPassed = 0

#Write-Verbose "Waiting for '$($File.Fullname)' to get unlocked!"
while (Test-IsFileLocked -File:$File -MSecsPassed:([ref]$MSecsPassed)) {
    Start-Sleep -MilliSeconds:$CheckIntervalInMSecs
    $MSecsPassed += $CheckIntervalInMSecs
    if ($Timeout) {
        $SecondsPassed += $SecondsAdder
        if (([uint32]$SecondsPassed) -ge $Timeout) {
            return $False
        }
    }
}
#Write-Vebose "'$($File.Fullname)' now isn't locked anymore"
return $True
}

If I call this code with

Wait-UntilFileIsAccessible -File:'C:\LockedByMSWord.txt' -Timeout:30

where 'C:\LockedByMSWord.txt' is an existing file actually locked (e.g. opened with MS Word) then after some time (16500 ms in most cases for me) the 'IO.FileNotFoundException' gets caught although the exception thrown seems to be of type 'IO.IOException'. If I then repeat the call to 'Wait-UntilFileIsAccessible' then usually Powershell immediately catches this 'wrong' exception.
It drove me nuts and I tried different things until I removed the code block that catches the 'IO.DirectoryNotFoundException' (for testing purposes initially) just to find out that then everything works as expected.

Am I doing something wrong here (I mean with the code that catches this 'IO.DirectoryNotFoundException' exception), do I misunderstand something or could this be a Powershell bug?

This is with Powershell 4 and ErrorActionPreference set to 'Continue'.
Also some code obviously is just in there for testing purposes (I wouldn't need ref parameter MSecsPassed in Test-IsFileLocked and output to host normally)

P.S.: I know how to workaround it, but I would like feedback to my question if I am doing something wrong in my code or if this possibly could be a bug in Powershell.

Thanks,
Patrik

来源:https://stackoverflow.com/questions/33078116/powershell-catches-wrong-exception-what-am-i-doing-wrong

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!