Скрипт PowerShell для копирования папок частями
| Скрипт PS пригодится когда будет необходимость копировать/синхронизировать большой объем папок и файлов между серверами. Под копотом будет запускаться Robocopy с параметрами /E /B /R:2 /W:1 /MT:8 /COPYALL /NFL /NDL /NP — можете запенить на нужные в самом теле скрипта. В данном скрипте копирование будет идит батчами по 10 папок в 8 поток. Эти все параметры можете заменить сами. Включено визуальное отображение процесса. Выглядит так: | ![]() |
# Параметры
$sourcePath = "\\server\d$\Shares\"#Указываем путь откуда копировать данные
$destinationPath = "D:\Shares\"#Путь куда данные скопировать. Обычно это локальное хранилище на сервера
$batchSize = 10 #Количество папок в батче
$threadCount = 6
# Проверяем доступность исходного пути
if (-not (Test-Path $sourcePath)) {
Write-Host "Ошибка: Исходный путь недоступен: $sourcePath" -ForegroundColor Red
exit 1
}
# Получаем все папки верхнего уровня
Write-Host "Сканирование папок в $sourcePath ..."
$allFolders = Get-ChildItem -Path $sourcePath -Directory | Select-Object -ExpandProperty FullName
Write-Host "Всего папок для копирования: $($allFolders.Count)"
$totalBatches = [Math]::Ceiling($allFolders.Count / $batchSize)
Write-Host "Будет обработано батчей: $totalBatches (по $batchSize папок в каждом)" -ForegroundColor Yellow
# Функция для многопоточного копирования
function Copy-FoldersBatch {
param(
[string[]]$Folders,
[string]$SourceRoot,
[string]$DestinationRoot,
[int]$ThreadCount = 6
)
$jobs = @()
$foldersPerThread = [Math]::Ceiling($Folders.Count / $ThreadCount)
for ($i = 0; $i -lt $ThreadCount; $i++) {
$startIndex = $i * $foldersPerThread
$endIndex = [Math]::Min(($startIndex + $foldersPerThread - 1), ($Folders.Count - 1))
if ($startIndex -gt $endIndex) { continue }
$threadFolders = $Folders[$startIndex..$endIndex]
Write-Host "Запущен поток $i для копирования $($threadFolders.Count) папок"
# Запуск фонового задания
$job = Start-Job -ScriptBlock {
param($folders, $sourceRoot, $destinationRoot, $threadId)
foreach ($folder in $folders) {
try {
$folderName = Split-Path $folder -Leaf
$relativePath = $folder.Substring($sourceRoot.Length).TrimStart('\')
$destPath = Join-Path $destinationRoot $relativePath
# Создаем целевую директорию, если не существует
if (-not (Test-Path $destPath)) {
New-Item -ItemType Directory -Path $destPath -Force | Out-Null
}
# Всегда запускаем Robocopy — он сам определит, что обновлять
Write-Host "[Thread $threadId] Копирование (синхронизация): $folderName"
# Формируем команду для cmd
$cmd = "robocopy `"$folder`" `"$destPath`" /E /B /R:2 /W:1 /MT:8 /COPYALL /NFL /NDL /NP"
cmd.exe /c $cmd | Out-Null
$exitCode = $LASTEXITCODE
if ($exitCode -le 7) {
Write-Host "[Thread $threadId] Успешно: $folderName" -ForegroundColor Green
} else {
Write-Host "[Thread $threadId] Ошибка копирования: $folderName (Код: $exitCode)" -ForegroundColor Red
}
}
catch {
Write-Host "[Thread $threadId] EXCEPTION: $folder -> $($_.Exception.Message)" -ForegroundColor Red
}
}
} -ArgumentList $threadFolders, $SourceRoot, $DestinationRoot, $i
$jobs += $job
}
Write-Host "Ожидание завершения потоков..."
$jobs | Wait-Job | Out-Null
$jobs | Receive-Job | Out-Null
$jobs | Remove-Job | Out-Null
}
# Основной цикл по батчам
for ($batchNumber = 0; $batchNumber -lt $totalBatches; $batchNumber++) {
$startIndex = $batchNumber * $batchSize
$endIndex = [Math]::Min(($startIndex + $batchSize - 1), ($allFolders.Count - 1))
$currentBatch = $allFolders[$startIndex..$endIndex]
Write-Host "`n=== Батч $($batchNumber + 1) из $totalBatches ===" -ForegroundColor Yellow
Write-Host "Папки в батче: $($currentBatch.Count)" -ForegroundColor Cyan
$currentBatch | ForEach-Object { Write-Host " - $(Split-Path $_ -Leaf)" }
Copy-FoldersBatch -Folders $currentBatch -SourceRoot $sourcePath -DestinationRoot $destinationPath -ThreadCount $threadCount
Write-Host "Батч $($batchNumber + 1) завершен" -ForegroundColor Green
if ($batchNumber -lt $totalBatches - 1) {
Write-Host "Пауза 3 секунд перед следующим батчем..." -ForegroundColor Gray
Start-Sleep -Seconds 3
}
}
Write-Host "`n=== ВСЕ ПАПКИ СИНХРОНИЗИРОВАНЫ ===" -ForegroundColor Green
Write-Host "Источник: $sourcePath"
Write-Host "Назначение: $destinationPath"
Write-Host "Всего обработано папок: $($allFolders.Count)"
