Skip to content

Instantly share code, notes, and snippets.

@IMJLA
Created December 20, 2023 01:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IMJLA/16cdd97c7e7bc337176a5f0896c51803 to your computer and use it in GitHub Desktop.
Save IMJLA/16cdd97c7e7bc337176a5f0896c51803 to your computer and use it in GitHub Desktop.
function Copy-File {
param(
#Path to the source file
[Parameter(
Mandatory = $True,
Position = 0
)]
[String]$SourceFilePath,
#Path to the destination file
[Parameter(
Mandatory = $True,
Position = 1
)]
[String]$DestinationFilePath
)
process{
# Get the file name.
$SourceFileName = $SourceFilePath.Split("\") | Select-Object -Last 1
# Open the source and destination files.
$Pref = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
$SourceFile = [System.IO.File]::OpenRead($SourceFilePath)
$DestinationFile = [System.IO.File]::OpenWrite($DestinationFilePath)
$ErrorActionPreference = $Pref
# Show a progress bar.
$Progress = @{
Activity = "Copying file"
Status = $SourceFileName
PercentComplete = 0
}
Write-Progress @Progress
try {
# Start a timer
$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# Create a 4 MiB buffer.
$Buffer = New-Object -TypeName Byte[] (4194304)
# Initialize counters to track progress based on the number of bytes written.
[Long]$CurrentByteCount = 0
[Long]$TotalBytesRead = 0
do {
# Read 4 MiB from the source file into the buffer.
$CurrentByteCount = $SourceFile.Read($Buffer, 0, $Buffer.Length)
# Write the buffer to the destination file.
$DestinationFile.Write($Buffer, 0, $CurrentByteCount)
# Update the counters to track progress
[Int64]$MillisecondsElapsed = $Stopwatch.ElapsedMilliseconds
[Int64]$SecondsElapsed = $MillisecondsElapsed/1000
$TotalBytesRead += $CurrentByteCount
if ( $MillisecondsElapsed -ne 0 ) {
[Int64]$BytesPerMillisecond = $TotalBytesRead / $MillisecondsElapsed
}
else {
[Int64]$BytesPerMillisecond = 0
}
#Update the progress bar every MiB
if ($TotalBytesRead % 1048576 -eq 0) {
[Int16]$PercentComplete = $TotalBytesRead / $SourceFile.Length * 100
if($PercentComplete -gt 0){
[int]$EstimatedSecondsRemaining = $SecondsElapsed / $PercentComplete * 100 - $SecondsElapsed
}
else {
[int]$EstimatedSecondsRemaining = 0
}
$CopySpeed = '{0:N2}' -f ($BytesPerMillisecond*1000/1048576)
$Elapsed = New-TimeSpan -Seconds $SecondsElapsed
$Progress = @{
Activity = "Copying file"
Status = "$PercentComplete% copying '$SourceFileName' @ $CopySpeed MiB/s. Elapsed: $Elapsed"
PercentComplete = $PercentComplete
SecondsRemaining = $EstimatedSecondsRemaining
}
Write-Progress @Progress
}
}
# Loop until the end of the FileStream is reached and 0 bytes are read into the buffer.
while ($CurrentByteCount -gt 0)
}
finally {
if ( $MillisecondsElapsed -ne 0 ) {
[Int64]$AverageBytesPerMillisecond = $SourceFile.Length/$MillisecondsElapsed
Write-Verbose "$SourceFileName ($($SourceFile.Length) B) copied in $($MillisecondsElapsed) Milliseconds at $AverageBytesPerMillisecond B/ms."
}
else {
[Int64]$AverageBytesPerMillisecond = 0
}
#Reset the timer.
$Stopwatch.Reset()
$AmountCopied = '{0:N2}' -f ($SourceFile.Length/1048576)
$CopySpeed = '{0:N2}' -f ($AverageBytesPerMillisecond*1000/1048576)
Write-Host "$SourceFileName ($AmountCopied MiB) copied in $SecondsElapsed seconds at $CopySpeed MiB/s."
#Close the Source and Destination Files
$SourceFile.Close()
$DestinationFile.Close()
}
Write-Progress -Activity "Copying file" -Completed
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment