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

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


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.


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 $Filterforeach ($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".