inter
inter

Reputation: 179

How to merge / 'flatten' a folder structure using PowerShell - recursive

I'm looking for help restructuring a large number of files within many subfolders.

Example source:

folderX
   aaa.txt
   bbb.txt
folderY
   ccc.txt
   folderZ
      ddd.txt
eee.txt

Ideal result:

folderX_aaa.txt
folderX_aaa.txt
folderX_bbb.txt
folderY_ccc.txt
folderY_folderZ_ddd.txt
eee.txt

I hope that makes sense! I'm using Plex to manage some media and it doesn't like subfolders for certain uses (eg featurettes directory).

I'd like to use PowerShell because I'm already kinda familiar with it - but any techniques or suggestions are welcome.

Thanks in advance :)

Upvotes: 6

Views: 5160

Answers (2)

mklement0
mklement0

Reputation: 438763

Here's a single-pipeline solution:

$targetDir = Convert-Path '.' # Get the current (target) directory's full path.

Get-ChildItem -LiteralPath $targetDir -Directory | # Loop over child dirs.
Get-ChildItem -Recurse -File -Filter *.txt | # Loop over all *.txt files in subtrees of child dirs.
Move-Item -Destination { # Move to target dir.
  # Construct the full target path from the target dir.
  # and the relative sub-path with path separators replaced with "_" chars.
  Join-Path $targetDir `
            ($_.Fullname.Substring($targetDir.Length + 1) -replace '[/\\]', '_') 
} -Whatif

-WhatIf previews the move operations; remove it to perform actual moving.
Regex [/\\] matches / or \ as the path separator, so as to make the solution cross-platform.

Upvotes: 9

Lee_Dailey
Lee_Dailey

Reputation: 7479

while it would have been nice if you had shown what you have tried, i got interested ... [grin]

what the code does ...

  • sets some constants
  • creates some files & dirs to work with
  • grabs the files that match the target location & type
  • skips any file that is already in the $TopDir
  • derives the old file & dir names
  • uses the above to make a new full file name
  • moves the items
    this only shows what WOULD happen. remove the -WhatIf to do it for real.

please note that the code DOES NOT check to see if there are same-named files in the destination.

the code itself ...

$TopDir = "$env:TEMP\PlexStuff"
$Delimiter = '_-_'
$Filter = '*.txt'

#region >>> create some files to test with
#   remove this region after you have tested it
@(
    [System.IO.FileInfo]"$TopDir\OneThing\aaa.txt"
    [System.IO.FileInfo]"$TopDir\OneThing\bbb.txt"
    [System.IO.FileInfo]"$TopDir\TwoThing\aaa.txt"
    [System.IO.FileInfo]"$TopDir\ThreeThing\ccc.txt"
    [System.IO.FileInfo]"$TopDir\ThreeThing\ddd.txt"
    [System.IO.FileInfo]"$TopDir\eee.txt"
    ) |
    ForEach-Object {
        # the "$Null =" suppresses unwanted output from the commands
        $Null = mkdir $_.Directory.FullName -Force -ErrorAction SilentlyContinue
        $Null = New-Item -Path $_.Directory.FullName -Name $_.Name -ItemType File -ErrorAction SilentlyContinue
        }
#endregion >>> create some files to test with


$FileList = Get-ChildItem -LiteralPath $TopDir -File -Recurse -Filter $Filter
foreach ($FL_Item in $FileList)
    {
    # skip files that are in the TopDir
    if (-not ($FL_Item.DirectoryName -eq $TopDir))
        {
        $OldFileName = $FL_Item.Name
        $OldDirName = $FL_Item.DirectoryName
        $NewFileName = ($OldDirName, $OldFileName) -join $Delimiter

        Move-Item -LiteralPath $FL_Item.FullName -Destination $NewFileName -WhatIf
        }
    }

output [slightly reformatted for readability] ...

What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\OneThing\aaa.txt 
    Destination: C:\Temp\PlexStuff\OneThing_-_aaa.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\OneThing\bbb.txt 
    Destination: C:\Temp\PlexStuff\OneThing_-_bbb.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\ThreeThing\ccc.txt 
    Destination: C:\Temp\PlexStuff\ThreeThing_-_ccc.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\ThreeThing\ddd.txt 
    Destination: C:\Temp\PlexStuff\ThreeThing_-_ddd.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\TwoThing\aaa.txt 
    Destination: C:\Temp\PlexStuff\TwoThing_-_aaa.txt".

Upvotes: 1

Related Questions