Powershell: рекурсивное перемещение файлов из исходного каталога на один уровень вверх - PullRequest
2 голосов
/ 17 июня 2020

Я только начал баловаться Powershell, и после поиска многих скриптов я не нашел ни одного, который бы работал. (Возможно, я работаю неправильно, но у меня есть права администратора, et c.)

Мой запрос:
Сценарий Powershell, который
- рекурсивно просматривает структуру каталогов, на последний уровень
- перемещает весь контент (файлы с любым расширением), ВВЕРХ на один уровень, откуда были файлы
- после перемещения удаляет ту папку, из которой были перемещены файлы

    ◘ 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



Примечания:
- Базовая папка может называться любой папкой, например Classical, Rock и т. Д. c.
(так что в идеале я бы запустите сценарий Powershell изнутри базовой папки, где находятся все подпапки)
- глубина папки может быть 1 или многоуровневой
(в 99,9% случаев это будет 2-3 уровня глубины , т.е.
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)


Ответы [ 3 ]

1 голос
/ 19 июня 2020

Хорошо, это заставляло меня какое-то время, но я наконец понял это. Требовалась рекурсивная функция (функция, которая вызывает сама себя). Этому методу безразлично, насколько глубоко ваше дерево, поэтому он справится с этим 0,1% случаев, когда go глубиной более 3 уровней.

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

0 голосов
/ 18 июня 2020

Мне удалось смешать и сопоставить решение, которое у меня работает, ie.
Двухэтапный процесс:
1) Переместить все файлы на 1 уровень вверх, к его родительскому элементу
2) Поскольку исходная папка теперь пуста, потому что файлы были перемещены на 1 уровень вверх, следующая задача - рекурсивно удалить все пустые папки

Имея это в виду:

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

Примечания:
○ Я должен был также упомянуть, что имена моих папок содержат «[» и «]», и это становится проблемой для Powershell, потому что Get-ChildItem не будет работать.
См. Здесь: Параметр -recurse иногда не работает для командлета PowerShell get-childitem

○ Кроме того, из-за наличия в именах папок «[» и «]» для удаления этих папок также требуется какая-то «хитрость».
Сначала я остановился на этом решении
- Как рекурсивно удалить все пустые папки в PowerShell?
Однако это тот, который сработал хорошо:
Как удалить пустые подпапки с помощью PowerShell?
(На основе: Скрипт PowerShell для рекурсивного удаления пустых папок )

0 голосов
/ 17 июня 2020

Это сработало в моих тестах.

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

Примечание: вы можете избавиться от аргумента Exclude, если хотите сохранить файлы .ini.

HTH

...