Reputation: 17
I've just started dabbling with Powershell & after searching many scripts, I have not found one that works. (Maybe I'm not running correctly, but I have enabled the right administrative rights, etc.)
My request:
A Powershell script which
- recursively goes through directory structure, to the last level
- moves all content (files with any extension), UP one-level, from where the files were
- after the move, removes that folder the files were moved from
◘ BEFORE ◘ Classical ├─Mozart-5 │ └─Mozart-European-Composers │ ├─01-symphony.mp3 │ └─03-symphony.mp3 │ ├─Bach-7 │ └─Bach │ ├─02-symphony.ogg │ └─04-concerto.wav │ │ └─Vivaldi-2 └─Vivaldi-Not-The-Browser ├─01-track.m4a └─02-solo.mp4 ================================================= ◘ AFTER ◘ Classical ├─Mozart-5 │ ├─01-symphony.mp3 │ └─03-symphony.mp3 │ ├─Bach-7 │ ├─02-symphony.ogg │ └─04-concerto.wav │ └─Vivaldi-2 ├─01-track.m4a └─02-solo.mp4
Notes:
- Base-folder could be called any folder, e.g. Classical, Rock, etc.
(so, ideally, I would run the Powershell script from inside the base-folder, where all the sub-folders are)
- Folder depth could be 1 or many levels deep
( 99.9% of the time, it will be 2-3 levels deep, i.e.
Root - Music
1st - _Classical_
2nd - Mozart-5
3rd - Mozart-European-Composers
1st - _Indian Classical_
2nd - Ravi
3rd - Ravi Masterpieces
2nd - Zakir
3rd - Zakir-Solo-Piece
)
Upvotes: 2
Views: 1597
Reputation: 3158
Ok this had me going for a while but I finally figured it out. It required a Recursive Function (a function that calls itself). This method doesn't care how deep your tree is so it will handle that .1% of cases that go more than 3 levels deep.
Clear-Host
Function Check-Dir {
Param (
[Parameter(Mandatory=$True)]
[String] $Path
)
$GCIArgs = @{Path = "$Path"}
$Files = Get-ChildItem @GCIArgs |
Where-Object {-not $_.PSIsContainer}
#--- If no Subs returns $Null! ---
$Subs = Get-childitem @GCIArgs |
Where-Object {$_.PSIsContainer}
If ($Null -ne $Subs) {
ForEach ($S in $Subs) {
$Bottom = $False
$DelDir = Check-Dir -Path "$($S.FullName)"
If ($DelDir) {
$S | Remove-Item -Force
}
}
}
Else {
$MIArgs = @{Destination = "$("$Path" + "\..")"
Force = $True}
$Files | Move-Item @MIArgs
$Bottom = $True
}
If ($Bottom) {$True}
Else {$False}
} #End Function Check-Dir
#-------------- Main Program -----------------
$BaseDir = "G:\Test\Music"
Check-dir -path "$BaseDir"
HTH
Upvotes: 1
Reputation: 17
I was able to mix'n'match up a solution, which works for me, ie.
A 2-step process:
1) Move all files 1-level up, to its parent
2) Since the source folder is now empty, because the files were moved 1-level up, so next task is to recursively remove all of the empty folders
With this in mind:
Get-ChildItem '*\*\*' | Move-Item -Destination { $_.Directory.Parent.FullName }
Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
@(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -recurse
Notes:
○ I should have also mentioned that my folder names contained "[" and "]", and this becomes challenging for Powershell, because Get-ChildItem
won't work.
See here: Option -recurse sometimes does not work for PowerShell cmdlet get-childitem
○ Also, because of "[" and "]" in myfolder names, removing these folders also require some 'trickery'.
At first, I settled on this solution
- How to recursively remove all empty folders in PowerShell?
However, this is the one that worked well:
How to delete empty subfolders with PowerShell?
(Inspired by: PowerShell script to recursively delete empty folders )
Upvotes: 0
Reputation: 3158
This worked in my tests.
Clear-Host
$BaseDir = "G:\Test\America"
$GCIArgs = @{Path = "$BaseDir"
Exclude = "*.ini"
Recurse = $True}
$Files = Get-childitem @GCIArgs
$Files | Where-Object {-not $_.PSIsContainer} |
Move-Item -Destination "$BaseDir"
$Files | Where-Object {$_.PSIsContainer} |
Remove-Item -Force -Recurse
Note: you can get rid of the Exclude argument if you want to save the .ini files.
HTH
Upvotes: 0