Как стать автором
Обновить

Копирование структуры папок без содержимого с помощью PowerShell

После приобретения нашей компанией сетевого хранилища для резервного копирования, встал вопрос о создании структуры папок, аналогично той, что уже использовались на другом хранилище. Казалось бы все просто, берем копируем и готово. Но к сожалению, вся эта структура занимает сотни гигабайт и просто копировать ее ради создания аналогичного дерева папок не совсем разумно. Кроме того, нет никакого смысла копировать туда содержимое этих папок. Создавать вручную данную структуру нереально, она достаточно витиевата и похоже уже на дерево с огромным количеством ветвей, созданную в течении длительного времени.

Постоянно работая с Powershell, я решил, что с его помощью легко смогу решить данную задачу. Первое что мне пришло в голову это вот такой код:

Copy-Item $source -Destination $destination -Recurse -Exclude *.*

но увы, как я выяснил, оказалось что при использовании параметра -Recurse, параметр -Exclude *.* не работает, он работает только без него.
И при выполнении данного кода копировалось все, включая содержимое всех папок. Я перепробовал еще несколько вариантов, но по прежнему желаемого результат не удалось добиться. Я начал искать решение в интернете, но ничего не нашел, были лишь альтернативные варианты решения при помощи сторонних утилит. Мне стало принципиально интересно решить данную задачу с помощью PowerShell.
Сначала я получал все папки, которые мне нужно было перенести на новое хранилище вот такой строкой:

$folders = Get-ChildItem $path -Recurse | ?{$_.PsIsContainer -eq $true}

переменная $folders содержит все мне необходимые папки, но она не содержит их структуры и при выполнение например такого кода:

$folders | Copy-Item $source -Destination $destination -Recurse

копируется опять же все содержимое вместе с файлами. А если делать так:

New-Item -ItemType directory $folders

то он создаст все папки в одной директории без сохранения структуры.
Я решил просмотреть свойства объектов моего массива $folders и нашел параметр FullName который содержал полный путь до папки, включая ее саму. Это не совсем то что нужно, так мне не нужно было копировать всю структуру с корня диска, а нужна была лишь ее часть. Например, FullName = 'C:\dir1\dir2\dir3\dir4\.....\dirN' и мне нужна структура начиная скажем с папки 4 и все что лежит далее в ней, в этом случае FullName мне не подходит. Однако ничего не мешает нам выбрать из этого пути того что нам нужно путем разбора строки.
В результате у меня получился простенький скрипт:

$path = Get-ChildItem Z:\Backup\Dir1 -Recurse | ?{$_.PsIsContainer -eq $true}
$dest = «C:\test\»
$parent = $path[0].Parent.Name
$path | foreach {

$_.FullName -match "$parent.+"
New-Item -ItemType directory ($dest + $Matches[0])

}

Сначала он забирает все папки в переменную $path.
Переменная $dest содержит путь, куда мы хотим скопировать структуры.
Затем в переменную $parent я помещаю «родителя» моей структуры, в данном случае это папка Dir1.
Далее перебирая все элементы я выполняю разбор строки параметра FullName(его результат выглядит так: Dir1\...\....\...\… а далее вся структура папок).
И затем просто создаю заново эту структуру в нужном мне месте.

Как оказалось все просто.

P.S. Есть небольшие нюансы при разборе строки параметра FullName, например если имя нашего $parent дублируется где внутри пути, а именно если наша родительская папка вложена в какую-нибудь папку с аналогичным ей именем, то результат разбора строки может быть иным нежели мы ожидаем. Впрочем там просто нужно немного поработать с регулярными выражениями и получить нужный результат.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.