How to Show Progress When Copying Files with PowerShell Copy-Item (Step-by-Step Tutorial)

One of our clients recently wanted us to display a progress bar while copying files from one directory to another. This is a valid requirement when copying larger files.

Unfortunately, PowerShell’s Copy-Item cmdlet doesn’t display a progress bar by default. I recall the first time I attempted to copy a massive folder from a network share to my local drive. I sat there, staring at the blinking cursor, wondering if anything was happening at all! In those scenarios, a progress bar will definitely be helpful.

In this tutorial, I will show you step-by-step how to show progress when using Copy-Item in PowerShell, using different methods such as Write-Progress and RoboCopy.

Limitations of Copy-Item in PowerShell

In PowerShell, you can use the Copy-Item cmdlet to copy files from one directory to another, but it doesn’t show progress natively.

Basic Syntax

Copy-Item -Path "C:\Users\Bijay\Documents\Reports" -Destination "D:\Backups\Reports" -Recurse

When I run this, there’s no indication of progress—just a blinking prompt until the command completes. For small files, this is fine. But for folders with hundreds or thousands of files, it’s not ideal.

Key Limitations:

FeatureCopy-Item Default
Progress Bar
File Count Info
ETA
Error HandlingBasic

To see progress, you’ll need to use a custom approach or a different tool.

Check out Create a Folder with Today’s Date and Copy Files to it using PowerShell

Show Progress When Copying Files with PowerShell Copy-Item

Method 1: Using Write-Progress with Copy-Item (Custom Script)

After running into the limitations above, I started writing scripts that wrap Copy-Item in a way that displays progress using PowerShell’s Write-Progress cmdlet.

How Write-Progress Works

Write-Progress shows a progress bar in the console window, updating as your script runs. You can use it to display the percentage of files copied, the current file, and even estimated time remaining.

Step-by-Step Example

Let’s say I want to copy all files from C:\Data to E:\Backup\Data and show progress.

$source      = "C:\Data"
$destination = "E:\Backup\Data"

# Get all files (recursively)
$files = Get-ChildItem -Path $source -Recurse -File
$total = $files.Count
$count = 0

foreach ($file in $files) {
    $relativePath = $file.FullName.Substring($source.Length)
    $targetPath   = Join-Path $destination $relativePath

    # Create target directory if it doesn't exist
    $targetDir = Split-Path $targetPath
    if (-not (Test-Path $targetDir)) {
        New-Item -Path $targetDir -ItemType Directory -Force | Out-Null
    }

    # Copy the file
    Copy-Item -Path $file.FullName -Destination $targetPath -Force

    $count++
    $percent = ($count / $total) * 100

    Write-Progress -Activity "Copying files..." `
                   -Status "Copying $($file.Name) ($count of $total)" `
                   -PercentComplete $percent
}

Write-Progress -Activity "Copying files..." -Completed -Status "Done!"

What’s Happening Here?

  • Get-ChildItem collects all files to copy.
  • The script loops through each file, copying it to the destination.
  • Write-Progress updates after each file, showing:
    • The name of the file being copied
    • How many files have been copied
    • The percentage complete

Why I Like This

  • It works for any folder, no matter how large.
  • The progress bar is clear and updates in real time.
  • You can easily add logging or error handling as needed.

When to Use

  • Copying many files or large directories.
  • When you need a simple, native PowerShell solution.
  • When you want to customize the progress output.

Read PowerShell Copy-item Create Folder If Not Exist

Method 2: Using RoboCopy for Built-In Progress

If you’ve ever copied files on Windows, you’ve probably heard of RoboCopy. It’s a robust command-line tool built into Windows, and it displays a detailed progress bar by default.

Why Use RoboCopy?

  • Built-in progress reporting (even for huge files)
  • Handles retries, network interruptions, and long paths
  • Great for copying large datasets

How to Use RoboCopy in PowerShell

You can call RoboCopy directly from PowerShell using the Start-Process or Invoke-Expression cmdlets.

Basic Example

Here is a basic example.

$source      = "C:\Data"
$destination = "E:\Backup\Data"

Start-Process -NoNewWindow -Wait -FilePath "robocopy.exe" `
    -ArgumentList "`"$source`" `"$destination`" /E /ETA /NFL /NDL"

Key RoboCopy Switches

SwitchDescription
/ECopy all subdirectories (including empty)
/ETAShow estimated time of arrival
/NFLNo file list (reduces output noise)
/NDLNo directory list

RoboCopy’s console output includes a live progress bar, file count, and ETA. It’s my go-to for heavy-duty copy jobs.

Advanced: Capture RoboCopy Output

If you want to capture RoboCopy’s output and display it in your PowerShell console, you can do:

$robocopyCmd = "robocopy `"$source`" `"$destination`" /E /ETA"
Invoke-Expression $robocopyCmd

Or, for even more control, parse its output and update a custom progress bar.

Check out Copy and Rename Files in PowerShell

Method 3: Monitoring Progress for Large Single Files

If you’re copying a single large file (like a video or backup image), neither Copy-Item nor Write-Progress will show byte-level progress. Here’s how I handle this:

Using System.IO for Byte-Level Progress

You can use .NET’s System.IO.FileStream to copy a file chunk by chunk and update progress based on bytes copied.

Example Script

$source      = "C:\BigFiles\movie.mp4"
$destination = "E:\Backup\movie.mp4"
$bufferSize  = 4MB

$sourceStream = [System.IO.File]::OpenRead($source)
$destStream   = [System.IO.File]::Create($destination)
$totalBytes   = $sourceStream.Length
$bytesCopied  = 0
$buffer       = New-Object byte[] $bufferSize

while (($read = $sourceStream.Read($buffer, 0, $bufferSize)) -gt 0) {
    $destStream.Write($buffer, 0, $read)
    $bytesCopied += $read
    $percent = ($bytesCopied / $totalBytes) * 100
    Write-Progress -Activity "Copying large file..." `
                   -Status "$([math]::Round($percent,2))% complete" `
                   -PercentComplete $percent
}

$sourceStream.Close()
$destStream.Close()

Write-Progress -Activity "Copying large file..." -Completed -Status "Done!"

When to Use

  • Copying very large files (multi-GB)
  • When you need real-time progress in PowerShell
  • For advanced automation scripts

Conclusion

In this tutorial, I explained how to show a progress bar while copying files from one folder to another using PowerShell. Over the years, I’ve relied on both custom Write-Progress scripts and RoboCopy for different scenarios.

If you’re working with lots of files or need advanced features, RoboCopy is hard to beat. For smaller copy jobs or when you want to stay 100% in PowerShell, the custom progress script is perfect.

Try out the methods above and see which one works best for your requirements. If you have any questions or want to share your own tips, drop a comment below—I’d love to hear from you.

I hope you found this tutorial helpful. If you have any questions or suggestions, feel free to leave them in the comments below!

You may also like the following tutorials:

100 PowerShell cmdlets download free

100 POWERSHELL CMDLETS E-BOOK

FREE Download an eBook that contains 100 PowerShell cmdlets with complete script and examples.