powershell progress-bar progress copying copy-item

powershell - Progreso durante la copia de archivos de gran tamaño(¿Copiar elemento y escribir progreso?)



progress-bar progress (9)

¿Hay alguna forma de copiar un archivo realmente grande (de un servidor a otro) en PowerShell Y visualizar su progreso?

Existen soluciones para usar Write-Progress junto con looping para copiar muchos archivos y mostrar el progreso. Sin embargo, parece que no puedo encontrar nada que muestre el progreso de un solo archivo.

¿Alguna idea?


Esta función recursiva copia archivos y directorios recursivamente de la ruta de origen a la ruta de destino

Si el archivo ya existe en la ruta de destino, solo los copiará con archivos más nuevos.

Function Copy-FilesBitsTransfer( [Parameter(Mandatory=$true)][String]$sourcePath, [Parameter(Mandatory=$true)][String]$destinationPath, [Parameter(Mandatory=$false)][bool]$createRootDirectory = $true) { $item = Get-Item $sourcePath $itemName = Split-Path $sourcePath -leaf if (!$item.PSIsContainer){ #Item Is a file $clientFileTime = Get-Item $sourcePath | select LastWriteTime -ExpandProperty LastWriteTime if (!(Test-Path -Path $destinationPath/$itemName)){ Start-BitsTransfer -Source $sourcePath -Destination $destinationPath -Description "$sourcePath >> $destinationPath" -DisplayName "Copy Template file" -Confirm:$false if (!$?){ return $false } } else{ $serverFileTime = Get-Item $destinationPath/$itemName | select LastWriteTime -ExpandProperty LastWriteTime if ($serverFileTime -lt $clientFileTime) { Start-BitsTransfer -Source $sourcePath -Destination $destinationPath -Description "$sourcePath >> $destinationPath" -DisplayName "Copy Template file" -Confirm:$false if (!$?){ return $false } } } } else{ #Item Is a directory if ($createRootDirectory){ $destinationPath = "$destinationPath/$itemName" if (!(Test-Path -Path $destinationPath -PathType Container)){ if (Test-Path -Path $destinationPath -PathType Leaf){ #In case item is a file, delete it. Remove-Item -Path $destinationPath } New-Item -ItemType Directory $destinationPath | Out-Null if (!$?){ return $false } } } Foreach ($fileOrDirectory in (Get-Item -Path "$sourcePath/*")) { $status = Copy-FilesBitsTransfer $fileOrDirectory $destinationPath $true if (!$status){ return $false } } } return $true }


Alternativamente, esta opción usa la barra de progreso nativa de Windows ...

$FOF_CREATEPROGRESSDLG = "&H0&" $objShell = New-Object -ComObject "Shell.Application" $objFolder = $objShell.NameSpace($DestLocation) $objFolder.CopyHere($srcFile, $FOF_CREATEPROGRESSDLG)


Modifiqué el código de stej (que era genial, ¡justo lo que necesitaba!) Para usar un buffer más grande, [largo] para archivos más grandes y utilicé System.Diagnostics.Stopwatch class para rastrear el tiempo transcurrido y estimar el tiempo restante.

También se agregaron informes de la velocidad de transferencia durante la transferencia y la salida del tiempo total transcurrido y la tasa de transferencia general.

Usar un búfer de 4MB (4096 * 1024 bytes) para obtener mejores resultados que el copiado de rendimiento nativo de Win7 del NAS al dispositivo USB en la computadora portátil a través de wifi.

En la lista de tareas pendientes:

  • agregar manejo de errores (catch)
  • manejar la lista de archivos get-childitem como entrada
  • barras de progreso anidadas al copiar varios archivos (archivo x de y,% si se copiaron datos totales, etc.)
  • parámetro de entrada para el tamaño del búfer

Siéntete libre de usar / mejorar :-)

function Copy-File { param( [string]$from, [string]$to) $ffile = [io.file]::OpenRead($from) $tofile = [io.file]::OpenWrite($to) Write-Progress ` -Activity "Copying file" ` -status ($from.Split("/")|select -last 1) ` -PercentComplete 0 try { $sw = [System.Diagnostics.Stopwatch]::StartNew(); [byte[]]$buff = new-object byte[] (4096*1024) [long]$total = [long]$count = 0 do { $count = $ffile.Read($buff, 0, $buff.Length) $tofile.Write($buff, 0, $count) $total += $count [int]$pctcomp = ([int]($total/$ffile.Length* 100)); [int]$secselapsed = [int]($sw.elapsedmilliseconds.ToString())/1000; if ( $secselapsed -ne 0 ) { [single]$xferrate = (($total/$secselapsed)/1mb); } else { [single]$xferrate = 0.0 } if ($total % 1mb -eq 0) { if($pctcomp -gt 0)` {[int]$secsleft = ((($secselapsed/$pctcomp)* 100)-$secselapsed); } else { [int]$secsleft = 0}; Write-Progress ` -Activity ($pctcomp.ToString() + "% Copying file @ " + "{0:n2}" -f $xferrate + " MB/s")` -status ($from.Split("/")|select -last 1) ` -PercentComplete $pctcomp ` -SecondsRemaining $secsleft; } } while ($count -gt 0) $sw.Stop(); $sw.Reset(); } finally { write-host (($from.Split("/")|select -last 1) + ` " copied in " + $secselapsed + " seconds at " + ` "{0:n2}" -f [int](($ffile.length/$secselapsed)/1mb) + " MB/s."); $ffile.Close(); $tofile.Close(); } }


