Powershell Mount-DiskImage:输入/输出操作因线程退出或应用程序请求而中止
我写了一个PowerShell脚本,用来挂载Kodak Photo CD的 ISO文件,然后再用pcdtojpeg把它们转换成JPEG。它运行正常,但在某些磁盘镜像上偶尔会出现这个错误:
Mount-DiskImage:
Line |
2 | try{Mount-DiskImage -ImagePath $_.FullName
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| The I/O operation has been aborted because of either a thread exit or an application request.
我可以用wincdemu或 Windows自带工具手动挂载ISO,它本身并不是损坏之类的。
这是为什么?我该怎么做才能防止它,或者检测到它并重试?
这些错误甚至不会中断程序流程,它只是把错误信息输出到控制台。还有一些因为ISO没有被挂载而导致读取不到存在的文件的错误。我尝试把它放进try/catch里,但并没有改变任何行为。
ISO文件存放在一个外接的Thunderbolt 3硬盘的文件夹里,我也把JPEG写到同一驱动器上的另一个文件夹里,但任务管理器显示该驱动器并未被完全占用之类的。
这是我的脚本
cd "C:\Users\mirandac\Desktop\pcdtojpeg_1_0_17\Binaries\Windows"
$disks = "D:\Corel Professional Photos Collection"
Get-ChildItem –Path $disks -Recurse |Foreach-Object {
try{Mount-DiskImage -ImagePath $_.FullName
$message = "Mount: "
$message = $message + $_
$message
}
catch{
$message = "Mount Failed"
$message
Dismount-DiskImage -ImagePath $_.FullName
Start-Sleep -Seconds 10
Mount-DiskImage -ImagePath $_.FullName
$message = "Mount: "
$message = $message + $_
$message
}
Start-Sleep -Seconds 1
$first = Get-ChildItem -Path E:\Corel -Force -Recurse -File -Name | Select-Object -First 1
$last = Get-ChildItem -Path E:\Corel -Force -Recurse -File -Name | Select-Object -Last 1 -Skip 1
$first = $first -replace "\.[^.]+$"
$last = $last -replace "\.[^.]+$"
$A = "E:\COREL\"
$B = ".PCD"
$C = "D:\PICS\"
$D = ".jpeg"
for ($i = [int]$first; $i -le ([int]$first + 99); $i++){
$diskpath = $A + [string]$i + $B
$picpath = $C + [string]$i + $D
if(-not(Test-Path $picpath)){
.\pcdtojpeg.exe $diskpath $picpath
}
}
Dismount-DiskImage -ImagePath $_.FullName
Start-Sleep -Seconds 1
$message = "Dismount: "
$message = $message + $_
$message
}
我在Windows 11上使用PowerShell 7.4.13。
我的磁盘镜像来自Internet Archive上的Corel Professional Photos Collection。
解决方案
-
你立刻遇到的问题就是Santiago指出的那个:因为
Mount-DiskImage报告的是一个 非终止 错误,try ... catch不能用来捕获它;若要后者成功,你需要添加-ErrorAction Stop,这在以下帖子中有解答: - Try Catch not working in Powershell Script
-
另请参阅:
- 在为命令作者提供何时发出终止错误与非终止错误的指导时,PowerShell的基本错误类型的描述:此回答。
- 关于PowerShell错误处理令人惊讶的复杂性全面概述:GitHub文档问题#1583。
- 或者,检查 自动
$?变量 以确定是否发生了错误,如下所示。 - 至于 再次尝试:假设你遇到的错误是一个 瞬时的 错误,你可以按照下面的思路实现一个 重试循环:
$VerbosePreference = 'Continue' # Remove this line to silence verbose output.
Get-ChildItem $disks -File -Recurse -Filter *.iso | ForEach-Object {
# Try to mount the ISO image, up to 3 attempts with a delay in between.
foreach ($i in 1..3) {
$mountedImage =
Mount-DiskImage -ImagePath $_.FullName -ErrorAction SilentlyContinue -ErrorVariable mountError
if ($?) { break } # Succeeded; exit loop.
Start-Sleep -Seconds 1
Write-Verbose "Retrying mount of $($_.FullName)..."
}
# If mounting failed even after retries, emit a non-terminating error and
# proceed to the next input ISO file.
if (-not $mountedImage) {
Write-Error "Failed to mount $($_.FullName) after multiple attempts: $mountError"
return # Proceed to next ISO file.
}
# Determine the drive letter of the newly mounted image, e.g. E:
$mappedDrive = ($mountedImage | Get-Volume).DriveLetter + ':'
# Work with $mappedDrive here...
Write-Verbose "Successfully mounted $($_.FullName) as drive $mappedDrive"
# Unmount again...
$null = Dismount-DiskImage -ImagePath $_.FullName
}
注:
- 先说一个不寻常的要求(你的代码通过使用
$_.FullName正确处理了这一点):莫名其妙地,-ImagePath参数在Mount-DiskImage与Dismount-DiskImage中都需要一个 完整(绝对)文件路径。 - CIM实例
Mount-DiskImage输出用于描述已经成功挂载的镜像,但它本身并不会透露新挂载镜像的 驱动器字母;后者可以通过将该实例通过管道输送到Get-Volume来确定,如上所示。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。