Frage

Gibt es eine Möglichkeit, eine wirklich große Datei (von einem Server auf einem anderen) in Powershell zu kopieren und den Fortschritt angezeigt?

Es gibt Lösungen gibt in Verbindung Write-Progress zu verwenden, um mit Looping viele Dateien und Anzeige Fortschritt zu kopieren. Allerdings kann ich nicht scheinen, nichts zu finden, die den Fortschritt einer einzelnen Datei zeigen würde.

Alle Gedanken?

War es hilfreich?

Lösung

Ich habe nicht über Fortschritte bei Copy-Item gehört. Wenn Sie ein externes Tool nicht verwenden möchten, können Sie mit Streams experimentieren. Die Größe des Puffers variiert, können Sie verschiedene Werte versuchen (von 2 kb bis 64 kb).

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
    }
}

Andere Tipps

Es scheint wie eine viel bessere Lösung nur BitsTransfer zu verwenden, so scheint es OOTB auf den meisten Windows-Rechnern mit Powershell 2.0 oder höher zu kommen.

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

Alternativly diese Option nutzt die native Windows-Statusleiste ...

$FOF_CREATEPROGRESSDLG = "&H0&"

$objShell = New-Object -ComObject "Shell.Application"

$objFolder = $objShell.NameSpace($DestLocation) 

$objFolder.CopyHere($srcFile, $FOF_CREATEPROGRESSDLG)
cmd /c copy /z src dest

nicht reines Powershell, aber ausführbare Datei in Powershell und zeigt die Fortschritte in Prozent

ich den Code aus stej jeweils gültigen Fassung (das war toll, genau das, was ich brauchte!) Größeren Puffer zu verwenden, [lang] für größere Dateien und gebrauchte System.Diagnostics.Stopwatch Klasse verbleibenden verstrichene Zeit und Schätzung der Zeit zu verfolgen.

Auch hinzugefügt während der Übertragung Berichterstattung von Übertragungsrate und Gesamt verstrichene Zeit und die Gesamtübertragungsrate ausgegeben werden.

4MB Verwendung (4096 * 1024 Bytes) Puffer, besser zu werden als Win7 nativen Durchsatz Kopieren von NAS auf USB-Stick am Laptop über WLAN.

Auf To-Do-Liste:

  • Add Fehlerbehandlung (catch)
  • handle get-childitem Dateiliste als Eingabe
  • verschachtelte Balken Fortschritt, wenn mehrere Dateien zu kopieren (Datei x von y, wenn% Gesamt Daten kopiert usw.)
  • Eingabeparameter für Puffergröße

Fühlen Sie sich frei zu verwenden / verbessern: -)

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();
    }
}

Nicht, dass ich wüsste. Ich würde copy-Element mit für diese ohnehin nicht empfehlen. Ich glaube nicht, es wie robocopy.exe zu Unterstützung Wiederholungs robust sein konzipiert wurde, die Sie für extrem große Dateikopien über das Netzwerk wünschen würden.

Diese rekursive Funktion kopiert Dateien und Verzeichnisse rekursiv aus Quellpfad Zielpfad

Wenn die Datei existiert bereits auf Zielpfad, kopiert er sich nur mit neueren Dateien.

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 von der Hey, Scripting Guy! Blog hat eine Lösung, die ich funktioniert ziemlich gut gefunden.

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++
    }
}

Dann, es zu benutzen:

Copy-WithProgress -Source $src -Destination $dest

Trevor Sullivan hat eine Zuschreibung auf, wie ein Befehl hinzufügen namens Copy-ItemWithProgress zu Powershell auf Robocopy .

Hass derjenige zu sein, ein altes Thema zu stoßen, aber ich fand dieser Beitrag sehr nützlich. Nach dem Ausführen von Performance-Tests auf den Schnipseln von stej und die Verfeinerung von Graham Gold, plus dem BITS Vorschlag von Nacht, ich habe decuded dass:

  1. I wirklich mochte Graham Befehl mit der Zeit Schätzungen und Geschwindigkeitswerten.
  2. ich auch wirklich mochte die deutliche Geschwindigkeitssteigerung von BITS als meine Übertragungsmethode verwendet wird.

Angesichts der Entscheidung zwischen den beiden ... fand ich, dass Start BitsTransfer Asynchronous-Modus unterstützt. So, hier ist das Ergebnis meiner die beiden fusionierenden.

function Copy-File {
    param([string]$from, [string]$to)

    try {
        $job = Start-BitsTransfer -Source $from -Destination $to `
                   -Description "Moving: $from => $to" `
                   -DisplayName "Backup" -Asynchronous

        # Start stopwatch
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        Write-Progress -Activity "Connecting..."

        while ($job.JobState.ToString() -ne "Transferred") {
            switch ($job.JobState.ToString()) {
                "Connecting" {
                    break
                }
                "Transferring" {
                    $pctcomp = ($job.BytesTransferred / $job.BytesTotal) * 100
                    $elapsed = ($sw.elapsedmilliseconds.ToString()) / 1000

                    if ($elapsed -eq 0) {
                        $xferrate = 0.0
                    } else {
                        $xferrate = (($job.BytesTransferred / $elapsed) / 1mb);
                    }

                    if ($job.BytesTransferred % 1mb -eq 0) {
                        if ($pctcomp -gt 0) {
                            $secsleft = ((($elapsed / $pctcomp) * 100) - $elapsed)
                        } else {
                            $secsleft = 0
                        }

                        Write-Progress -Activity ("Copying file '" + ($PathName.Split("\") | Select -last 1) + "' @ " + "{0:n2}" -f $xferrate + "MB/s") `
                                       -PercentComplete $pctcomp `
                                       -SecondsRemaining $secsleft
                    }
                    break
                }
                "Transferred" {
                    break
                }
                Default {
                    throw $job.JobState.ToString() + " unexpected BITS state."
                }
            }
        }

        $sw.Stop()
        $sw.Reset()
    } finally {
        Complete-BitsTransfer -BitsJob $job
        Write-Progress -Activity "Completed" -Completed
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top