1

So, I have a folder structure with some downloads that goes like this (I manually edited it a bit because it contains some sensitive data, which is not relevant to the question. The extensions are also not common, nor relevant):

C:.
│   [FILENAME].[ext]
│   
├───Example 1
│   └───Example 1
│       └───Example 1
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   
│           └───Folder.[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   [FILENAME].[ext]
│               │   
│               ├───test1
│               │       [FILENAME].[ext]
│               │       [FILENAME].[ext]
│               │       
│               ├───test10
│               │       [FILENAME].[ext]
│               │       [FILENAME].[ext]
│               │       
│               ├───test11
│               │       [FILENAME].[ext]
│               │       [FILENAME].[ext]
│               │       
│               ├───test12
│               │       [FILENAME].[ext]
│               │       [FILENAME].[ext]
│               │       
│               ├───test2
│                       [FILENAME].[ext]
│                       [FILENAME].[ext]
│                       
│                       
├───Example 2
│   └───Example 2
│       └───Example 2
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   
│           ├───Folder.[ext]
│           │       [FILENAME].[ext]
│           │       [FILENAME].[ext]
│           │       [FILENAME].[ext]
│           │       [FILENAME].[ext]
│           │       
│           └───Setup
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   
├───Example 3
│   └───Example 3
│       └───Example 3
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   
│           └───Folder.[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   
├───Example 4
│   └───Example 4
│       └───Example 4
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   [FILENAME].[ext]
│           │   
│           └───Folder.[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]
│                   [FILENAME].[ext]

                             .
                             .
                             .

As you can see, there are a lot of unnecessary folders in-between before the actual files.

Is it possible to use batch to programmatically remove the "intermediate folders"? Basically, I want to remove any folders that contain only folders and bring the sub-contents up one level. How would it be done (preferably with only built-in Windows tools)?

On this small excerpt, simply removing the first two parent "Example #" folders would solve for all, but the nesting depth occasionally varies up or down. If a folder contains only a single folder, it's a "middle man" that I want to remove, if there are actual files (or more than one folder, which means it's actual organization), than it should remain there.

Thank you!

EDIT: I'm trying to achieve something like this, removing the triplicated (but sometimes other depths) nesting:

C:.
├───Example 1
│    │   [FILENAME].[ext]
│    │   [FILENAME].[ext]
       .
       .
       .
  • To be clear, specify in the post exactly the final folder structure that you want. What have you already researched or tried? – harrymc Jun 28 at 21:00
  • Why not to use tree /f for illustrate your folder tree, and, size is not useful information on this task – It Wasn't Me Jun 28 at 22:48
  • @ItWasn'tMe OMG, I just have been searching for a command like this for hours, thank you, I'll soon improve my question. I'm a bit worried about sensitive file names, so right now I'm reworking a sample from the full tree /f output. – Fabio Freitas Jun 29 at 0:56
  • Are the nested foldernames actually identical? That makes things trickier... – Keith Miller Jun 30 at 0:13
  • Yes, they are. I used a single RegEx per Example # to produce the excerpt above... – Fabio Freitas Jun 30 at 0:19
2

In PowerShell, a simple recursive function could find the first subfolder that contains files. The content of that folder can then be moved to its top-level container. afer that, empty folders can be deleted. Just edit $Top to reflect the path to your folder:

$Top = 'c:\TopFolder'
Function Get-NonEmptyPath ($FPath) {
   If ( -not (gci -LiteralPath $FPath -file) ) {
      $Return = Get-NonEmptyPath ( gci -LiteralPath $FPath -Directory  ).FullName
   } Else { $Return = $FPath }
   $Return
}

Filter Get-LiteralPath { $_ | Select  @{ N='LiteralPath'; E={ $_.FullName }}}

( Get-ChildItem $Top -Directory ).FullName  | ForEach{
   If (( $Buried = Get-NonEmptyPath $_ ) -ne $null ) {
      gci -LiteralPath $Buried | Get-LiteralPath | Move-Item -Destination $_
      For ( $Empty = $Buried ; $Empty -ne $_ ; ( $Empty = Split-Path -LiteralPath $Empty )) {
         Remove-Item -LiteralPath $Empty
      }
   }
}

After editing $Top, the entire block can be copied & psted into a PowerShell console window.

gci/Get-ChildItem

ForEach

About For

Move-Item

Split-Path

Remove-Item

| improve this answer | |
  • Can this be run from anywhere or do I have to change my working directory? – Fabio Freitas Jun 30 at 3:05
  • 1
    It prints a lot of errors, but it does work, thank you! – Fabio Freitas Jun 30 at 3:25
  • 1
    Fully modified to deal with special characters. – Keith Miller Jun 30 at 5:19
  • 1
    Even an error messge is a foreogn languge would give me a clue as to which cmdlet is throwing an error --- which is more that "doesn't work" does! – Keith Miller Jul 2 at 17:57
  • 1
    I see no reason to do so. I'm curious about the behavior of -notLIke, but posted in MS TechNet forums for clarification. – Keith Miller Jul 2 at 18:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.