大文件复制期间的进度(Copy-Item&Write-Progress?)

Jas*_*ett 56 powershell progress copy-item copying progress-bar

有没有办法在PowerShell中复制一个非常大的文件(从一个服务器到另一个服务器)并显示其进度?

有一些解决方案可以将Write-Progress与循环结合使用来复制许多文件并显示进度.但是,我似乎无法找到任何可以显示单个文件进度的内容.

有什么想法吗?

Nac*_*ica 85

这似乎是一个更好的解决方案,只使用BitsTransfer,它似乎在大多数Windows机器上使用PowerShell 2.0或更高版本来OOTB.

Import-Module BitsTransfer
Start-BitsTransfer -Source $Source -Destination $Destination -Description "Backup" -DisplayName "Backup"
Run Code Online (Sandbox Code Playgroud)

  • 正是我的工作完美并给出了进度条! (2认同)
  • 这应该是最佳答案。 (2认同)
  • 奇怪的是,当我运行命令时,什么也没有发生,没有输出?我使用例如 -Source "\\comp1\c$\folder" -Destionation "\\comp2\c$\folder" ,知道可能出了什么问题吗?我可以访问这两个文件夹,没有问题。如果我使用 copy-item 它可以工作,但显然没有任何进展。 (2认同)

ste*_*tej 45

我没有听说过进步Copy-Item.如果您不想使用任何外部工具,可以尝试使用流.缓冲区的大小各不相同,您可以尝试不同的值(从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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 有趣的解决方案.当我尝试它时,我收到一个错误 - 无法将值"2147483648"转换为"System.Int32".错误:"对于Int32,值太大或太小." 将[int]替换为[long]后,效果很好.谢谢 (5认同)
  • 嗯,这更像是一个编程讽刺而不是脚本编写(如果你选择区分),但从计算机科学的角度来看:你依赖的是一个对象的内部实现细节,这些细节不能得到保证,并且可以随时改变,并且不遵循既定的公共合同模式.这既违反了面向对象设计的主要租户,也忽略了公共IDisposable合同(您*应该知道存在的合同),该合同具有完善的最佳实践,表明应该始终处置它. (4认同)

小智 24

另外,此选项使用本机Windows进度条...

$FOF_CREATEPROGRESSDLG = "&H0&"

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

$objFolder = $objShell.NameSpace($DestLocation) 

$objFolder.CopyHere($srcFile, $FOF_CREATEPROGRESSDLG)
Run Code Online (Sandbox Code Playgroud)


小智 16

cmd /c copy /z src dest
Run Code Online (Sandbox Code Playgroud)

不是纯PowerShell,而是PowerShell中的可执行文件,它以百分比显示进度


Gra*_*old 14

我修改了stej中的代码(这很好,正是我需要的!)使用更大的缓冲区,[long]用于更大的文件,并使用System.Diagnostics.Stopwatch类来跟踪已用时间和估计剩余时间.

还添加了传输过程中传输速率的报告,并输出了总体经过时间和总体传输速率.

使用4MB(4096*1024字节)缓冲区比通过wifi从笔记本电脑上的NAS到USB棒的Win7本机吞吐量更好.

待办事项列表:

  • 添加错误处理(catch)
  • 将get-childitem文件列表作为输入处理
  • 复制多个文件时的嵌套进度条(y的文件x,复制的总数据的%等)
  • 缓冲区大小的输入参数

随意使用/改进:-)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Kei*_*ill 9

不是我知道的.无论如何,我不建议使用copy-item.我认为它不像robocopy.exe那样强大,以支持你想要通过网络进行超大文件拷贝的重试.