Get started Bring yourself up to speed with our introductory content.

Level up with these advanced PowerShell commands to copy files

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 is 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 folders.

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

These include the following cmdlets:

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

Therefore, you can use the Copy-Item cmdlet to copy files, Registry keys and variables.

How do you use the Copy-Item command?

The example in the following command uses variable $a:

Copy-Item -Path variable:a -Destination variable:aa

A common practice in PowerShell is to use transactions -- one or more commands treated as a unit -- so the commands either work or they roll back.

Only the Registry provider supports PowerShell transactions, so the UseTransaction parameter on Copy-Item doesn't do anything. The UseTransaction parameter is part of Windows PowerShell v2 through v5.1, but it's not in the newer cross-platform PowerShell version.

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 -Definition copy-item
CommandType     Name           Version    Source
-----------     ----            -------    ------
Alias           copy -> Copy-Item
Alias           cp -> Copy-Item
Alias           cpi -> Copy-Item

These aliases only exist on Windows PowerShell to prevent a conflict with native Linux commands for users on the open source version of PowerShell.

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:

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

The issue with this command is there is no indication if the operation succeeds or fails.

When working interactively, you can use the alias and positional parameters to reduce typing.

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

This works in scripts, but it makes the code harder to understand and maintain.

To get feedback on the copy, use the PassThru parameter. This feature gives results for a command that does not generate output. It's a helpful tool to confirm the command performed properly.

Copy-Item -Path C:\test\p1.txt -Destination C:\test2\ -PassThru
    Directory: C:\test2
Mode          LastWriteTime    Length Name
----          -------------     ------ ----
-a----       13/08/2018  11:01    40670 p1.txt

Or we can 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 : Access to the path 'C:\test2\p1.txt' is denied.
At line:1 char:1
+ Copy-Item -Path C:\test\p1.txt -Destination C:\test2\
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (C:\test\p1.txt:FileInfo) [Copy-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : CopyFileInfoItemUnauthorizedAccessError,

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 called p2.txt through p10.txt.

2..10 | foreach {
 $newname = "p$_.txt"
 Copy-Item -Path C:\test\p1.txt -Destination C:\test\$newname

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

There are a few techniques to copy multiple files 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, the command below only copies files with a 6 in the filename.

Copy-Item -Path C:\test\* -Include *6*.txt -Destination C:\test2\ -PassThru
    Directory: C:\test2
Mode        LastWriteTime       Length Name
----         -------------      ------ ----
-a----       13/08/2018 11:01    40670 p6.txt
-a----       13/08/2018 11:01    40670 x6.txt

The 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\
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

Combine the Path, Filter, Include or Exclude parameters to refine the copy process even further. 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 accepts pipeline input.

Get-ChildItem -Path C:\test\p*.txt |
where {(($_.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.

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 {
 param (
 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.

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.

Dig Deeper on Windows administration tools