Manage Learn to apply best practices and optimize your operations.

PowerShell commands to copy files: Basic to advanced methods

Admins proficient in PowerShell can build advanced scripts that copy files for different scenarios with added measures to ensure the duplicates reach their destinations.

Copying files between folders, drives and machines is a common administrative task that PowerShell can simplify....

Administrators who understand the parameters associated with the Copy-Item commands and how they work together will get the most from the PowerShell commands to copy files.

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 *-Item, *-ItemProperty, *-Content, *-Path and *-Location cmdlets. Therefore, you can use the Copy-Item cmdlet to copy files, Registry keys and variables.

The example in the following command uses variable $a:

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

When working with databases, administrators commonly use transactions -- one or more commands treated as a unit -- so the commands either all work or they all roll back. PowerShell transactions are only supported by the Registry provider, so the UseTransaction parameter on Copy-Item doesn't do anything. The UseTransaction parameter is part of Windows PowerShell v2 through v5.1, but not in the open source PowerShell Core.

When working with databases, administrators commonly use transactions -- one or more commands treated as a unit -- so the commands either all work or they all roll back.

PowerShell has a number of aliases for its major cmdlets. Copy-Item uses three aliases.

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 PowerShell Core users.

Ways to 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:

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\

While this works in scripts, it makes the code harder to understand and maintain.

To get feedback on the copy, we use the PassThru parameter:

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:

The Verbose parameter
Administrators can use the Verbose parameter to see detailed output when running PowerShell commands.

The Verbose parameter gives you information as the command executes, while PassThru shows you 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,

Microsoft.PowerShell.Commands.CopyItemCommand

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

As part of the copy process, you can rename the file. You must include the new file name as part of the destination. 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

}

PowerShell commands to copy multiple files

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 you can also be more selective and only copy files with, for instance, a 6 in the name.

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

You can also exclude certain files from the copy operation. This command copies all the 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
Administrators can fine-tune the PowerShell commands to copy certain files from a folder and exclude others.

You can combine the Path, Filter, Include or Exclude parameters to define exactly what to copy. If you use Include and Exclude in the same call, PowerShell ignores Exclude. You can also supply an array of file names. 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 2. If so, PowerShell copies the file to the C:\test2 folder.


How to use PowerShell cmdlets to copy, move
and delete files

If you end up with a folder or file name that contains wild-card characters, use the LiteralPath parameter instead of the Path parameter. LiteralPath treats all the characters as literals and ignores any possible wild-card implications.

To copy a folder and all its 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 UNC 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.

Copy-Item doesn't have any 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

   }

 }

}

In this script, the file path for the source is tested and a hash of the file is calculated. The file copy occurs within a try-catch block to catch and report errors.

With additional coding, the script can recursively retry a certain number of 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.

This was last published in September 2018

Dig Deeper on Windows administration tools

Join the conversation

3 comments

Send me notifications when other members comment.

Please create a username to comment.

The copy command issue that I could never quite understand is why you end up with 2 vastly different folder trees depending if the target folder already existed.  Example:  

# clean up any folders that already exist
remove-item -Path "C:\TargetPath1" -Recurse -ErrorAction SilentlyContinue
remove-item -Path "C:\TargetPath2" -Recurse -ErrorAction SilentlyContinue


# Create one of the targets
New-Item -Path "c:\" -Name "TargetPath2" -ItemType "directory"

# now do 1 copies.  
#  One to a folder that doesn't exist
#  the other to a empty folder that already exists
write-host "===== First copy to a folder that doesn't exist ====="
copy-item -path "C:\Tools\SysinternalsSuite\" -destination "C:\TargetPath1\" -Recurse -Verbose


write-host "===== Second copy to a folder that alredy exists ====="
copy-item -path "C:\Tools\SysinternalsSuite\" -destination "C:\TargetPath2\" -Recurse -Verbose
Cancel
Another way to demonstrate what I see is to do the exact same copy command twice in a row.  You may think the second copy command will overwrite the files the first command copied, but instead the results of the 2nd copy command has put the files in a subfolder of the target, using the original source folder's name.  Why is that?
Cancel
The answer to both questions is by design I think.  Reading the online help at https://docs.microsoft.com/en-gb/powershell/module/Microsoft.PowerShell.Management/Copy-Item?view=powershell-5.1 - examples 2 and 3 seem to explain what is happening.  I need to do some experimentation I have a suspicion that the -Container parameter is involved.
Cancel

-ADS BY GOOGLE

SearchServerVirtualization

SearchCloudComputing

SearchSQLServer

SearchEnterpriseDesktop

SearchVirtualDesktop

Close