问题
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