Загрузка данных
# ============================================================
# ftp.ps1 — скачивание архивов с FTP по папкам
# ============================================================
# Качает архивы в подпапки (App2\KPE, App2\PPK и т.д.),
# после чего запускает downloader.ps1.
# ============================================================
$ftpHost = "n5001-fap.dpc.tax.nalog.ru"
$ftpPath = "/AisNalog3"
$ftpUser = "anonymous"
$ftpPassword = ""
# Корневая папка, где лежат downloader.ps1 и папки KPE, PPK и т.д.
$rootAppPath = "C:\Users\n4200-01-031\Desktop\App2"
$networkBasePath = "Z:\Documents"
# Соответствие: папка на FTP -> локальная папка -> папка на Z:
$folderMapping = @(
@{ Remote = "AisNalog3_PROM"; Local = "KPE"; Network = "KPE" }
@{ Remote = "AisNalog3_PPK"; Local = "PPK"; Network = "PPK" }
@{ Remote = "OE"; Local = "KOE"; Network = "KOE" }
@{ Remote = "OE_IZ"; Local = "KOEIZ"; Network = "KOEIZ" }
)
$versionPattern = '^\d+_\d+_\d+_\d+$'
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $PSCommandPath }
$downloader = Join-Path $scriptDir "downloader.ps1"
$BufferSize = 16MB
$ProgressEveryMs = 300
$ShowSpeed = $true
# ============================================================
# Вспомогательные функции
# ============================================================
function Show-ProgressLine {
param([string]$FileName, [int64]$Downloaded, [int64]$Total, [int]$Width = 30)
if ($Total -gt 0) {
$percent = [math]::Floor(($Downloaded / $Total) * 100)
if ($percent -gt 100) { $percent = 100 }
$mbNow = [math]::Round($Downloaded / 1MB, 1)
$mbTotal = [math]::Round($Total / 1MB, 1)
$filled = [math]::Floor($Width * $percent / 100)
if ($filled -gt $Width) { $filled = $Width }
$empty = $Width - $filled
$bar = ("*" * $filled) + ("." * $empty)
Write-Host ("`r {0} : [{1}] {2}% {3}/{4} MB" -f $FileName, $bar, $percent, $mbNow, $mbTotal) -NoNewline -ForegroundColor Cyan
} else {
$mbNow = [math]::Round($Downloaded / 1MB, 1)
Write-Host ("`r {0} : {1} MB" -f $FileName, $mbNow) -NoNewline -ForegroundColor Cyan
}
}
function Get-FtpFoldersWithDates {
param([string]$ftpPath)
$folders = @{}
try {
$uri = "ftp://$ftpHost$ftpPath/"
$request = [System.Net.FtpWebRequest]::Create($uri)
$request.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
$request.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
$request.UseBinary = $true
$request.UsePassive = $true
$request.EnableSsl = $false
$request.KeepAlive = $false
$request.Timeout = 30000
$response = $request.GetResponse()
$stream = $response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($stream)
$listing = $reader.ReadToEnd()
$reader.Close()
$response.Close()
$lines = $listing -split "`r?`n" | Where-Object { $_ -ne "" }
foreach ($line in $lines) {
$isDirectory = $false
$folderName = $null
$dateTime = $null
# Unix-подобный формат: drwxr-xr-x ...
if ($line -match "^d.*\s+(\S+)$") {
$folderName = $matches[1]
$isDirectory = $true
if ($line -match "(\w{3})\s+(\d{1,2})\s+(\d{2}:\d{2})") {
$month = $matches[1]; $day = $matches[2]; $time = $matches[3]
$currentYear = (Get-Date).Year
try {
$dateTime = [DateTime]::ParseExact("$month $day $currentYear $time", "MMM d yyyy HH:mm", [System.Globalization.CultureInfo]::InvariantCulture)
} catch {
try {
$dateTime = [DateTime]::ParseExact("$month $day $currentYear $time", "MMM dd yyyy HH:mm", [System.Globalization.CultureInfo]::InvariantCulture)
} catch { $dateTime = $null }
}
}
}
# Windows (IIS) формат: 08-10-26 10:39AM <DIR> name
elseif ($line -match "<DIR>\s+(\S+)$") {
$folderName = $matches[1]
$isDirectory = $true
if ($line -match "(\d{2}-\d{2}-\d{2})\s+(\d{2}:\d{2}[AP]M)") {
try {
$dateTime = [DateTime]::ParseExact("$($matches[1]) $($matches[2])", "MM-dd-yy hh:mmtt", [System.Globalization.CultureInfo]::InvariantCulture)
} catch { $dateTime = $null }
}
}
if ($isDirectory -and $folderName -and $folderName -ne "." -and $folderName -ne "..") {
if ($dateTime) { $folders[$folderName] = $dateTime }
else { $folders[$folderName] = [DateTime]::MinValue }
}
}
return $folders
}
catch {
Write-Host " Ошибка при получении списка папок: $_" -ForegroundColor Red
return @{}
}
}
function Get-FtpFileList {
param([string]$ftpDirPath)
$items = @()
try {
$uri = "ftp://$ftpHost$ftpDirPath/"
$request = [System.Net.FtpWebRequest]::Create($uri)
$request.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectory
$request.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
$request.UseBinary = $true; $request.UsePassive = $true
$request.EnableSsl = $false; $request.KeepAlive = $false; $request.Timeout = 30000
$response = $request.GetResponse()
$stream = $response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($stream)
$listing = $reader.ReadToEnd()
$reader.Close(); $response.Close()
$lines = $listing -split "`r?`n" | Where-Object { $_ -ne "" }
foreach ($line in $lines) { $items += $line.Trim() }
return $items
} catch { return @() }
}
function Get-FtpFileSize {
param([string]$remoteUri)
try {
$request = [System.Net.FtpWebRequest]::Create($remoteUri)
$request.Method = [System.Net.WebRequestMethods+Ftp]::GetFileSize
$request.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
$request.UseBinary = $true; $request.UsePassive = $true
$request.Timeout = 30000
$response = $request.GetResponse()
$size = $response.ContentLength
$response.Close()
if ($size -gt 0) { return [int64]$size }
} catch {}
return -1
}
function Get-VersionFile {
param([string]$folderPath)
if (!(Test-Path $folderPath)) { return $null }
$files = Get-ChildItem -Path $folderPath -File -Force -ErrorAction SilentlyContinue
foreach ($f in $files) {
if ($f.BaseName -match $versionPattern) { return $f }
}
return $null
}
function Download-FtpFile {
param([string]$remoteUri, [string]$localPath)
try {
$fileName = Split-Path $localPath -Leaf
$knownSize = Get-FtpFileSize -remoteUri $remoteUri
$resumeOffset = 0
if (Test-Path $localPath) {
$resumeOffset = (Get-Item $localPath).Length
if ($knownSize -gt 0 -and $resumeOffset -ge $knownSize) {
Write-Host " Локальный файл уже полностью скачан." -ForegroundColor Green
return $true
}
if ($resumeOffset -gt 0) { Write-Host " Докачка: $([math]::Round($resumeOffset/1MB,2)) / $([math]::Round($knownSize/1MB,2)) MB" -ForegroundColor Yellow }
}
$request = [System.Net.FtpWebRequest]::Create($remoteUri)
$request.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$request.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
$request.UseBinary = $true; $request.UsePassive = $true; $request.Timeout = 60000
$resumeSupported = $false
if ($resumeOffset -gt 0) {
try { $request.ContentOffset = $resumeOffset; $resumeSupported = $true } catch { $resumeSupported = $false }
}
$response = $null
try { $response = $request.GetResponse() } catch {
if ($resumeSupported) {
if (Test-Path $localPath) { Remove-Item $localPath -Force -ErrorAction SilentlyContinue }
$resumeOffset = 0
$request = [System.Net.FtpWebRequest]::Create($remoteUri)
$request.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$request.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPassword)
$request.UseBinary = $true; $request.UsePassive = $true; $request.Timeout = 60000
$response = $request.GetResponse()
} else { throw }
}
$remaining = $response.ContentLength
$totalBytes = if ($knownSize -gt 0) { $knownSize } else { $resumeOffset + $remaining }
$ftpStream = $response.GetResponseStream()
if ($resumeOffset -gt 0 -and $resumeSupported) {
$localStream = [System.IO.File]::Open($localPath, [System.IO.FileMode]::Append, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
} else {
$localStream = [System.IO.File]::Create($localPath)
$resumeOffset = 0
}
$buffer = New-Object Byte[] $BufferSize
$bytesRead = $ftpStream.Read($buffer, 0, $BufferSize)
$downloaded = $resumeOffset
$lastRender = [DateTime]::MinValue
$speedSw = $null; $speedStartBytes = 0
if ($ShowSpeed) { $speedSw = [System.Diagnostics.Stopwatch]::StartNew(); $speedStartBytes = $downloaded }
while ($bytesRead -gt 0) {
$localStream.Write($buffer, 0, $bytesRead)
$downloaded += $bytesRead
$bytesRead = $ftpStream.Read($buffer, 0, $BufferSize)
$now = Get-Date
if (($now - $lastRender).TotalMilliseconds -lt $ProgressEveryMs) { continue }
$lastRender = $now
Show-ProgressLine -FileName $fileName -Downloaded $downloaded -Total $totalBytes
}
$localStream.Close(); $ftpStream.Close(); $response.Close()
if ($totalBytes -gt 0) { Show-ProgressLine -FileName $fileName -Downloaded $totalBytes -Total $totalBytes }
Write-Host ""
if ($ShowSpeed -and $speedSw) {
$speedSw.Stop()
if ($speedSw.Elapsed.TotalSeconds -gt 0) {
$speedMBs = [math]::Round((($downloaded - $speedStartBytes) / 1MB) / $speedSw.Elapsed.TotalSeconds, 2)
Write-Host (" Скорость: {0} MB/s" -f $speedMBs) -ForegroundColor Yellow
}
}
return $true
} catch {
Write-Host "`n Ошибка скачивания: $_" -ForegroundColor Red
return $false
}
}
# ============================================================
# MAIN
# ============================================================
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "FTP-хост: $ftpHost" -ForegroundColor Yellow
Write-Host "База: $rootAppPath" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
$downloadedCount = 0
foreach ($map in $folderMapping) {
$remoteFolder = $map.Remote
$localFolder = $map.Local
$networkFolder = $map.Network
$remoteBasePath = "$ftpPath/$remoteFolder"
$localFolderPath = Join-Path $rootAppPath $localFolder
$networkFolderPath = Join-Path $networkBasePath $networkFolder
Write-Host ">> [Скачивание] $remoteFolder -> $localFolder" -ForegroundColor Magenta
if (!(Test-Path $localFolderPath)) { New-Item -ItemType Directory -Path $localFolderPath -Force | Out-Null }
# Проверяем актуальность
$foldersWithDates = Get-FtpFoldersWithDates -ftpPath $remoteBasePath
if ($foldersWithDates.Count -eq 0) {
Write-Host " В папке $remoteFolder нет подпапок (или ошибка листинга)" -ForegroundColor Red
continue
}
$latestFolder = $null; $latestDate = [DateTime]::MinValue
foreach ($f in $foldersWithDates.Keys) {
if ($foldersWithDates[$f] -gt $latestDate) { $latestDate = $foldersWithDates[$f]; $latestFolder = $f }
}
Write-Host " Самая новая папка: $latestFolder ($($latestDate.ToString('dd.MM.yyyy HH:mm')))" -ForegroundColor Green
$versionFile = Get-VersionFile -folderPath $networkFolderPath
if ($versionFile -and $versionFile.BaseName -eq $latestFolder) {
Write-Host " Версия актуальна ($($versionFile.BaseName) = $latestFolder). Пропускаем." -ForegroundColor Green
continue
}
# Ищем архивы в EKP
$ekpPath = "$remoteBasePath/$latestFolder/EKP"
$ekpFiles = Get-FtpFileList -ftpDirPath $ekpPath
$archives = @()
foreach ($file in $ekpFiles) { if ($file -match "\.rar$") { $archives += $file } }
if ($archives.Count -eq 0) {
Write-Host " В EKP не найдено RAR архивов" -ForegroundColor Red
continue
}
$archiveToDownload = $archives[0]
$localFilePath = Join-Path $localFolderPath $archiveToDownload
$downloadUri = "ftp://$ftpHost$ekpPath/$archiveToDownload"
Write-Host " Скачивание: $archiveToDownload" -ForegroundColor Cyan
if (Download-FtpFile -remoteUri $downloadUri -localFilePath $localFilePath) { # Внимание: здесь небольшая правка
$downloadedCount++
}
}
Write-Host "`nСкачано архивов: $downloadedCount. Запуск downloader.ps1..." -ForegroundColor Green
# ============================================================
# Запуск downloader.ps1
# ============================================================
if (Test-Path $downloader) {
$dlArgs = @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$downloader`"")
$dlProc = Start-Process powershell.exe -ArgumentList $dlArgs -Wait -PassThru -NoNewWindow
if ($dlProc.ExitCode -ne 0) {
Write-Host "`ndownloader.ps1 завершился с кодом $($dlProc.ExitCode)." -ForegroundColor Red
}
} else {
Write-Host "ОШИБКА: downloader.ps1 не найден" -ForegroundColor Red
}
Read-Host "ENTER для закрытия"