You’re running a nightly backup script, and it keeps overwriting files that already made it to the destination folder. That’s wasted time, wasted bandwidth, and a real risk if the newer copy accidentally replaces a good file with a broken one.
This happens because Copy-Item, the built-in PowerShell cmdlet for copying files and folders, doesn’t check for existing files by default. It either throws an error when a file already exists, or silently overwrites it if you add the -Force parameter. Neither behavior is what you want when your goal is to copy only the files that are missing.
Think of a real scenario: you manage a file server for a mid-size company, and every night a script copies new log files from \\Server01\Logs to a backup share at \\Server02\LogsBackup. Thousands of old log files already sit in the backup folder. You only want to copy the new ones, skip the rest, and avoid wasting time re-copying files that haven’t changed. In this article, I’ll show you 5 ways to do Copy-Item skip if file exists in PowerShell.
Method 1 – Using Test-Path in a Foreach Loop
Use this method for a quick, beginner-friendly script when you’re comfortable with basic loops and want full control over the logic.
Step 1: Set your source and destination paths
$Source = "\\Server01\Logs"
$Destination = "\\Server02\LogsBackup"
Step 2: Loop through each file and check if it exists
Get-ChildItem -Path $Source -File | ForEach-Object {
$DestFile = Join-Path -Path $Destination -ChildPath $_.Name
if (-not (Test-Path -Path $DestFile)) {
Copy-Item -Path $_.FullName -Destination $Destination
Write-Host "Copied: $($_.Name)"
} else {
Write-Host "Skipped (already exists): $($_.Name)"
}
}Sample Output:
Copied: server_log_2026-06-30.txt
Skipped (already exists): server_log_2026-06-29.txt
Copied: server_log_2026-07-01.txt
How does this script work?
Get-ChildItem retrieves every file in the source folder. The -File parameter tells it to grab files only, not folders. For each file, Test-Path checks whether a file with the same name already exists at the destination.
Join-Path safely combines the destination folder path with the file name, so you don’t run into issues with missing or extra backslashes. If the file doesn’t exist, Copy-Item copies it over; if it does, the script just prints a message and moves on.
Pro Tip: This method works great for folders with a few hundred to a few thousand files. For very large folders (tens of thousands of files), the repeated Test-Path calls can slow things down — consider Method 3 instead.
Method 2 – One-Liner Using Where-Object Filter
Use this method when you want a compact, single-line command for quick, ad-hoc use in the console.
Step 1: Build the one-liner
Get-ChildItem -Path "\\Server01\Logs" -File | Where-Object { -not (Test-Path (Join-Path "\\Server02\LogsBackup" $_.Name)) } | Copy-Item -Destination "\\Server02\LogsBackup"Sample Output:
(No console output by default — files are copied silently)
How does this script work?
This command chains three pipeline stages together using the pipe operator (|), which passes output from one cmdlet into the next. Get-ChildItem lists all files, Where-Object filters out any file that already exists at the destination, and the final Copy-Item copies only what’s left in the pipeline. It’s the same logic as Method 1, just condensed into a single line.
Pro Tip: Add -Verbose to the Copy-Item command if you want to see which files actually get copied, since this one-liner is silent by default.
Method 3 – Compare Two Folders with Compare-Object
Use this method when you need better performance with large folders, since it compares file lists in bulk rather than checking each file one at a time.
Step 1: Get file lists from both folders
$SourceFiles = Get-ChildItem -Path "\\Server01\Logs" -File
$DestFiles = Get-ChildItem -Path "\\Server02\LogsBackup" -File
Step 2: Compare the two lists and find files unique to the source
$FilesToCopy = Compare-Object -ReferenceObject $SourceFiles -DifferenceObject $DestFiles -Property Name |
Where-Object { $_.SideIndicator -eq "<=" }
Step 3: Copy only the missing files
foreach ($File in $FilesToCopy) {
Copy-Item -Path (Join-Path "\\Server01\Logs" $File.Name) -Destination "\\Server02\LogsBackup"
}Sample Output:
InputObject SideIndicator
----------- -------------
server_log_07-01.txt <=
How does this script work?
Compare-Object checks two collections and tells you what’s different between them. The -Property Name parameter compares files by their file name instead of full object data.
The SideIndicator column marks each result with <= (only in the reference/source folder) or => (only in the difference/destination folder). Filtering for <= gives you exactly the files that exist in source but not in the destination, so you only loop through and copy those.
Pro Tip: This approach scales much better than Method 1 for folders with 10,000+ files, because it builds two lists once instead of running Test-Path repeatedly inside a loop.
Check out Skip to Next Item in PowerShell ForEach Loop
Method 4 – Robocopy Wrapped Inside PowerShell
Use this method when you need a battle-tested, high-performance file copy tool built into Windows, especially for large-scale or scheduled backup jobs.
Step 1: Run Robocopy through PowerShell with the /XC /XN /XO switches
robocopy "\\Server01\Logs" "\\Server02\LogsBackup" /XC /XN /XO /E
Sample Output:
-------------------------------------------------------------------------------
ROBOCOPY : Robust File Copy for Windows
-------------------------------------------------------------------------------
Started : Wed July 01 2026 23:15:02
Source : \\Server01\Logs\
Dest : \\Server02\LogsBackup\
1 server_log_2026-07-01.txt (New File) 2.3 k
100%
------------------------------------------------------------------------------
Total Copied Skipped Mismatch FAILED Extras
Files : 50 1 49 0 0 0
How does this script work?
Robocopy (Robust File Copy) is a command-line tool built into Windows that PowerShell can call directly. The /XC switch excludes files whose content has changed, /XN excludes newer files, and /XO excludes older files — together, these three switches mean Robocopy only copies files that don’t already exist at the destination. The /E switch copies subfolders, including empty ones.
Pro Tip: Robocopy is the fastest and most reliable option for large enterprise file migrations, since Microsoft designed it specifically for resilient, resumable copy jobs over unreliable networks.
Read How to Use PowerShell Remove-Item with Try Catch
Method 5 – Function with Error Handling for Automation
Use this method when you’re building a reusable script for scheduled tasks and need logging plus error handling in case a file is locked or a path is unreachable.
Step 1: Define a reusable function
function Copy-IfNotExists {
param (
[string]$SourcePath,
[string]$DestinationPath
)
try {
$Files = Get-ChildItem -Path $SourcePath -File
foreach ($File in $Files) {
$DestFile = Join-Path -Path $DestinationPath -ChildPath $File.Name
if (-not (Test-Path -Path $DestFile)) {
Copy-Item -Path $File.FullName -Destination $DestinationPath -ErrorAction Stop
Write-Host "Copied: $($File.Name)" -ForegroundColor Green
} else {
Write-Host "Skipped: $($File.Name)" -ForegroundColor Yellow
}
}
} catch {
Write-Error "Failed to copy $($File.Name): $_"
}
}Step 2: Call the function with your paths
Copy-IfNotExists -SourcePath "\\Server01\Logs" -DestinationPath "\\Server02\LogsBackup"
Sample Output:
Copied: server_log_2026-07-01.txt
Skipped: server_log_2026-06-30.txt
Skipped: server_log_2026-06-29.txt
How does this script work?
A function in PowerShell is a reusable block of code you can call multiple times with different inputs. The param block defines the two inputs the function needs: source and destination paths.
The try/catch block is PowerShell’s error-handling structure — code inside try runs normally, and if anything fails, catch captures the error instead of crashing the whole script.
The -ErrorAction Stop parameter forces Copy-Item to throw a catchable error instead of just printing a warning, which is essential for reliable automation.
Pro Tip: Wrap this function inside a scheduled task using Task Scheduler or a Power Automate desktop flow to automate nightly backups without manual intervention.
Things to Keep in Mind
- Execution policy blocks scripts by default: Windows restricts running .ps1 script files out of the box; run Set-ExecutionPolicy RemoteSigned as an administrator to allow local scripts to run.
- Admin permissions matter for network shares: Copying to or from restricted folders often requires running PowerShell as an administrator or using proper credentials with Connect or mapped drive commands.
- -Force doesn’t mean skip: Many beginners assume -Force on Copy-Item skips existing files — it actually overwrites them, which is the opposite behavior.
- PowerShell 7 vs Windows PowerShell: Windows PowerShell 5.1 comes preinstalled on Windows, while PowerShell 7 is a separate, cross-platform install; both support Copy-Item and Robocopy, but PowerShell 7 handles large pipelines faster.
- Test on a small folder first: Always run your script against a small test folder before pointing it at a production share with thousands of files, since mistakes in file paths can copy the wrong files.
- Watch for locked files: Files currently open in another program can trigger errors mid-copy; the try/catch pattern in Method 5 helps you catch and log these without stopping the whole job.
This article covered five practical ways to skip existing files with Copy-Item in PowerShell, from a simple Test-Path loop to a full Robocopy and error-handled function approach. Use Method 1 or 2 for quick, small-scale tasks, and reach for Method 3, 4, or 5 when working with large folders or scheduled automation. I hope you found this article helpful.
You may also like:
Bijay Kumar is an esteemed author and the mind behind PowerShellFAQs.com, where he shares his extensive knowledge and expertise in PowerShell, with a particular focus on SharePoint projects. Recognized for his contributions to the tech community, Bijay has been honored with the prestigious Microsoft MVP award. With over 15 years of experience in the software industry, he has a rich professional background, having worked with industry giants such as HP and TCS. His insights and guidance have made him a respected figure in the world of software development and administration. Read more.