Best practices for using PowerShell ISE for scripting 4 PowerShell modules every IT pro should know
X
Tip

How to copy files from source to destination in PowerShell

Take a closer look at Copy-Item cmdlet coding examples to build advanced PowerShell scripts that copy files with safety measures to ensure the duplicates reach their destinations.

Copying files between folders, drives and machines can be a waste of your time if you do it manually on a regular basis. A bit of PowerShell knowhow automates this tedious process and even handles the most complex situations.

Once you understand the parameters associated with the Copy-Item command and how they work together, you can produce comprehensive scripts with more advanced PowerShell commands to copy files and directories.

All these examples work on both Windows PowerShell and PowerShell 7.

PowerShell has providers -- .NET programs that expose the data in a data store for viewing and manipulation -- and a set of generic cmdlets that work across providers.

These include the following cmdlets:

  • *-Item
  • *-ItemProperty
  • *-Content
  • *-Path
  • *-Location

Therefore, with a default installation of PowerShell or Windows PowerShell, you can use the Copy-Item cmdlet to copy files, Registry keys and variables. Some modules do include custom providers, such as the Active Directory module, which lets you use those generic cmdlets in the data they expose. If you want to view the PowerShell providers in your PowerShell session, use the following.

Get-PsProvider

For example, in my PowerShell 7 session on Windows 10, I have the following providers.

Get-PsProvider cmdlet
Get-PsProvider cmdlet in PowerShell 7 with various providers

How do you use the Copy-Item command?

The simplest form of Copy-Item involves a source path and a destination path. If we want to use the FileSystem provider -- which all the following examples will assume -- we specify our paths by starting with a drive letter and a colon.

Using the .\ or ./ to represent the current directory infers the current path based on the current working directory, which doesn't have to be a FileSystem provider path. You can check your current working directory with Get-Location.

The example in the following command copies a single file located at the Path parameter to the path specified in the Destination parameter.

Copy-Item -Path C:\source\path\file.txt -Destination D:\dest\path\text.txt

If you prefer to use a shorter command, PowerShell has several aliases for its major cmdlets. The following command shows the three aliases, copy, cp and cpi, for the Copy-Item cmdlet.

Get-Alias cmdlet with -Definition Copy-Item parameter
Get-Alias with the -Definition Copy-Item parameter gets the aliases for that cmdlet.

In PowerShell on Linux, the cp alias doesn't exist because there is an existing Linux command named cp.

How can you use PowerShell commands to copy files?

To show how the various Copy-Item parameters work, create a test file with the following command.

Get-Process | Out-File -FilePath c:\test\p1.txt

Use this command to copy a file with the Destination parameter. We aren't specifying a file name in the destination parameter. In this case, it will use the original file name of "p1.txt."

Copy-Item -Path C:\test\p1.txt -Destination C:\test2\

A confusing part of using Copy-Item is that there is no output if the command succeeds.

Copy-Item cmdlet
Copy-Item cmdlet using the p1.txt file

If you want to take advantage of both the command's alias and position parameters, you can specify the source and destination in order.

Copy C:\test\p1.txt C:\test2\

However, alias use in saved scripts should be avoided for the most part as it isn't considered best practice.

To get feedback from Copy-Item, use the PassThru parameter. This feature returns objects for each of the items that was copied. It's a helpful tool to confirm the command performed properly.

Copy-Item -Path C:\test\p1.txt -Destination C:\test2\ -PassThru
Copy-Item with the PassThru parameter
The Copy-Item cmdlet with the PassThru parameter returns objects for the copied items.

You can also use the Verbose parameter.

PowerShell Verbose parameter
The Verbose parameter shows detailed output when running PowerShell command

The Verbose parameter gives you information as the command executes, whereas PassThru shows the result.

By default PowerShell overwrites the file if a file with the same name exists in the target folder.

If the file in the target directory is set to read-only, you'll get an error.

Copy-Item -Path C:\test\p1.txt -Destination C:\test2\
Copy-Item cmdlet error
The Copy-Item cmdlet returns an error if the file is read-only.

You need to be a PowerShell Jedi to overcome this. Use the Force parameter.

Copy-Item -Path C:\test\p1.txt -Destination C:\test2\ -Force

PowerShell can rename files as part of the copy process. For example, this code creates nine copies of the p1.txt file named "p2.txt" through "p10.txt."

2..10 | Foreach-Object {
 $newname = "p$_.txt"
 Copy-Item -Path C:\test\p1.txt -Destination C:\test2\$newname -Verbose
}
Foreach-Object and Copy-Item cmdlets
The Foreach-Object cmdlet with the Copy-Item cmdlet can be used to rename the file copies to avoid the error.

In this case, we're using the ".." operator to create an array of integers from two to 10. Then for each of those integers, we're creating a new file with the names that you can see in the verbose output.

How can you use PowerShell commands to copy multiple files or folders?

There are a few techniques to copy multiple files or folders when using PowerShell.

