문제

PowerShell에서 실제로 큰 파일 (한 서버에서 다른 서버로)을 복사하고 진행 상황을 표시하는 방법이 있습니까?

루핑과 함께 쓰기 진행을 사용하여 많은 파일을 복사하고 진행 상황을 표시하는 솔루션이 있습니다. 그러나 단일 파일의 진행 상황을 보여주는 것을 찾을 수없는 것 같습니다.

이견있는 사람?

도움이 되었습니까?

해결책

나는 진보에 대해 듣지 못했습니다 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
    }
}

다른 팁

BitsTransfer를 사용하는 것이 훨씬 더 나은 솔루션 인 것 같습니다. PowerShell 2.0 이상의 대부분의 Windows 머신에서 OOTB가 오는 것 같습니다.

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

또는이 옵션은 기본 Windows Progress Bar를 사용합니다 ...

$FOF_CREATEPROGRESSDLG = "&H0&"

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

$objFolder = $objShell.NameSpace($DestLocation) 

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

순수한 PowerShell은 아니지만 PowerShell에서 실행 파일을 실행할 수 있으며 지출의 진행 상황이 표시됩니다.

더 큰 파일에 더 큰 버퍼를 사용하고 더 큰 파일 및 사용 된 System.Diagnostics.StopWatch 클래스를 사용하여 경과 시간을 추적하고 남은 시간을 추정하기 위해 STEJ (필요한 것만으로도 훌륭했습니다!)의 코드를 수정했습니다.

또한 전송 및 출력 중 전송 속도보고를 추가하여 전체 경과 시간 및 전체 전송 속도를 추가했습니다.

4MB (4096*1024 바이트) 버퍼를 사용하여 WIFI를 통해 노트북의 NAS에서 USB 스틱으로 Win7 기본 처리량 복사보다 우수합니다.

할 일 목록에서 :

  • 오류 처리 (캐치) 추가
  • 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();
    }
}

내가 알고있는 것은 아닙니다. 어쨌든 복사 항목을 사용하지 않는 것이 좋습니다. 나는 그것이 네트워크를 통해 매우 큰 파일 사본을 원하는 재 시도를 지원하기 위해 Robocopy.exe와 같이 강력하게 설계되었다고 생각하지 않습니다.

이 재귀 함수는 소스 경로에서 대상 경로로 파일과 디렉토리를 재귀 적으로 복사합니다.

파일이 이미 대상 경로에 존재하는 경우 최신 파일로만 복사합니다.

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에서 이봐, 스크립팅 남자! 블로그 내가 찾은 솔루션이 꽤 잘 작동합니다.

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

그런 다음 사용하십시오 :

Copy-WithProgress -Source $src -Destination $dest

Trevor Sullivan은 프로토리를 복사 할 수 있습니다 Robocopy에 PowerShell에게.

오래된 주제를 부딪히는 사람이 싫지만이 게시물이 매우 유용하다는 것을 알았습니다. Stej의 스 니펫에서 성능 테스트를 실행 한 후 Graham Gold의 개선과 Nacht의 비트 제안서에 따르면 다음과 같습니다.

  1. 진짜 시간 추정과 속도 읽기와 함께 Graham의 명령을 좋아했습니다.
  2. 나도 진짜 비트를 전송 방법으로 사용하는 데의 상당한 속도 증가가 마음에 들었습니다.

둘 사이의 결정에 직면했습니다 ... START-BITSTRANSFER가 비동기 모드를 지원한다는 것을 알았습니다. 그래서 여기에 두 가지를 병합 한 결과가 있습니다.

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
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top