How to Copy Files and Folders with PowerShell

📜Part of the PowerShell Complete Guide, every PowerShell post on this site, grouped by the job you are doing.
The short answer

Copy-Item for most jobs, with -Recurse for folders. For very large trees, restartable copies or mirroring, call robocopy instead.

Copying is one of those tasks where the simple answer is right most of the time and badly wrong occasionally. Here is both halves of that.

Copy-Item, the Everyday Answer

# one file
Copy-Item "D:\Data\report.csv" -Destination "E:\Backup\report.csv"

# a whole folder, including everything inside it
Copy-Item "D:\Data" -Destination "E:\Backup\Data" -Recurse

# only certain files
Copy-Item "D:\Data\*.csv" -Destination "E:\Backup\"

# overwrite read-only files at the destination
Copy-Item "D:\Data\*" -Destination "E:\Backup\" -Recurse -Force

Copying Only What You Choose

The pipeline is where Copy-Item earns its place, because you can select files with any logic you like before copying them:

# only files changed in the last day
Get-ChildItem "D:\Data" -Recurse -File |
    Where-Object LastWriteTime -gt (Get-Date).AddDays(-1) |
    Copy-Item -Destination "E:\Backup\" -WhatIf
Copy-Item is not restartable. If it fails at 80% of a large copy, you start again. It also has no progress display worth the name on big trees, and no retry when a file is briefly locked. That is the point at which you stop using it.

When to Use robocopy Instead

robocopy ships with Windows, retries locked files, resumes, and can mirror. PowerShell calls it perfectly well:

# copy a tree, retry twice with a 5 second wait, multi-threaded
robocopy "D:\Data" "E:\Backup\Data" /E /R:2 /W:5 /MT:8

# MIRROR the destination to match the source - deletions included
robocopy "D:\Data" "E:\Backup\Data" /MIR /R:2 /W:5

# check how it went. robocopy exit codes below 8 are success
if ($LASTEXITCODE -lt 8) { "copy ok" } else { "copy FAILED: $LASTEXITCODE" }
/MIR deletes. Mirroring makes the destination identical to the source, so anything at the destination that is not in the source is removed. Point it at the wrong folder and it will empty it. Run with /L first, which lists what it would do and changes nothing.

The exit code check matters too: robocopy does not use 0 for success the way most tools do. Anything below 8 means it worked, with the number describing what it did.

Related


If SQL Server is part of your day job, my current work lives over at sqldba.blog: production DBA scripts, an error library and the SSMS guide.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Looking for SQL Server?

This site started as a SQL Server blog in 2017 and the archive is still here. The new SQL Server writing, and all the scripts, moved to a site of their own.

sqldba.blogScripts, error library, wait types, SSMS
Browse by topic