Use PowerShell Copy-Item to Copy a File or Folder Including Mirror Copy

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
Markup

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"
PowerShell

Result

C:\alkanedestination
│   file1.txt
Markup

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"
PowerShell

Result

C:\alkanedestination
│   file1.txt
│   file2.log
Markup

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
PowerShell

Result

C:\alkanedestination
│   file2.log
│   file3.zip
Markup

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
PowerShell

Result

C:\alkanedestination
│   file2.log
Markup

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"
PowerShell

Result

C:\alkanedestination
│   file1.txt
│   file2.log
│   file3.zip
Markup

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
PowerShell

Result

C:\alkanedestination
│   file1.txt
│   file2.log
│   file3.zip
└───alkanesubfolder 
   │   file4.ps1
Markup

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
Markup

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
PowerShell

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
}
PowerShell

Result

C:\alkanedestination
│   file1.txt
│   file2.log
│   file3.zip
└───alkanesubfolder 
   │   file4.ps1
Markup