Загрузка данных
<#
.SYNOPSIS
Reliable folder copy via robocopy, list from file, UTF-8 safe.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string]$ListFile,
[Parameter(Mandatory)] [string]$DestinationRoot,
[string]$LogDir = (Join-Path $DestinationRoot '_logs'),
[switch]$Mirror,
[switch]$CopyAll,
[switch]$WhatIf,
[ValidateSet('UTF8','ANSI','Auto')]
[string]$ListEncoding = 'Auto'
)
# --- Force UTF-8 console ---
try { chcp 65001 | Out-Null } catch {}
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $ListFile)) {
throw "List file not found: $ListFile"
}
if (-not (Test-Path -LiteralPath $DestinationRoot)) {
New-Item -ItemType Directory -Force -Path $DestinationRoot | Out-Null
}
if (-not (Test-Path -LiteralPath $LogDir)) {
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
}
# --- Read list with encoding fallback ---
function Get-PathList {
param([string]$File, [string]$Mode)
$bytes = [System.IO.File]::ReadAllBytes($File)
$candidates = switch ($Mode) {
'UTF8' { @([System.Text.Encoding]::UTF8) }
'ANSI' { @([System.Text.Encoding]::GetEncoding(1251)) }
'Auto' {
@(
[System.Text.Encoding]::UTF8,
[System.Text.Encoding]::GetEncoding(1251),
[System.Text.Encoding]::GetEncoding(866)
)
}
}
$bestLines = $null
$bestOk = -1
foreach ($enc in $candidates) {
$text = $enc.GetString($bytes)
$text = $text -replace '^\uFEFF','' # strip BOM
$lines = $text -split "`r?`n" |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -and -not $_.StartsWith('#') }
if (-not $lines) { continue }
$ok = 0
foreach ($p in $lines) {
try { if (Test-Path -LiteralPath $p) { $ok++ } } catch {}
}
Write-Host ("Encoding {0}: {1}/{2} paths exist" -f $enc.WebName, $ok, $lines.Count) -ForegroundColor DarkGray
if ($ok -eq $lines.Count) { return $lines }
if ($ok -gt $bestOk) { $bestOk = $ok; $bestLines = $lines }
}
if ($bestLines) { return $bestLines }
throw "Could not read any paths from $File"
}
$paths = Get-PathList -File $ListFile -Mode $ListEncoding
# --- robocopy common args ---
$commonArgs = @('/R:3','/W:5','/MT:16','/XJ','/NP','/TEE','/NFL','/NDL')
$copyMode = if ($CopyAll) { '/COPYALL' } else { '/COPY:DAT' }
$mode = if ($Mirror) { '/MIR' } else { '/E' }
if ($WhatIf) { $commonArgs += '/L' }
Write-Host ("Folders in list: {0}" -f $paths.Count) -ForegroundColor Cyan
Write-Host ("Destination: {0}" -f $DestinationRoot) -ForegroundColor Cyan
Write-Host ("Logs: {0}" -f $LogDir) -ForegroundColor Cyan
Write-Host ("Mode: {0} {1}{2}" -f $mode, $copyMode, $(if($WhatIf){' /L (dry-run)'}else{''})) -ForegroundColor Cyan
Write-Host ""
$ok = 0
$failed = New-Object System.Collections.Generic.List[string]
foreach ($src in $paths) {
try {
$srcFull = [System.IO.Path]::GetFullPath($src).TrimEnd('\')
} catch {
Write-Warning "Invalid path: $src"
$failed.Add($src); continue
}
if (-not (Test-Path -LiteralPath $srcFull)) {
Write-Warning "Source not found: $srcFull"
$failed.Add($srcFull); continue
}
$drive = ($srcFull -replace '^([A-Za-z]):.*$', '$1').ToUpper()
$tail = $srcFull -replace '^[A-Za-z]:\\?', ''
$target = Join-Path (Join-Path $DestinationRoot $drive) $tail
$safeName = ($srcFull -replace '^[A-Za-z]:\\?','' -replace '[\\/:*?"<>|]','_')
if (-not $safeName) { $safeName = $drive }
$log = Join-Path $LogDir ("{0}_{1}.log" -f $drive, $safeName)
Write-Host ("-> {0}" -f $srcFull) -ForegroundColor Yellow
Write-Host (" {0} -> {1}" -f $mode, $target) -ForegroundColor DarkGray
$rcArgs = @($srcFull, $target, $mode, $copyMode) + $commonArgs + @("/LOG:$log")
& robocopy @rcArgs | Out-Null
$code = $LASTEXITCODE
if ($code -ge 8) {
Write-Warning ("FAIL (code {0}): {1} -> log: {2}" -f $code, $srcFull, $log)
$failed.Add($srcFull)
} else {
Write-Host (" OK (code {0})" -f $code) -ForegroundColor Green
$ok++
}
Write-Host ""
}
Write-Host "==================================================" -ForegroundColor Cyan
Write-Host ("OK: {0} / {1}" -f $ok, $paths.Count) -ForegroundColor Green
if ($failed.Count -gt 0) {
Write-Host ("Failed: {0}" -f $failed.Count) -ForegroundColor Red
$failed | ForEach-Object { Write-Host (" - {0}" -f $_) -ForegroundColor Red }
exit 1
} else {
Write-Host "All folders copied." -ForegroundColor Green
exit 0
}