No que yo supiese. No recomendaría el uso de copiar elementos para esto de todos modos. No creo que haya sido diseñado para ser robusto como robocopy.exe para admitir el reintento que usted desearía para copias de archivos extremadamente grandes a través de la red.


Parece una solución mucho mejor usar BitsTransfer, parece que viene OOTB en la mayoría de las máquinas Windows con PowerShell 2.0 o superior.

Import-Module BitsTransfer Start-BitsTransfer -Source $Source -Destination $Destination -Description "Backup" -DisplayName "Backup"


Sean Kearney del chico de Hey, Scripting! Blog tiene una solución que encontré funciona muy bien.

Function Copy-WithProgress { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] $Source, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] $Destination ) $Source=$Source.tolower() $Filelist=Get-Childitem "$Source" –Recurse $Total=$Filelist.count $Position=0 foreach ($File in $Filelist) { $Filename=$File.Fullname.tolower().replace($Source,'''') $DestinationFile=($Destination+$Filename) Write-Progress -Activity "Copying data from ''$source'' to ''$Destination''" -Status "Copying File $Filename" -PercentComplete (($Position/$total)*100) Copy-Item $File.FullName -Destination $DestinationFile $Position++ } }

Entonces para usarlo:

Copy-WithProgress -Source $src -Destination $dest


Trevor Sullivan tiene un Copy-ItemWithProgress sobre cómo agregar un comando llamado Copy-ItemWithProgress a PowerShell en Robocopy.


No he escuchado sobre el progreso con Copy-Item . Si no desea utilizar ninguna herramienta externa, puede experimentar con transmisiones. El tamaño del búfer varía, puede probar diferentes valores (de 2kb a 64kb).

function Copy-File { param( [string]$from, [string]$to) $ffile = [io.file]::OpenRead($from) $tofile = [io.file]::OpenWrite($to) Write-Progress -Activity "Copying file" -status "$from -> $to" -PercentComplete 0 try { [byte[]]$buff = new-object byte[] 4096 [int]$total = [int]$count = 0 do { $count = $ffile.Read($buff, 0, $buff.Length) $tofile.Write($buff, 0, $count) $total += $count if ($total % 1mb -eq 0) { Write-Progress -Activity "Copying file" -status "$from -> $to" ` -PercentComplete ([int]($total/$ffile.Length* 100)) } } while ($count -gt 0) } finally { $ffile.Dispose() $tofile.Dispose() Write-Progress -Activity "Copying file" -Status "Ready" -Completed } }


cmd /c copy /z src dest

no es pura PowerShell, sino ejecutable en PowerShell y muestra el progreso en porcentajes