Progrès pendant la copie de gros fichiers (Copie-Item & écriture-progrès?)
y a-t-il un moyen de copier un très gros fichier (d'un serveur à un autre) dans PowerShell et d'afficher sa progression?
il existe des solutions pour utiliser Write-Progress en conjonction avec looping pour copier de nombreux fichiers et afficher la progression. Cependant, je ne trouve rien qui montre l'évolution d'un seul fichier.
une idée?
9 réponses
Je n'ai pas entendu parler de progrès avec Copy-Item
. Si vous ne voulez pas utiliser d'outil externe, vous pouvez expérimenter avec des flux. La taille du tampon varie, Vous pouvez essayer différentes valeurs (de 2KB à 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
}
}
il semble comme une bien meilleure solution pour juste utiliser BitsTransfer, il semble venir OOTB sur la plupart des machines Windows avec PowerShell 2.0 ou plus.
Import-Module BitsTransfer
Start-BitsTransfer -Source $Source -Destination $Destination -Description "Backup" -DisplayName "Backup"
Alternativly cette option utilise la barre de progression de windows native...
$FOF_CREATEPROGRESSDLG = "&H0&"
$objShell = New-Object -ComObject "Shell.Application"
$objFolder = $objShell.NameSpace($DestLocation)
$objFolder.CopyHere($srcFile, $FOF_CREATEPROGRESSDLG)
j'ai modifié le code de stej (ce qui était génial, juste ce dont j'avais besoin!) pour utiliser un tampon plus grand, [long] pour des fichiers plus gros et le système utilisé.Diagnostic.Classe du chronomètre pour suivre le temps écoulé et estimer le temps restant.
a également ajouté la déclaration du taux de transfert pendant le transfert et la sortie du temps total écoulé et du taux de transfert global.
utilisant un tampon de 4 Mo (4096*1024 octets) pour obtenir un meilleur débit que Win7 natif copie du NAS à USB bâton sur ordinateur portable sur wifi.
sur la liste des choses à faire:
- ajouter la gestion des erreurs (catch)
- poignée get-childitem liste de fichier comme entrée
- barres de progression imbriquées lors de la copie de plusieurs fichiers (fichier x de y, % si total données copiées etc)
- paramètre d'entrée pour la taille du tampon
N'hésitez pas à utiliser / améliorer :-)
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();
}
}
cmd /c copy /z src dest
pas pur PowerShell, mais exécutable en PowerShell et il affiche la progression en pourcentages
pas que je sache. Je ne recommande pas l'utilisation de copy-item pour cela de toute façon. Je ne pense pas qu'il a été conçu pour être robuste comme robocopy.exe à l'appui de réessayer de qui vous voulez pour les très grandes des copies de fichiers sur le réseau.
cette fonction récursive copie des fichiers et des répertoires de façon récursive du chemin source au chemin de destination
si le fichier existe déjà sur le chemin de destination, il ne les Copie qu'avec des fichiers plus récents.
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
}
Sean Kearney du Hé, le gars des scripts! Blog a une solution que j'ai trouvé fonctionne assez 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++
}
}
puis l'utiliser:
Copy-WithProgress -Source $src -Destination $dest
Trevor Sullivan a un rapport sur la façon d'ajouter une commande appelée Copy-ItemWithProgress à PowerShell sur Robocopy.