简体   繁体   中英

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 :)

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".

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM