PowerShell: Copy All Files from Subfolders and Rename Duplicate

Print View Mobile View

When copying and merging files from multiple folders, there may be times when you encounter conflicting files. These files may be having same file name but different content. To avoid replacing existing files they just have to be renamed. To help you out with this, here’s a PowerShell script to copy all files and automatically rename duplicate ones. All you need to do is provide the source and destination folder in the script, and you’re good to go. Let’s now look at the script.

Copy Files and Rename Duplicate

This PowerShell code runs a search through each subfolder within the source directory and copies all files to the target directory. While doing so, if any file already exist in the destination directory, it would rename the duplicate file by appending a number – which is automatically incremented – before the extension.

function fcopy ($SourceDir,$DestinationDir)
{
	Get-ChildItem $SourceDir -Recurse | Where-Object { $_.PSIsContainer -eq $false } | ForEach-Object ($_) {
		$SourceFile = $_.FullName
		$DestinationFile = $DestinationDir + $_
		if (Test-Path $DestinationFile) {
			$i = 0
			while (Test-Path $DestinationFile) {
				$i += 1
				$DestinationFile = $DestinationDir + $_.basename + $i + $_.extension
			}
		} else {
			Copy-Item -Path $SourceFile -Destination $DestinationFile -Verbose -Force
		}
		Copy-Item -Path $SourceFile -Destination $DestinationFile -Verbose -Force
	}
}
fcopy -SourceDir "C:\Source\Directory\" -DestinationDir "C:\Destination\Directory\"

Script Breakdown

We start off by specifying the source and destination directory in this line:

fcopy -SourceDir "C:\Source\Directory\" -DestinationDir "C:\Destination\Directory\"

Next, on running the script, a list of files is created by recursively searching through the source directory. Folders are excluded here.

Get-ChildItem $SourceDir -Recurse | Where-Object { $_.PSIsContainer -eq $false } | ForEach-Object ($_)

Once we have a list of file names, we are using the Test-Path cmdlet to determine whether a file already exists in the destination.

if (Test-Path $DestinationFile)

If it doesn’t exist, the file is immediately copied to the target directory.

Copy-Item -Path $SourceFile -Destination $DestinationFile -Verbose -Force

Now, if a file does exist, script enters in a While loop.

while (Test-Path $DestinationFile) {
	$i += 1
	$DestinationFile = $DestinationDir + $_.basename + $i + $_.extension
}

In this loop, file name is altered by adding a number at the end, but before the extension. This loop keeps on running until the script finds a name that doesn’t match an existing file. For instance, if a file New.pdf already exists, it will rename the next file as New2.pdf and copy it. Subsequent files are named New3.pdf, New4.pdf, and so on.

We are using Test-Path here as the default behavior for Copy-Item is to overwrite files in the target folder. With Test-Path, we are preserving all existing files and copying over new files.

Move Files and Rename Duplicate

Instead of copy, if you are looking to move all files to a single folder, simply replace Copy-Item with Move-Item cmdlet in the script. That’d move all files and automatically rename duplicate.

Move Specific Files and Rename Duplicate

Using -Filter, we can filter specific files:

-Filter *.txt

-Filter accepts a single string. To add more than one filter, you can use -Include:

-Include *.txt, *.xls

This script is based on this post by Kris Powell where he shows how to copy individual files and rename duplicates.