Flatten Files in Subfolders on Windows 7 (Cmd or Powershell)

I have a large volume of files organized in a very hierarchical folder structure. In this structure, the file that I care about is always located in the lowest level of the folders. As such, I'd like to flatten the directory so that it's easier to access the files that I care about. However, I'd like to preserve the 2 higher levels (Person & Project) of the folder structure.

Here's an example of the EXISTING folder directory:

  • Directory
    • Tom
      • Project 1
        • Subfolder Level A
          • FileA
        • FileB
      • Project 2
        • Subfolder Level C
          • FileC
        • FileD
    • Jerry
      • Project 1
        • Subfolder Level E
          • FileE

Here's an example of the DESIRED folder directory:

  • Directory
    • Tom
      • Project 1
        • FileA
        • FileB
      • Project 2
        • FileC
        • FileD
    • Jerry
      • Project 1
        • FileE

I have tried doing something like this, however this flattens all of the files into a single directory:

for /r %f in (*) do @copy "%f" .

However, this produces:

  • Directory
    • FileA
    • FileB
    • FileC
    • FileD
    • FileE

I'd appreciate any guidance that you can offer. Thanks a lot!

4 Answers

Here is a Powershell approach. It gets a list of the folders at the level that you want. Then it moves all the sub files up to that level. it will also remove the sub folders.

$Rootfolder = Dir directory\*\* -Directory 

ForEach($folder in $Rootfolder)
{
    Dir $folder.fullname -Recurse -File | Copy-Item -Destination $folder.fullname
    Dir $folder.fullname -Recurse -Directory | Remove-Item -Force -Recurse -WhatIf
}

If you want it to delete, remove the -WhatIf from the last line.

Throw a couple of extra for loops around the one that works then.

e.g. First change to the name folder, then the project folder, looping through both levels.

for /D %n in (*) do (
    pushd %n
    for /D %p in (*) do (
        pushd %p
        for /r %f in (*) do @copy "%f" .
        popd
    )
    popd
)

If you put this in a bat file, remember to replace % with %%

7
@echo off
pushd yourDirectory
for /d %%A in (*) do for /d %%B in ("%%A\*") do for /d %%C in ("%%B\*") do (
  pushd "%%C"
  for /r %%F in (*) do move /y "%%F" "%%B" >nul
  popd
  rd /q /s "%%C"
)
popd

%%A contains something like "yourDirectory\Tom"
%%B contains something like "yourDirectory\Tom\Project 1"
%%C contains something like "yourDirectory\Tom\Project 1\subdirectory1" %%F contains a file to move, to any depth

At first I thought I could eliminate PUSHD/POPD and use

for /r "%%C" %%F in (*) do ...  THIS DOES NOT WORK

But that doesn't work - the value after /R cannot use a FOR variable or delayed expansion because of how the command is parsed.

I tweaked @ScottC's answer and used the following code:

for /D %%n in (*) do (
    pushd %%n
    for /D %%p in (*) do (
        pushd %%p
        for /r %%f in (*.ppt) do (
            move "%%f" "[ROOT_PATH_THAT_I_WANT]\%%n\%%p".
        )
        popd
    )
    popd
)

I ran this solution as a .bat file, which is why I used %% instead of %.

%%n = name (aka C:\Directory\Name)
%%p = project (aka C:\Directory\Name\Project)
%%f = file to be moved (recursively drilling through the folders and moving them up to the project level)

Ultimately, I wasn't able to get @dbenham's suggestion of deleting the empty folders to work, so I ended up using this utility: . So far it seems pretty intuitive and like it's taking care of the problem without much effort from me :)

Thanks for the help everybody!

Your Answer

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

Maya Lin-Takahashi

Maya Lin-Takahashi

Consumer Tech & Gadget Reviewer

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.

Share this article
Twitter Facebook Pinterest