Пара функций, которые я буду использовать в одном из своих скриптов.
Код подробно комментирован, поэтому дополнительных пояснений не делаю.
# Функция синхронизации целевого каталога с каталогом, содержимое которого принято за образец. # ПАРАМЕТРЫ ФУНКЦИИ: # $sourceDirPath - путь к каталогу-источнику, т.е. к каталогу, с которым должен быть синхронизирован # целевой каталог. # $destDirPath - путь к целевому каталогу, подлежащему синхронизации. # $recursive - метка рекурсивной обработки содержимого ($True - с рекурсивной обработкой; $False - # без рекурсивной обработки). # $excludSrvFoldNames - Перечень имён подкаталогов, которые не должны участвовать в # синхронизации (т.е. пропускать их). Содержимое этих подкаталогов можно синхронизировать по иному # алгоритму (учитывая специфику содержимого). # В качестве параметра $excludSrvFoldNames можно передавать значение $NULL - это означает, # что обрабатывать следует все подкаталоги. # ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ: # Функция не имеет возвращаемых значений. # # ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ: # # sync -sourceDirPath "c:\000" -destDirPath "c:\111\222" -recursive "Новая папка", "Новая папка (2)" # # Первый пример синхронизирует содержимое каталога "c:\111\222" с содержимым принятого за эталон # каталога "c:\000". При этом обработка будет рекурсивной, и в обоих каталогах из обработки будут # исключены все подкаталоги, имеющие имена "Новая папка" и "Новая папка (2)". # # sync -sourceDirPath "c:\000" -destDirPath "c:\111\222" -recursive $NULL # # Второй пример синхронизирует содержимое каталога "c:\111\222" с содержимым принятого за эталог # каталога "c:\000". При этом обработка будет рекурсивной, и обработке будут подвергаться все # подкаталоги, т.к. аргументу '-excludSrvFoldNames' в качестве значения передан $NULL. # # sync -sourceDirPath "c:\000" -destDirPath "c:\111\222" $NULL # # Третий пример синхронизирует содержимое каталога "c:\111\222" с содержимым принятого за эталог # каталога "c:\000". При этом обработка не будет рекурсивной, т.к. не указан переключатель '-recursive'. # function sync ([string] $sourceDirPath, [string] $destDirPath, [Switch] $recursive, ` [string[]] $excludSrvFoldNames) { # Если указанный клиентский каталог отсутствует - создаём новый одноимённый каталог if (![System.IO.Directory]::Exists($destDirPath)) { New-Item -Path $destDirPath -ItemType "directory" | Out-Null } # Если в качестве фильтра передан $NULL - заменяем его массивом, состоящим из одного значения # "" (каталогов с таким именем не может существовать, а следовательно это гарантирует выборку # всех подкаталогов. if ($excludSrvFoldNames -eq $NULL) { [string[]] $excludSrvFoldNames = "" } # Получаем имена эталонных файлов $sourceFileNames = $NULL $sourceDirPath | Get-Item | Get-ChildItem | Where-Object {!$_.PSIsContainer} | ForEach-Object ` {[string[]] $sourceFileNames += $_.PSChildName} # Удаляем лишние целевые файлы $destDirPath | Get-Item | Get-ChildItem | Where-Object {!$_.PSIsContainer -and ` !($sourceFileNames -contains $_.PSChildName)} | Remove-Item # Заменяем модифицированные целевые файлы их эталонными оригиналами $destDirPath | Get-Item | Get-ChildItem | Where-Object {!$_.PSIsContainer -and ` !(IsEqualContents "$destDirPath\$($_.PSChildName)" "$sourceDirPath\$($_.PSChildName)")} | ForEach-Object {Copy-Item -Path "$sourceDirPath\$($_.PSChildName)" -Destination $destDirPath ` -Recurse} # Получаем имена целевых файлов $destFileNames = $NULL $destDirPath | Get-Item | Get-ChildItem | Where-Object {!$_.PSIsContainer} | ForEach-Object {[string[]] $destFileNames += $_.PSChildName} # Добавляем недостающие файлы в целевой каталог $sourceDirPath | Get-Item | Get-ChildItem | Where-Object {!$_.PSIsContainer -and ` !($destFileNames -contains $_.PSChildName)} | Copy-Item -Destination $destDirPath # Если указана рекурсивная обработка, то синхронизируем вложенные подкаталоги. if ($recursive) { # Получаем имена эталонных подкаталогов $sourceSubDirNames = $NULL $sourceDirPath | Get-Item | Get-ChildItem | Where-Object {$_.PSIsContainer -and ` !($excludSrvFoldNames -contains $_.PSChildName)} | ForEach-Object ` { [string[]] $sourceSubDirNames += $_.PSChildName} # Удаляем лишние целевые каталоги $destDirPath | Get-Item | Get-ChildItem | Where-Object {$_.PSIsContainer -and ` !($excludSrvFoldNames -contains $_.PSChildName) -and !($sourceSubDirNames -contains ` $_.PSChildName)} | Remove-Item -Recurse -Force # Синхронизируем вложенные подкаталоги. $sourceDirPath | Get-Item | Get-ChildItem | Where-Object {$_.PSIsContainer -and ` !($excludSrvFoldNames -contains $_.PSChildName)} | ForEach-Object {sync $_.FullName ` "$destDirPath\$($_.PSChildName)" $recursive $excludSrvFoldNames} } } # Функция, с помощью которой будем определять идентичность содержимого файлов. Выносим проверку # идентичности в отдельную функцию, чтобы можно было заменить логику проверки. Например сейчас # проверяется размер файла и дата модификации, но можно вместо этого организовать проверку хеша по # некоторому алгоритму (MD5, SHA2 или др.). # ПАРАМЕТРЫ ФУНКЦИИ: # $first - имя первого файла, подлежащего сравнению # $second - имя второго файла, подлежащего сравнению # ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ: # Функция возвращает логическое значение, являющееся результатом сравнения: # $True - файлы одинаковые; $False - файлы разные. function IsEqualContents ([string] $first, [string] $second) { $f1 = New-Object -TypeName System.IO.FileInfo -ArgumentList $first $f2 = New-Object -TypeName System.IO.FileInfo -ArgumentList $second ($f1.Length -eq $f2.Length) -and ($f1.LastWriteTimeUtc -eq $f2.LastWriteTimeUtc) }
Код подробно комментирован, поэтому дополнительных пояснений не делаю.
2 комментария:
Добрый день!
Очень полезный и интересный скрипт.Можно ли его настроить так, чтобы он не удалял файлы которые отсутствуют в эталонной папке?
Можно. Закомментируйте строку кода, которая удаляет лишние целевые файлы (помечена комментарием в коде).
Отправить комментарий