Use PowerShell to Copy Files to Multiple Locations

During the course of my work week, I often need to backup files. Most of the time, I need to copy files to another directory or location. On occasion, I find myself needing to copy the same files to multiple locations. Yes, I could wait for the first copy command to finish, hit the up arrow to get the last command, modify it, and copy again. This process seems like a lot of work, and I feel there has to be a more efficient way. As a result, I set out to see what I could do with PowerShell. I’m in PowerShell all the time so if I can get this to work, it will probably be faster than using the GUI. Plus, I may experience a scenario in the future where I need to do this without the GUI.

For the sake of my demonstration, I’m going to define two different destinations.

One very easy approach is to simply pass the results of the first copy operation to another.

Copy-Item by default doesn’t write anything to the pipeline unless you use –Passthru. In this one-line command, I am copying all the .txt files from C:\work to the first destination. As files are copied, they are copied again to the second destination. Technically the files in $destB are copies of the files in $destA. This sequential approach works nicely if the file sets are small, as files can’t get copied to the second destination until they are copied to the first.

Another approach is to use background jobs. I can define a hashtable of parameters to splat to Copy-Item.

It takes a little PowerShell sleight of hand to pass this hashtable, but I can create the first job.

The only thing that needs to change for the second job is the destination.

Then I can create another job.

My copy task in this example is the entire C:\Work folder including subfolders so this might take some time to copy. But it is copying to two locations simulataneously. I’m using –Passthru so I can always receive the job results if I want to verify. There is the potential for access violations depending on where you are copying and file size.

In my examples one destination is an external USB 3 drive and the other is a location on my NAS. I can’t guarantee this approach is hassle or error free.

Another idea I had was to spin up a second PowerShell window. Remember, ideally I’d like the copy process to run simultaneously. What I need to do is launch a command like this:

The challenge is to construct this dynamically for both locations.

The tricky part was getting the hashtable into the command scriptblock with all of the quoting and variable expansion issues. I found it easier to take the original parameter multi-line hashtable and recreate as a single entry with each key/value pair separated by a semi-colon. In the end $h looks like this:

That made it easier to pass as an argument and then splat. I also included a brief delay to avoid any access violations. This worked pretty well although it doesn’t lend itself well to a pipelined expression. I have to know in advance what I want to copy. But I have an idea.

While the original Copy-Item doesn’t accept multiple locations for the Destination parameter, perhaps I can create my own. So I created a proxy version of Copy-Item and inserted my own core copy commands using multiple PowerShell sessions.

I made the Destination parameter mandatory and configured it to accept an array. Now I can do this:

I removed the pipeline binding attribute for the Path parameter for performance reasons. A command like this won’t work:

I can live with this solution for what I need to copy.

Looking forward, I should probably add a parameter to control the Window style, or I can do something in conjunction with –Passthru, so that if you want to see the results, then you can. However, because the copy process is running in separate PowerShell sessions, I can’t really direct the output to the original shell without resorting to some other PowerShell voodoo. But it is something to consider or perhaps something you’d like tackle.

Related Topics:

  • PowerShell

    Don't have a login but want to join the conversation? Sign up for a Petri Account