3

I have a set of projects that involve a mix of project-specific files plus common files. I'm trying to copy contents from two different folders -- a project-specific folder, and a common folder -- into a single folder named for the project. I also want to retain any folder hierarchies from the original folders.

For example, some paths to the common files:

src\Common\PackageAssets\logo1.jpg
src\Common\PackageAssets\logo2.jpg

And example paths to project-specific files:

src\Projects\ProjectA\PackageFiles\readme.txt
src\Projects\ProjectA\PackageFiles\scale-100\projA.png

The desired result after copying would be:

bld\ProjectA\pkgFiles\logo1.png
bld\ProjectA\pkgFiles\logo2.png
bld\ProjectA\pkgFiles\readme.txt
bld\ProjectA\pkgFiles\scale-100\projA.png

What I'm using is this:

[string]$pkgContentPath = "bld\$project\pkgFiles"

# copy common files
Copy-Item -Path .\src\Common\PackageAssets -Recurse -Destination $pkgContentPath
# copy project-specific files
Copy-Item -Path .\src\Projects\ProjectA\PackageFiles\ -Recurse -Destination $pkgContentPath

But instead of the expected results, all the files are ending up in an extra level of subfolder:

bld\ProjectA\pkgFiles\PackageAssets\logo1.png
bld\ProjectA\pkgFiles\PackageAssets\logo2.png
bld\ProjectA\pkgFiles\PackageFiles\readme.txt
bld\ProjectA\pkgFiles\PackageFiles\scale-100\projA.png

I'm stumped. I can't figure out how to get rid of the extra subfolder layer. I tried using Get-ChildItem piping to Copy-Item, but then the subfolder hierarchies were lost.

In a .bat file, this works:

xcopy src\Common\PackageAssets\* bld\%project\pkg_contents /s
xcopy src\Projects\%project\PackageFiles bld\%project\pkg_contents /s

I guess I could use xcopy, but surely there must be a way to do this using cmdlets.

Peter Constable
  • 2,707
  • 10
  • 23
  • 1
    `New-Item bld\ProjectA\pkgFiles -Type Directory; Copy-Item -Path .\src\Common\PackageFile\* bld\ProjectA\pkgFiles -Recurse; Copy-Item -Path .\src\Projects\ProjectA\PackageFiles\* bld\ProjectA\pkgFiles -Recurse` – user4003407 Dec 24 '17 at 22:47
  • What else is odd is that results are different when I'm running commands in the console versus from a script. – Peter Constable Dec 24 '17 at 23:08

1 Answers1

2

The behavior you describe is a known problem as of Windows PowerShell v5.1 / PowerShell Core v6.2.0-preview.2, unfortunately:

In short, the behavior of Copy-Item regrettably depends on whether the target directory happens to exist already or not:

If the target dir. exists, it is not the source directory's content that is copied, but the source dir. as a whole, to a subdirectory of the target directory named for the source dir.


The workaround is already mostly spelled out in PetSerAl's helpful comment on the question:

  • Before copying, make sure that the target directory exists.

  • Append \* to the source path to explicitly target the contents of the source dir.

    • Also specify -Force, so as to ensure that hidden files and directories are also copied.
$pkgContentPath = "bld\$project\pkg_contents"

# Make sure the target dir. exists.
# (-Force leaves an existing dir alone and otherwise creates it.)
New-Item -Force -Type Directory $pkgContentPath

# IF desired, clear out the pre-existing directory content.
# !! Beware of Remove-Item's intermittent failures - see below.
#  Remove-Item -Force $pkgContentPath\* -Recurse.

# Copy with \* appended to the source paths and -Force added:
#
# copy common files
Copy-Item -Recurse -Force -Path .\src\Common\PackageAssets\* $pkgContentPath
# copy project-specific files
Copy-Item -Recurse -Force -Path .\src\Projects\ProjectA\PackageFiles\* $pkgContentPath

A note re use of Remove-Item -Recurse to clear out preexisting destination-directory content, if needed: Regrettably, Remove-Item can fail on occasion and you cannot predict when that happens - see this answer for a robust alternative.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    In my case, I already had the target folder created, and was still having problems. However, I didn't have \* appended, and that did make the difference. – Peter Constable Dec 26 '17 at 22:17