Search code examples
powershellcopy-item

Powershell Copy-To - If Destination Directory exists, copies into Existing Directory


Right I have a simple Copy-Item script to copy files from one destination folder to another.

releasecode.ps1

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]
    [string]$source, 
    [Parameter(Mandatory=$true)]
    [string]$destination
) 
Process {
    Copy-Item -Path $source -Destination $destination -Recurse -Force

I'm running releasecode.ps1 using the following command line:

.\releasecode.ps1 -source "C:\test\from" -destination "C:\test\to"

The from folder has the following structure:

.
├── from
├── stain.txt
├── test1.txt
├── folder
|   ├── test2.bmp

This correctly copies to (On the first copy):

.
├── to
├── stain.txt
├── test1.txt
├── folder
|   ├── test2.bmpthe 

If I re-ran it straight afterwards, the from folder is created as a directory within `to' instead of just overwriting the existing structure:

.
├── to
├── stain.txt
├── test1.txt
├── folder
|   ├── test2.bmp
├── from
|   ├── stain.txt
|   ├── test1.txt
|   └── folder
|       ├── test2.bmp

How do I just overwrite the existing to directory structure if the files and folders exist currently.

More Information

  • Running this on a Windows Box

  • $PSVersionTable:

enter image description here


Solution

  • You've run into a Copy-Item gotcha related to copying source directories.

    If the destination exists and is a folder the cmdlet copies the source to the destination.

    Copy-Item C:\src\a C:\dst\b -Recurse
    
    C:\                 C:\
    ├─dst               ├─dst
    | └─b               | └─b
    └─src               |   └─a
      └─a           ⇒   |     ├─bar.txt
        ├─bar.txt       |     └─baz.txt
        └─baz.txt       └─src
                          └─a
                            ├─bar.txt
                            └─baz.txt
    

    If the destination does not exist the cmdlet copies the source as the destination.

    Copy-Item C:\src\a C:\dst\b -Recurse
    
    C:\                 C:\
    ├─dst               ├─dst
    └─src               | └─b
      └─a               |   ├─bar.txt
        ├─bar.txt   ⇒   |   └─baz.txt
        └─baz.txt       └─src
                          └─a
                            ├─bar.txt
                            └─baz.txt
    

    The customary way of handling this in PowerShell is to ensure that the destination folder exists first, then copy the content of the source folder:

    if (-not (Test-Path $destination)) {
        New-Item -Type Directory -Path $destination | Out-Null
    }
    Copy-Item -Path $source\* -Destination $destination -Recurse -Force
    

    Alternatively you can use robocopy, which does not have this issue:

    robocopy C:\src\a C:\dst\b /s