This post explains how to use PowerShell Copy-Item to copy a file or folder including mirror copy!
Throughout this example, consider that we have created the following folder/file structure:
C:\alkanesource
│ file1.txt
│ file2.log
│ file3.zip
└───alkanesubfolder
│ file4.ps1
C:\alkanedestination
C:\alkanesource
contains all of the files and folders we want to copy – this is our source location. And
C:\alkanedestination
is an empty folder where we want to copy files and folder to – this is our destination location.
Copy a Single Known File Name using Copy-Item
We can copy a single known file name to a destination is as simple as:
Copy-Item -Path "C:\alkanesource\file1.txt" -Destination "C:\alkanedestination"
Result
C:\alkanedestination
│ file1.txt
Copy Multiple Known File Names using Copy-Item
We can copy multiple known filenames by providing a string array containing file paths to the
-Path
parameter like so:
$multipleKnownFilenames = "C:\alkanesource\file1.txt","C:\alkanesource\file2.log"
Copy-Item -Path $multipleKnownFilenames -Destination "C:\alkanedestination"
Result
C:\alkanedestination
│ file1.txt
│ file2.log
Filter Copied Files using Include and Exclude (Excluding Files in Sub folders)
We can include or exclude certain file names or types from a copy operation using the
-Include
and
-Exclude
parameters.
Here is an example of including the file types of *.log and *.zip – note that the source copy path indicates we’re copying files and is denoted by *.*.
$filesToInclude = "*.log","*.zip"
Copy-Item -Path "C:\alkanesource\*.*" -Destination "C:\alkanedestination" -Include $filesToInclude
Result
C:\alkanedestination
│ file2.log
│ file3.zip
Here is an example of excluding the file names file3.zip and file1.txt – note again that the source path indicates we’re copying files and is denoted by *.*.
$filesToExclude = "file3.zip","file1.txt"
Copy-Item -Path "C:\alkanesource\*.*" -Destination "C:\alkanedestination" -Exclude $filesToExclude
Result
C:\alkanedestination
│ file2.log
Copying All File Names using Copy-Item (Excluding Files in Sub folders)
Here we can copy all files (excluding those in subfolders) from our source folder to the destination folder by using the wildcard “*.*” – the first asterisk represents “any file name” and the second asterisk represents “any file extension”.
Copy-Item -Path "C:\alkanesource\*.*" -Destination "C:\alkanedestination"
Result
C:\alkanedestination
│ file1.txt
│ file2.log
│ file3.zip
You will notice that the previous examples didn’t copy the files contained within
alkanesubfolder
. Many people think that adding the
-recurse
parameter will resolve this. But the
-recurse
parameter only creates a destination folder structure if the source is a folder, not if it is a file. When the source is a file (as in our example above),
Copy-Item
expects the destination to be a file or a folder that already exists. Which it doesn’t!
Copying All File Names and Sub Folders using Copy-Item
To copy all files and sub folders recursively, instead of targeting files as our source we must instead target the folder. Note that specifying one asterisk represents any wildcard folder:
Copy-Item -Path "C:\alkanesource\*" -Destination "C:\alkanedestination" -Recurse
Result
C:\alkanedestination
│ file1.txt
│ file2.log
│ file3.zip
└───alkanesubfolder
│ file4.ps1
Note that if we didn’t specify the wildcard (representing any folder), it will also include copying the source folder itself to the destination:
C:\alkanedestination
└───alkanesource
│ file1.txt
│ file2.log
│ file3.zip
└───alkanesubfolder
│ file4.ps1
Mirror Copying Specific File Names and File Types using Copy-Item
You would think intuitively that we could use the
-Include
and
-Exclude
parameters to filter which file names and file types we want to recursively copy like so:
$filesToInclude = "*.log","*.zip"
Copy-Item -Path "C:\alkanesource\*" -Destination "C:\alkanedestination" -Recurse -Include $filesToInclude
But you’d be wrong. Because the
-Include
and
-Exclude
parameters don’t support recursion. So we have to go about it a different way by iterating through files manually:
$filesToInclude = "*.log","*.ps1"
$sourceFolder = "C:\alkanesource\"
$destinationFolder = "C:\alkanedestination\"
#loop through each file in source folder
Get-ChildItem -Path $sourceFolder -File -Recurse -Include $filesToInclude |
Foreach {
#replace source folder with target folder
New-Object PSObject -Prop @{
Source = $_.Fullname
Destination = $_.Fullname.Replace($sourceFolder,$destinationFolder)
}
} |
Foreach {
#create target folder if it doesnt exist since copy-item requires it
New-Item -ItemType File -Path $_.Destination -Force | Out-Null
#overwrite with actual file
Copy-Item -Path $_.Source -Destination $_.Destination -Force
}
Result
C:\alkanedestination
│ file1.txt
│ file2.log
│ file3.zip
└───alkanesubfolder
│ file4.ps1