1

I have a very large directory located at D:\Stuff and I want to create a copy of it at D:\CopyStuff, but I only want to take files with a certain extension as well as keep the folder structure.

Getting the files I want seems simple enough:

$from = "D:\stuff"
$to = "D:\CopyStuff"   
$files = Get-ChildItem -Recurse -Path $from -Include *.config, *.txt, *.ini 

However, copying the files and keeping the structure is a bit more challenging. I could use a for-loop, but that seems against the very nature of Powershell. Here https://stackoverflow.com/a/25780745/782880, it suggests to do it this way:

Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Container

But that copies files to D:\CopyStuff with no folders, much less my original structure. What am I doing wrong? I'm using Powershell 5.

1
  • while robocopy is FAR better at both copying AND moving files, the info you linked to has another link that says you need to use both -Recurse and -Container:$False to copy the Source dirtree to the Dest dirtree and preserve relative paths. ///// i have not tested it - i usually use robocopy - but the following post seems quite specific ... What is the meaning of Powershell's Copy-Item's -container argument? - Stack Overflow — stackoverflow.com/questions/129088/… ///// look at the highest voted answer. [grin] Commented Jan 5, 2019 at 2:27

3 Answers 3

2

try this :

$Source="C:\temp\test1"
$Dest="C:\temp\test2"
$EnableExt=".config", ".txt" , ".ini"

Get-ChildItem $Source -Recurse | % {

    $NewPath=$_.FullName.Replace($Source, $Dest)

    if ($_.psiscontainer)
    {
        New-Item -Path $NewPath -ItemType Directory -Force
    }
    elseif ($_.Extension -in $EnableExt)
    {
        Copy-Item $_.FullName $NewPath -Force
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

First of all, Copy-Item can do it on its own like:

$fromFolder = "C:\Temp\Source"
$toFolder = "C:\Temp\Dest"
Copy-Item -Path $fromFolder -Destination $toFolder -Recurse -Filter *.txt

But, you may not like the result: it will make folder "Source" inside the "Dest" folder, and then copy the structure. I reckon, you need the same files/folders from inside "Source" folder to be copy to the "Dest" folder. Well, it's a bit more complex, but here it is:

$fromFolder = "C:\Temp\Source"
$toFolder = "C:\Temp\Dest"

Get-ChildItem -Path $fromFolder -Directory -Recurse | Select-Object FullName, @{N="NewPath";E={$_.FullName.Replace($fromFolder, $toFolder)}} | ForEach-Object { New-Item -Path $_.NewPath -ItemType "Directory" }
Get-ChildItem -Path $fromFolder -Include "*.txt" -Recurse | Select-Object FullName, @{N="NewPath";E={$_.FullName.Replace($fromFolder, $toFolder)}} | ForEach-Object { Copy-Item -Path $_.FullName -Destination $_.NewPath }

It copies folder structure first, then files.

NB! I do strongly recommend to use absolute paths only. Otherwise, the Replace method may give unexpected results.

Comments

0

Note: The solution below creates analogous target folders only for those source folders that contain files matching the -Include filter, not for all source folders.


You can get away with a single-pipeline solution by combining Get-ChildItem -Name with delay-bind script blocks:

$from = 'D:\stuff'
$to = 'D:\CopyStuff'

Get-ChildItem -Name -Recurse -LiteralPath $from -Include *.config, *.txt, *.ini |
  Copy-Item `
    -LiteralPath { Join-Path $from $_ } `
    -Destination { New-Item -Type Directory -Force (Split-Path (Join-Path $to $_)) }
  • -Name emits paths relative to the input directory as strings.

  • Delay-bind script block { Join-Path $from $_ } builds the full input file name from each relative input path.

  • Delay-bind script block { New-Item -Type Directory -Force (Split-Path (Join-Path $to $_)) } builds the full path of the target directory from the target root path and the relative input path and creates that directory on demand, using a preexisting one if present (-Force).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.