Eu escrevi um pequeno script do PowerShell para ignorar os erros de E / S do dispositivo na cópia (e, assim, substituir os dados ilegíveis pelo zero). Uma versão atualizada e mais avançada está disponível aqui . O código que coloquei aqui abaixo é uma das primeiras versões e é o mais simples possível:
## .SYNOPSIS
#########################
## This script copies a file, ignoring device I/O errors that abort the reading of files in most applications.
##
## .DESCRIPTION
#########################
## This script will copy the specified file even if it contains unreadable blocks caused by device I/O errors and such. The block that it can not read will be replaced with zeros. The size of the block is determined by the buffer. So, to optimize it for speed, use a large buffer. T optimize for accuracy, use small buffer, smallest being the cluster size of the partition where your source file resides.
##
## .OUTPUTS
#########################
## Errorcode 0: Copy operation finished without errors.
##
## .INPUTS
#########################
## Blabla..
##
## .PARAMETER SourceFilePath
## Path to the source file.
##
## .PARAMETER DestinationFilePath
## Path to the destination file.
##
## .PARAMETER Buffer
## I makes absolutely no sense to set this less than the cluster size of the partition. Setting it lower than cluster size might force rereading a bad sector in a cluster multiple times. Better is to adjust the retry option. Also, System.IO.FileStream buffers input and output for better performance. (http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx).
##
## .EXAMPLE
## .\Force-Copy.ps1 -SourceFilePath "file_path_on_bad_disk" -DestinationFilePath "destinaton_path"
##
#########################
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
HelpMessage="Source file path.")]
[string][ValidateScript({Test-Path -LiteralPath $_ -Type Leaf})]$SourceFilePath,
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
HelpMessage="Destination file path.")]
[string][ValidateScript({ -not (Test-Path -LiteralPath $_) })]$DestinationFilePath,
[Parameter(Mandatory=$false,
ValueFromPipeline=$false,
HelpMessage="Buffer size in bytes.")]
[int32]$BufferSize=512*2*2*2 # 4096: the default windows cluster size.
)
Write-Host "Working..." -ForegroundColor "Green";
# Making buffer
$Buffer = New-Object System.Byte[] ($BufferSize);
$UnreadableBits = 0;
# Fetching source and destination files.
$SourceFile = Get-Item -LiteralPath $SourceFilePath;
$DestinationFile = New-Object System.IO.FileInfo ($DestinationFilePath);
# Copying starts here
$SourceStream = $SourceFile.OpenRead();
$DestinationStream = $DestinationFile.OpenWrite();
while ($SourceStream.Position -lt $SourceStream.Length) {
try {
$ReadLength = $SourceStream.Read($Buffer, 0, $Buffer.length);
# If the read operation is successful, the current position of the stream is advanced by the number of bytes read. If an exception occurs, the current position of the stream is unchanged. (http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx)
}
catch [System.IO.IOException] {
Write-Warning "System.IO.IOException at $($SourceStream.position) bit: $($_.Exception.message)"
Write-Debug "Debugging...";
$ShouldReadSize = [math]::Min([int64] $BufferSize, $SourceStream.Length - $SourceStream.Position);
$DestinationStream.Write((New-Object System.Byte[] ($BufferSize)), 0, $ShouldReadSize);
$SourceStream.Position = $SourceStream.Position + $ShouldReadSize;
$UnreadableBits += $ShouldReadSize;
continue;
}
catch {
Write-Warning "Unhandled error at $($SourceStream.position) bit: $($_.Exception.message)";
Write-Debug "Unhandled error. You should debug.";
throw $_;
}
$DestinationStream.Write($Buffer, 0, $ReadLength);
# Write-Progress -Activity "Hashing File" -Status $file -percentComplete ($total/$fd.length * 100)
}
$SourceStream.Dispose();
$DestinationStream.Dispose();
if ($UnreadableBits -ne 0) {Write-Host "$UnreadableBits bits are bad." -ForegroundColor "Red";}
Write-Host "Finished copying $SourceFilePath!" -ForegroundColor "Green";