Copy-Item -Path C:\test\*.txt -Destination C:\test2\
Copy-Item -Path C:\test\*  -Filter *.txt -Destination C:\test2\
Copy-Item -Path C:\test\* -Include *.txt -Destination C:\test2\

These commands copy all the .txt files from the test folder to the test2 folder, but the Include parameter lets PowerShell be more selective. For example, this command only copies files with "6" in the filename.

Copy-Item -Path C:\test\* -Include *6*.txt -Destination C:\test2\ -PassThru
Copy-Item cmdlet with the Include parameter
The Copy-Item cmdlet with the Include parameter specifies which files to copy.

Copy-Item has an Exclude parameter to reject certain files from the copy operation. This PowerShell command only copies text files that start with the letter P unless there is a "7" in the name.

Copy-Item -Path C:\test\*  -Filter p*.txt  -Exclude *7*.txt -Destination C:\test2\ -PassThru
PowerShell copying
You can customize the PowerShell commands to copy files from a folder if they begin with a certain letter but ignore them if they contain a particular character.

Example: Learn to use the Path, Filter, Include or Exclude parameters

You can combine the Path, Filter, Include or Exclude parameters to refine the copy process even further. However if you use Include and Exclude in the same call, PowerShell ignores Exclude. You can also supply an array of filenames. The path is simplified if your working folder is the source folder for the copy.

Copy-Item -Path p1.txt,p3.txt,x5.txt -Destination C:\test2\

The Path parameter also accepts pipeline input.

Get-ChildItem -Path C:\test\p*.txt |
Where-Object {(($_.BaseName).Substring(1,1) % 2 ) -eq 0} |
Copy-Item -Destination C:\test2\

PowerShell checks the p*.txt files in the c:\test folder to see if the second character is divisible by two. If so, PowerShell copies the file to the C:\test2 folder.

If you end up with a folder or file name that contains wildcard characters (*, [, ], ?), use the LiteralPath parameter instead of the Path parameter. LiteralPath treats all the characters as literals and ignores any wildcards.

Example: Recursive copy

To copy a folder and its entire contents, use the Recurse parameter.

Copy-Item -Path c:\test\ -Destination c:\test2\ -Recurse

The recursive copy will work its way through all the subfolders below the c:\test folder. PowerShell will then create a folder named "test" in the destination folder and copy the contents of c:\test into it.

When copying between machines, you can use universal naming convention paths to bypass the local machine.

Copy-Item -Path \\server1\fs1\test\p1.txt -Destination \\server2\arc\test\

Another option is to use PowerShell commands to copy files over a remoting session.

$cred = Get-Credential -Credential W16ND01\Administrator
$s = New-PSSession -VMName W16ND01 -Credential $cred

In this case, we use PowerShell Direct to connect to the remote machine. You'll need the Hyper-V module loaded to create the remoting session over the VMBus. Next, use PowerShell commands to copy files to the remote machine.

Copy-Item -Path c:\test\ -Destination c:\ -Recurse -ToSession $s

You can also copy from the remote machine.

Copy-Item -Path c:\test\p*.txt -Destination c:\test3\ -FromSession $s

The ToSession and FromSession parameters control the direction of the copy and whether the source and destination are on the local machine or a remote one. You can't use ToSession and FromSession in the same command, and you also can't use relative paths.

Example: Advanced techniques to check for errors and resume a copy

The Copy-Item cmdlet lacks error checking or restart capabilities. For those features, you'll need to write the code. Here is a starting point. 

function Copy-FileSafer {
 [CmdletBinding()]
 param (
   [string]$path,
   [string]$destinationfolder
 )
 if (-not (Test-Path -Path $path)) {
   throw "File not found: $path"
 }
 $sourcefile = Split-Path -Path $path -Leaf
 $destinationfile = Join-Path -Path $destinationfolder -ChildPath $sourcefile
 $b4hash = Get-FileHash -Path $path
 try {
    Copy-Item -Path $path -Destination $destinationfolder -ErrorAction Stop
 }
 catch {
   throw "File copy failed"
 }
 finally {
   $afhash = Get-FileHash -Path $destinationfile
   if ($afhash.Hash -ne $b4hash.Hash) {
      throw "File corrupted during copy"
   }
   else {
     Write-Information -MessageData "File copied successfully" -InformationAction Continue
   }
 }
}

This script tests the source file path and calculates the file hash. The file copy process occurs within a try/catch block used for exception handling. So if an error is detected, it will display "File copy failed."

With additional coding, the script can recursively retry several times. After each copy attempt the script can calculate the hash of the file and compare it to the original. If they match, all is well. If not, an error is reported.

Editor's note: Richard Siddaway originally wrote this article, and Anthony Howell has expanded it.

Next Steps

25 basic PowerShell commands for Windows administrators

Best practices for using PowerShell ISE for scripting

How to upload and download files with PowerShell FTP script

Dig Deeper on Microsoft messaging and collaboration