There are many factors to consider when copying files within a script.
In many instances, we check for the existence of a file and only copy the file if it does not exist. Sometimes we only copy if it’s older/newer than a certain file. Sometimes we only copy if the file sizes are different…and so on and so forth.
I’m sure that you get the idea. There are many things to consider.
For this particular case, I wanted to keep all copies and rename any duplicates sequentially. I will be using Copy-Item to get this done.
Normally, when using Copy-Item, you’ll find that it will overwrite any destination files. It will not create any nonexistent folders in your destination file path.
For example, if you try to copy the source file to a new location that doesn’t exist yet, you will see a similar error:
In this case, the
C:\Temp\File.txt file exists but the subdirectory does not, as it mentions in the error above.
The only way to get Copy-Item to create the subdirectories if they don’t already exist is to copy a directory recursively. Unfortunately, it will not work with individual files, so it is out of the scope for this post.
One of the simplest ways to get the nonexistent directories created when copying individual files is to test for missing files and manually create the file before you copy (similar to unix/linux “touch” command).
In order to verify if a file already exists, we will use the Test-Path cmdlet. Test-Path can verify if a file or folder exists. When using Test-Path, items that exist will return $true whereas items that do not exist (or cannot be verified) will return $false:
Once we’ve verified that a file doesn’t exist, we can use New-Item to create a placeholder for the file we’re about to copy. Unlike Copy-Item, New-Item can create the nonexistent directory structure when creating new files.
Here’s an example of creating the destination file before copying (in order to create the destination file’s directory structure):
Breaking it down:
Finally, we are able to successfully use the Copy-Item command to copy the
$SourceFile to the newly-created
As awesome as this is, it only gets us partially there. The normal behavior for Copy-Item will overwrite the destination file (with or without
-Force). We’re trying to preserve all files and create duplicate destination files instead of overwriting.
Here is a simple way to copy a file from one location to another while preserving all destination files. We increment the destination file names:
Breaking it down:
We test if the path $DestinationFile exists by using Test-Path. We then check if the file name already exists.
If $DestinationFile doesn’t exist, it will create the file and then copy the source over the destination file.
If $DestinationFile does already exist, it will jump into a While loop. It will modify the Destination File name by incrementing part of the name, testing each modified name until it finds a name that doesn’t match an existing file.
If File.txt doesn’t exist, it will create File.txt first. Subsequent runs will create, File1.txt, File2.txt, File3.txt and so forth.
Keep in mind that copying large or numerous files will result in increased disk usage, so be sure to keep an eye on your utilization.
Use these scripts at your own risk. Be sure you understand what you’re doing before using these in a production environment. As always, feel free to modify these to suit your environment.
I realize that there are many ways to tackle the issues above. In fact, the latest estimates place the possibilities at around 1.2 bajillion, though scientists predict even greater numbers.
Additional resources and tools for copying/moving/deleting files are also available, such as one of my favorite tools for copying: Robocopy.
Did you know that PDQ Deploy has a PowerShell step you can use to deploy your scripts?
Kris was an employee at PDQ.