Copy folders without files, files without folders, or everything using PowerShell

52,006

Solution 1

To copy everything in a folder hierarchie

Copy-Item $source $dest -Recurse -Force

To copy the hierarchie you can try:

$source = "C:\ProdData"
$dest = "C:\TestData"
Copy-Item $source $dest -Filter {PSIsContainer} -Recurse -Force

To flatten a file structure you can try:

$source = "C:\ProdData"
$dest = "C:\TestData"
New-Item $dest -type directory
Get-ChildItem $source -Recurse | `
    Where-Object { $_.PSIsContainer -eq $False } | `
    ForEach-Object {Copy-Item -Path $_.Fullname -Destination $dest -Force} 

Good luck!

Solution 2

Here are some ideas for handling each situation you describe.

Folder Structure Only

This will copy the source to a destination, recursing subdirectories but excluding all files.

robocopy $source $dest /e /xf *.*

Files Only (Flatten Structure)

There are a few ways to handle this, but I don't know of an especially good or elegant way. Here's an awkward but effective approach - for each subdirectory, it runs a non-recursive copy to a root destination folder. Criticism or nicer alternatives would be most welcome.

Get-ChildItem $source -Recurse |
  Where-Object { $_.PSIsContainer -eq $true } |
  Foreach-Object { robocopy $_.FullName $dest }

Everything

This scenario is the most straightforward of the bunch.

robocopy $source $dest /e

You can experiment with the switches yourself (referencing robocopy /? along the way) to fine tune the process. The trickiest scenario in my opinion is the one that flattens the directory structure. You'll have some decisions to make, like how you want to handle the same file name appearing in multiple directories.

As for how to accept options from the command line, I'd suggest putting together Powershell parameter sets for your three situations. There are a number of blog posts around that discuss the concept, but you can also see TechNet or run help about_Functions_Advanced_Parameters inside Powershell.

Solution 3

I propose my solution :

$source = "C:\temp\"
$dest = "C:\TestData\"

#create destination directory if dont exist
New-Item -ItemType Directory $dest -Force


#To copy everything in a folder hierarchie
Get-ChildItem $source -Recurse | Copy-Item -Destination {$_.FullName.Replace($source, $dest)}  -Force

#To copy only directory hierarchie:
Get-ChildItem $source -Recurse -directory | Copy-Item -Destination {$_.FullName.Replace($source, $dest)}  -Force

#To copy only file (remove doublon be carefull):
Get-ChildItem $source -Recurse -file | Copy-Item -Destination $dest -Force

Solution 4

The following copies just the folder structure form ProdData to TestData without any files

$from = "C:\ProdData"
$to = "C:\TestData"

Get-ChildItem -Path $from -Recurse | 
?{ $_.PSIsContainer } | 
Copy-Item -Destination {Join-Path $to $_.Parent.FullName.Substring($from.length)} -Force 

Share:
52,006

Related videos on Youtube

steve_o
Author by

steve_o

Updated on June 13, 2020

Comments

  • steve_o
    steve_o almost 4 years

    I would like to be able to write a PowerShell script that would take a folder (or set of folders) and to duplicate them in which the folder structure (without the files) could be created, where the file structure (without the folders) could be created, or in which both the files (all or selected ones) AND folders could be created.

        Example:
    
        C:\ProdData has 3 subfolders in it
        C:\ProdData\Fld1
        C:\ProdData\Fld2
        C:\ProdData\Fld3 - has 2 subfolders under it
        C:\ProdData\Fld3\MyFolder1
        C:\ProdData\Fld3\MyFolder2
    

    Each folder above has a various number of files of various sizes in it, of various file extensions.

    I would like to have a PowerShell script that would duplicate that folder structure elsewhere, giving me a choice of Folder Structure Only, Files Only, or Files AND Folders to be copied.

    In the above, I'd like to be able to copy C:\ProdData to another folder, essentially renaming ProdData to TestData (that is, C:\ProdData copied to C:\TestData), or to copy the entire folder structure.

    C:\ProdData into another folder that is a subfolder of something else: C:\TestArea\TestFolders\2012-04-01\TestData\ProdData\Fld1, etc...

    And selectively choose to include folders, files or both.

    The ideal solution would be to (for folders only) take the folder structure, export/save it, read it in, and create that same structure elsewhere. Some solutions I've found said they copied the folder structure only, but if data exists, that gets copied also and you can't exclude one or the other. I have a partial solution to the files-only requirement that semi-preserves the path, but it would take a file:

    c:\ProdData\Fld1\MyFile.dat
    

    and copy it to:

    c:\TestData\yyyyMMdd_hhmmss_ProdData_Fld1_MyFile.dat
    

    But that's not something that could easily be decoded and would be impossible to re-integrate the source structure. I'd appreciate any thoughts about how to accomplish this without re-inventing the wheel.

  • steve_o
    steve_o about 12 years
    Thanks for the suggestion. I did not have Robocopy even installed, and it suits the needs fairly well. What I ended up doing for the structure to a file was to pipe Show-Tree to a text file. That accomplished another piece of what I was after. No one thing would do it all, but 3 relatively straightforward pieces together accomplished what I needed. Thank you for your help!
  • Brandon
    Brandon almost 11 years
    For the flatten one, you can skip the middle section and just use the -File option on Get-ChildItem like (and Copy-Item instead of robocopy): Get-ChildItem $source -Recurse -File | Foreach-Object { Copy-Item $_.FullName $dest }. Not a huge difference though.
  • ajk
    ajk almost 11 years
    @Brandon Good point. As long as you're on Powershell 3 you can certainly do that (the -File and -Directory parameters didn't exist until v3).
  • JabberwockyDecompiler
    JabberwockyDecompiler about 5 years
    I found this very helpful to filter out specific files for a copy. All that was needed was to add a variable inside the foreach $filename = $_.Name with an if check if ($filename.endswith("dll") and I could pull out the dlls for a dev environment debug session. Note you will probably want to filter out the system dlls :).
  • Bob Lokerse
    Bob Lokerse almost 5 years
    Vote up for the copy file only. I could not get that working with the other examples.
  • Honza S.
    Honza S. over 2 years
    -file flag is exactly what I was looking for