ROBOCOPY - Copy folders content to a single folder

You could do that with a PowerShell one liner. In this example I filter out all the files with the .txt extension from all the subfolders. And then send them to the Copy-Item Cmdlet.

Combine the Cmdlets Get-Childitem (GCI for short), -recurse, and -filter and then pipe the result to the Copy-Item Cmdlet. Use -WhatIf first to check that the output is what you expected.

Copy to another folder (Use -WhatIf and verify the output to check your command before committing to copying the files):

Get-Childitem -recurse R:\Contracts -filter *.txt | Copy-Item -Destination R:\Contracts\Sites -WhatIf

To do multiple filetypes as you've asked, you can just run multiple commands, one for each filetype.


I recently had to tackle this problem, and many files that I wanted to move to from the hierarchy to a single folder had the same name as each other, and I wanted to still flatten the hierarchy without them to being over-written. What I did was write a script that moves the file, but renames it with the old hierarchy path in the name for example: source files:

C:\files\somefiles\file.txt

C:\files\otherfiles\file.txt

destination is C:\newdir\ files are created as

C:\newdir\somefiles-file.txt

C:\newdir\otherfiles-file.txt

here is the code, batch file 1 goes thru the files, batch file 2 renames and moves them (could also copy instead, if you want to preserve the source:

@echo off
for /r %%f in (*.*pr) do @renameandmovefilespart2.bat "%%f" "%%~ff" "%%~xf"

renameandmovefilespart2.bat

@echo off
Setlocal EnableDelayedExpansion
rem set the whole file path
set origWhole=%1
set origPathOnly=%2
set extension=%3
rem here you can set where the directory to hold the flattened hierarchy is
set destDir=c:\destinationDir\
rem  set the directory to do a string replace
rem make this the starting directory, that you dont want in the newly renamed files
set startingDir=C:\starting\directory\
set nothing=
set slash=\
rem here you can set what the character to represent the directory indicator \ in the new files 
set reaplcementDirectoryCharacter=--
set quote="
rem cut out the starting part of the directory
call set newname=%%origWhole:!startingDir!=!nothing!%%
rem replace slashes with new character
call set newname=%%newname:!slash!=!reaplcementDirectoryCharacter!%%
rem remove quotes
call set newname=%%newname:!quote!=!nothing!%%
rem @echo shortened: %newname%
rem @echo source path: %origPathOnly% newPath: %startingDir%
rem @echo extension: %extension%
rem rename the files
ren %origWhole% %newname%
rem prepare to move the file, clean up the source path
call set origPathOnly=%%origPathOnly:!quote!=!nothing!%%
move "%origPathOnly%%newname%" "%destDir%"

Similar to the previous Powershell option, I did the following to flatten a multi-subdirectory music folder:

#Get all files and not the directories
$files = Get-ChildItem -Path R:\Contracts -Recurse | Where {$_.PSIsContainer -eq $false}

#Copy items from sources to new destination
foreach ($file in $files){
    Copy-Item -Path $file.FullName -Destination R:\Contracts\Sites\$($file.Name)
}

The Get-ChildItem with the -Recurse switch will get a listing of all sub-folders and files. The Where function is stripping out any directories by checking the boolean PSIsContainer property. Without stripping the directories the sub-folder structure would be created without files in them. This listing is stored in the $files variable.

The foreach function runs through the list of files in the $files variable and stores one item at a time in the $file variable. The Copy-Item function then uses the full path from $file.FullName and then copies the file to the destination with the same name from $file.Name.


No single command will flatten the hierarchy for you; you will have to use multiple commands. It can be done simply by using FOR /R to walk the hierarchy, coupled with your copy/move command of choice (move, copy, xcopy, robocopy). Because your destination is within the source hierarchy, you need an IF to prevent the destination from being a source.

Before proceeding you should stop and think about what happens if the same file name appears in multiple source folders. You can only have one version in your destination folder. Can you guarantee no duplicate names exist? If not, which file should be kept? How can you structure the command to keep the file you want? This complication is probably why no command was ever written to simply flatten a hierarchy.

Here is your ROBOCOPY command integrated with the FOR /R solution.

@echo off
set source="R:\Contracts"
set destination="R:\Contracts\Sites"

::Not sure if this is needed
::It guarantees you have a canonical path (standard form)
for %%F in (%destination%) do set destination="%%~fF"

for /r %source% %%F in (.) do if "%%~fF" neq %destination% ROBOCOPY "%%F" %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0