Reputation: 179
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
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
Reputation: 7479
while it would have been nice if you had shown what you have tried, i got interested ... [grin]
what the code does ...
-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