Загрузка данных
ftp.ps1
# --- Настройки FTP ---
$ftpHost = "n5001-fap.dpc.tax.nalog.ru"
$ftpPath = "/AisNalog3"
$ftpUser = "anonymous"
$ftpPassword = ""
# --- Временная локальная папка (только для скачивания) ---
$localBasePath = "C:\Users\n4200-01-031\Desktop\App"
# --- Сетевой путь (куда перекидываем и где маркеры) ---
$networkBasePath = "Z:\Documents"
# --- Файл-флаг успешного завершения ---
$flagFile = Join-Path $networkBasePath "success.flag"
# --- Соответствие удалённых папок локальным ---
$folderMapping = @{
"AisNalog3_PROM" = "KPE"
"AisNalog3_PPK" = "PPK"
"OE" = "KOE"
"OE_IZ" = "KOEIZ"
}
# --- Шаблон имени файла-маркера версии ---
$versionPattern = '^\d+_\d+_\d+_\d+$'
# --- Параметры скорости ---
$BufferSize = 16MB # буфер скачивания и копирования
$ProgressEveryMs = 300 # как часто перерисовывать прогресс
$ShowSpeed = $true # показывать скорость (MB/s) после скачивания/копирования
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
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 }
}
}
}
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]$ftpPath)
$items = @()
try {
$uri = "ftp://$ftpHost$ftpPath/"
$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 {
Write-Host " Ошибка при получении списка файлов: $_" -ForegroundColor Red
return @()
}
}
function Get-FtpFileSize {
param(
[string]$remoteUri,
[string]$ftpDirPath,
[string]$fileName
)
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.EnableSsl = $false
$request.KeepAlive = $false
$request.Timeout = 30000
$response = $request.GetResponse()
$size = $response.ContentLength
$response.Close()
if ($size -gt 0) { return [int64]$size }
}
catch {
}
try {
$uri = "ftp://$ftpHost$ftpDirPath/"
$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) {
if ($line -match ("\s" + [regex]::Escape($fileName) + "\s*$")) {
if ($line -match "^\d{2}-\d{2}-\d{2}\s+\d{2}:\d{2}[AP]M\s+(\d+)\s+") {
return [int64]$matches[1]
}
if ($line -match "^-.*\s+(\d+)\s+\w{3}\s+\d{1,2}\s+(\d{2}:\d{2}|\d{4})\s+") {
return [int64]$matches[1]
}
}
}
}
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 Update-VersionFile {
param(
[string]$folderPath,
[string]$latestFolder,
[System.IO.FileInfo]$versionFile
)
try {
if ($versionFile) {
if ($versionFile.BaseName -eq $latestFolder) {
return
}
$extension = $versionFile.Extension
if ([string]::IsNullOrEmpty($extension)) { $extension = ".txt" }
$newName = "$latestFolder$extension"
Rename-Item -Path $versionFile.FullName -NewName $newName -Force
Write-Host " Файл версии переименован: $($versionFile.Name) -> $newName" -ForegroundColor Green
}
else {
$newName = "$latestFolder.txt"
$newPath = Join-Path $folderPath $newName
New-Item -ItemType File -Path $newPath -Force | Out-Null
Write-Host " Создан файл версии: $newName" -ForegroundColor Green
}
}
catch {
Write-Host " Ошибка при обновлении файла версии: $_" -ForegroundColor Red
}
}
function Clear-NetworkFolder {
param(
[string]$folderPath,
[System.IO.FileInfo]$versionFile,
[string[]]$keepNames = @()
)
if (!(Test-Path $folderPath)) { return }
$versionFileName = if ($versionFile) { $versionFile.Name } else { $null }
$files = Get-ChildItem -Path $folderPath -File -Force -ErrorAction SilentlyContinue
foreach ($f in $files) {
if ($versionFileName -and $f.Name -eq $versionFileName) { continue }
if ($keepNames -contains $f.Name) { continue }
try {
Remove-Item -Path $f.FullName -Force -ErrorAction Stop
Write-Host " Удалён старый файл: $($f.Name)" -ForegroundColor Gray
}
catch {
Write-Host " Не удалось удалить $($f.Name): $($_.Exception.Message)" -ForegroundColor Yellow
}
}
}
function Download-FtpFile {
param(
[string]$remoteUri,
[string]$localPath,
[string]$ftpDirPath = "",
[string]$fileName = ""
)
try {
if (-not $fileName) { $fileName = Split-Path $localPath -Leaf }
$knownSize = Get-FtpFileSize -remoteUri $remoteUri -ftpDirPath $ftpDirPath -fileName $fileName
$resumeOffset = 0
if (Test-Path $localPath) {
$resumeOffset = (Get-Item $localPath).Length
if ($knownSize -gt 0 -and $resumeOffset -ge $knownSize) {
Write-Host " Локальный файл уже полностью скачан ($([math]::Round($resumeOffset / 1MB, 2)) MB). Докачка не нужна." -ForegroundColor Green
return $true
}
if ($resumeOffset -gt 0) {
$mbHave = [math]::Round($resumeOffset / 1MB, 2)
$mbAll = if ($knownSize -gt 0) { [math]::Round($knownSize / 1MB, 2) } else { "?" }
Write-Host " Найден недокачанный файл: $mbHave / $mbAll 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.EnableSsl = $false
$request.KeepAlive = $false
$request.Timeout = 60000
$resumeSupported = $false
if ($resumeOffset -gt 0) {
try {
$request.ContentOffset = $resumeOffset
$resumeSupported = $true
}
catch {
Write-Host " Сервер не поддерживает докачку (REST): $($_.Exception.Message)" -ForegroundColor Yellow
$resumeSupported = $false
}
}
$response = $null
try {
$response = $request.GetResponse()
}
catch {
if ($resumeSupported) {
Write-Host " Докачка не удалась, начинаем с нуля..." -ForegroundColor Yellow
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.EnableSsl = $false
$request.KeepAlive = $false
$request.Timeout = 60000
$response = $request.GetResponse()
}
else {
throw
}
}
$remaining = $response.ContentLength
if ($remaining -le 0) { $remaining = $knownSize - $resumeOffset }
$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
$lastMb = -1
$width = 30
# --- Замер скорости ---
$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
if ($totalBytes -gt 0) {
Show-ProgressLine -FileName $fileName -Downloaded $downloaded -Total $totalBytes -Width $width
}
else {
$mbNow = [math]::Floor($downloaded / 1MB)
if ($mbNow -eq $lastMb) { continue }
$lastMb = $mbNow
Show-ProgressLine -FileName $fileName -Downloaded $downloaded -Total 0 -Width $width
}
}
$localStream.Close()
$ftpStream.Close()
$response.Close()
if ($totalBytes -gt 0) {
Show-ProgressLine -FileName $fileName -Downloaded $totalBytes -Total $totalBytes -Width $width
}
Write-Host ""
# --- Вывод скорости ---
if ($ShowSpeed -and $speedSw) {
$speedSw.Stop()
$sec = $speedSw.Elapsed.TotalSeconds
if ($sec -gt 0) {
$bytesTransferred = $downloaded - $speedStartBytes
$speedMBs = [math]::Round(($bytesTransferred / 1MB) / $sec, 2)
Write-Host (" Скорость скачивания: {0} MB/s" -f $speedMBs) -ForegroundColor Yellow
}
}
$fileSize = [math]::Round($downloaded / 1MB, 2)
if ($resumeOffset -gt 0) {
Write-Host (" Файл докачан: {0} (Размер: {1} MB)" -f $localPath, $fileSize) -ForegroundColor Green
} else {
Write-Host (" Файл скачан: {0} (Размер: {1} MB)" -f $localPath, $fileSize) -ForegroundColor Green
}
return $true
}
catch {
Write-Host ""
Write-Host " Ошибка при скачивании: $_" -ForegroundColor Red
return $false
}
}
function Copy-ToNetwork {
param(
[string]$sourceFile,
[string]$networkFolder
)
try {
if (!(Test-Path $networkFolder)) {
New-Item -ItemType Directory -Path $networkFolder -Force | Out-Null
Write-Host " Создана сетевая папка: $networkFolder" -ForegroundColor Gray
}
$fileName = Split-Path $sourceFile -Leaf
$destPath = Join-Path $networkFolder $fileName
Write-Host " Копирование на сеть: $sourceFile -> $destPath" -ForegroundColor Cyan
# Источник: FileShare.Read + SequentialScan (подсказка ОС)
$sourceStream = New-Object System.IO.FileStream(
$sourceFile,
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::Read,
[System.IO.FileShare]::Read,
1MB,
[System.IO.FileOptions]::SequentialScan
)
# Назначение: SequentialScan
$destStream = New-Object System.IO.FileStream(
$destPath,
[System.IO.FileMode]::Create,
[System.IO.FileAccess]::Write,
[System.IO.FileShare]::None,
1MB,
[System.IO.FileOptions]::SequentialScan
)
$buffer = New-Object Byte[] $BufferSize
$totalBytes = $sourceStream.Length
$copied = 0
$lastRender = [DateTime]::MinValue
$width = 30
# --- Замер скорости ---
$speedSw = $null
if ($ShowSpeed) {
$speedSw = [System.Diagnostics.Stopwatch]::StartNew()
}
try {
while (($bytesRead = $sourceStream.Read($buffer, 0, $BufferSize)) -gt 0) {
$destStream.Write($buffer, 0, $bytesRead)
$copied += $bytesRead
$now = Get-Date
if (($now - $lastRender).TotalMilliseconds -lt $ProgressEveryMs) { continue }
$lastRender = $now
if ($totalBytes -gt 0) {
Show-ProgressLine -FileName $fileName -Downloaded $copied -Total $totalBytes -Width $width
}
}
}
finally {
$sourceStream.Close()
$destStream.Close()
}
if ($totalBytes -gt 0) {
Show-ProgressLine -FileName $fileName -Downloaded $totalBytes -Total $totalBytes -Width $width
}
Write-Host ""
# --- Вывод скорости ---
if ($ShowSpeed -and $speedSw) {
$speedSw.Stop()
$sec = $speedSw.Elapsed.TotalSeconds
if ($sec -gt 0 -and $copied -gt 0) {
$speedMBs = [math]::Round(($copied / 1MB) / $sec, 2)
Write-Host (" Скорость копирования на Z:: {0} MB/s" -f $speedMBs) -ForegroundColor Yellow
}
}
Write-Host " Файл скопирован на сетевой диск" -ForegroundColor Green
return $true
}
catch {
Write-Host ""
Write-Host " Ошибка копирования на сеть: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
# Скачивание с FTP
function Invoke-DownloadPhase {
param([hashtable]$mapping)
$plan = @()
foreach ($remoteFolder in $mapping.Keys) {
$localFolder = $mapping[$remoteFolder]
Write-Host ""
Write-Host (">> [Скачивание] {0} -> {1}" -f $remoteFolder, $localFolder) -ForegroundColor Magenta
$remoteBasePath = "$ftpPath/$remoteFolder"
$networkFolder = Join-Path $networkBasePath $localFolder
if (!(Test-Path $localBasePath)) {
New-Item -ItemType Directory -Path $localBasePath -Force | Out-Null
Write-Host " Создана временная папка: $localBasePath" -ForegroundColor Gray
}
if (!(Test-Path $networkFolder)) {
New-Item -ItemType Directory -Path $networkFolder -Force | Out-Null
Write-Host " Создана сетевая папка: $networkFolder" -ForegroundColor Gray
}
Write-Host " Получение списка папок из: ftp://$ftpHost$remoteBasePath/" -ForegroundColor Gray
$foldersWithDates = Get-FtpFoldersWithDates -ftpPath $remoteBasePath
if ($foldersWithDates.Count -eq 0) {
Write-Host " В папке $remoteFolder нет подпапок" -ForegroundColor Red
return $null
}
Write-Host " Найдено папок: $($foldersWithDates.Count)" -ForegroundColor Gray
$latestFolder = $null
$latestDate = [DateTime]::MinValue
foreach ($folder in $foldersWithDates.Keys) {
$date = $foldersWithDates[$folder]
if ($date -gt $latestDate) {
$latestDate = $date
$latestFolder = $folder
}
}
if (-not $latestFolder) {
Write-Host " Не удалось определить самую новую папку" -ForegroundColor Red
return $null
}
Write-Host " Самая новая папка: $latestFolder ($($latestDate.ToString('dd.MM.yyyy HH:mm')))" -ForegroundColor Green
# === Проверка версии ===
$versionFile = Get-VersionFile -folderPath $networkFolder
$versionChanged = $false
if ($versionFile) {
Write-Host " Файл версии на сети: $($versionFile.Name)" -ForegroundColor Gray
if ($versionFile.BaseName -eq $latestFolder) {
Write-Host " Версия актуальна ($($versionFile.BaseName) = $latestFolder). Пропускаем." -ForegroundColor Green
continue
} else {
Write-Host " Версия неактуальна ($($versionFile.BaseName) <> $latestFolder). Забираем архив." -ForegroundColor Yellow
$versionChanged = $true
}
} else {
Write-Host " Файл версии на сети не найден. Забираем архив." -ForegroundColor Yellow
}
$ekpPath = "$remoteBasePath/$latestFolder/EKP"
Write-Host " Проверка EKP: ftp://$ftpHost$ekpPath/" -ForegroundColor Gray
$ekpFiles = Get-FtpFileList -ftpPath $ekpPath
if ($ekpFiles.Count -eq 0) {
Write-Host " Папка EKP пуста или не существует" -ForegroundColor Red
return $null
}
Write-Host " Найдено файлов в EKP: $($ekpFiles.Count)" -ForegroundColor Gray
Write-Host " Файлы: $($ekpFiles -join ', ')" -ForegroundColor Gray
$archives = @()
foreach ($file in $ekpFiles) {
if ($file -match "\.rar$") { $archives += $file }
}
if ($archives.Count -eq 0) {
Write-Host " В EKP не найдено RAR архивов" -ForegroundColor Red
Write-Host " Доступные файлы: $($ekpFiles -join ', ')" -ForegroundColor Yellow
return $null
}
Write-Host " Найдены RAR архивы: $($archives -join ', ')" -ForegroundColor Gray
$archiveToDownload = $archives[0]
if ($archives.Count -gt 1) {
Write-Host " Найдено несколько архивов, выбран: $archiveToDownload" -ForegroundColor Yellow
}
$localFilePath = Join-Path $localBasePath $archiveToDownload
$networkFilePath = Join-Path $networkFolder $archiveToDownload
# --- Если сменилась версия — локальный обрубок невалиден, удаляем ---
if ($versionChanged -and (Test-Path $localFilePath)) {
Write-Host " Сменилась версия — удаляем локальный недокачанный файл: $localFilePath" -ForegroundColor Yellow
try {
Remove-Item -Path $localFilePath -Force -ErrorAction Stop
}
catch {
Write-Host " Не удалось удалить локальный файл: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
# --- Проверяем файл на сети ---
$alreadyOnNetwork = $false
if (Test-Path $networkFilePath) {
$networkSize = (Get-Item $networkFilePath).Length
$networkMb = [math]::Round($networkSize / 1MB, 2)
$ftpUriForCheck = "ftp://$ftpHost$ekpPath/$archiveToDownload"
$ftpSizeCheck = Get-FtpFileSize -remoteUri $ftpUriForCheck -ftpDirPath $ekpPath -fileName $archiveToDownload
if ($ftpSizeCheck -gt 0 -and $networkSize -eq $ftpSizeCheck) {
Write-Host " Файл уже полностью скачан на сеть: $networkFilePath ($networkMb MB)" -ForegroundColor Green
$alreadyOnNetwork = $true
}
elseif ($ftpSizeCheck -gt 0) {
$ftpMb = [math]::Round($ftpSizeCheck / 1MB, 2)
Write-Host " Файл на сети неполный: $networkMb / $ftpMb MB. Перекачаем." -ForegroundColor Yellow
try {
Remove-Item -Path $networkFilePath -Force -ErrorAction Stop
Write-Host " Неполный файл удалён: $networkFilePath" -ForegroundColor Gray
}
catch {
Write-Host " Не удалось удалить неполный файл: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
else {
Write-Host " Файл уже существует на сети: $networkFilePath ($networkMb MB). Размер на FTP неизвестен — считаем полным." -ForegroundColor Yellow
$alreadyOnNetwork = $true
}
}
# --- Если локальный файл старше 1 дня — считаем мусором ---
if (Test-Path $localFilePath) {
$localInfo = Get-Item $localFilePath
if ($localInfo.LastWriteTime -lt (Get-Date).AddDays(-1)) {
Write-Host " Удаляем устаревший локальный файл: $localFilePath" -ForegroundColor Gray
Remove-Item $localFilePath -Force -ErrorAction SilentlyContinue
}
}
if (-not $alreadyOnNetwork) {
$downloadUri = "ftp://$ftpHost$ekpPath/$archiveToDownload"
$remoteSize = Get-FtpFileSize -remoteUri $downloadUri -ftpDirPath $ekpPath -fileName $archiveToDownload
if ($remoteSize -gt 0) {
$mb = [math]::Round($remoteSize / 1MB, 2)
Write-Host " Размер архива на FTP: $mb MB" -ForegroundColor Gray
} else {
Write-Host " Размер архива на FTP: неизвестен" -ForegroundColor Gray
}
Write-Host " Скачивание: $archiveToDownload" -ForegroundColor Cyan
Write-Host " Во временную папку: $localBasePath" -ForegroundColor Cyan
if (-not (Download-FtpFile -remoteUri $downloadUri -localPath $localFilePath -ftpDirPath $ekpPath -fileName $archiveToDownload)) {
Write-Host " Не удалось скачать архив $archiveToDownload" -ForegroundColor Red
return $null
}
}
$plan += [PSCustomObject]@{
RemoteFolder = $remoteFolder
LocalFolder = $localFolder
LatestFolder = $latestFolder
NetworkFolder = $networkFolder
VersionFile = $versionFile
ArchiveName = $archiveToDownload
LocalFilePath = $localFilePath
NetworkFilePath = $networkFilePath
AlreadyOnNetwork = $alreadyOnNetwork
}
}
return ,$plan
}
# Копирование на Z:
function Invoke-CopyPhase {
param([array]$plan)
$successCount = 0
$totalCount = $plan.Count
if ($totalCount -eq 0) {
Write-Host ""
Write-Host "Все папки уже актуальны — копировать нечего." -ForegroundColor Green
return $true
}
$index = 0
foreach ($item in $plan) {
$index++
Write-Host ""
Write-Host (">> [Копирование {0}/{1}] {2} -> {3}" -f $index, $totalCount, $item.RemoteFolder, $item.LocalFolder) -ForegroundColor Magenta
if ($item.AlreadyOnNetwork) {
Write-Host " Файл уже полный на сети — копирование не требуется." -ForegroundColor Green
Update-VersionFile -folderPath $item.NetworkFolder -latestFolder $item.LatestFolder -versionFile $item.VersionFile
$successCount++
continue
}
Clear-NetworkFolder -folderPath $item.NetworkFolder -versionFile $item.VersionFile -keepNames @($item.ArchiveName)
if (-not (Copy-ToNetwork -sourceFile $item.LocalFilePath -networkFolder $item.NetworkFolder)) {
Write-Host " Не удалось скопировать на сеть" -ForegroundColor Red
return $false
}
try {
Remove-Item -Path $item.LocalFilePath -Force -ErrorAction Stop
Write-Host " Локальный файл удалён: $($item.LocalFilePath)" -ForegroundColor Gray
}
catch {
Write-Host " Не удалось удалить локальный файл: $($_.Exception.Message)" -ForegroundColor Yellow
}
Update-VersionFile -folderPath $item.NetworkFolder -latestFolder $item.LatestFolder -versionFile $item.VersionFile
$successCount++
}
Write-Host ""
Write-Host ("Копирование завершено: {0} из {1}" -f $successCount, $totalCount) -ForegroundColor Yellow
return ($successCount -eq $totalCount)
}
#main
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "FTP-хост: $ftpHost" -ForegroundColor Yellow
Write-Host "FTP-путь: $ftpPath" -ForegroundColor Yellow
Write-Host "Временная: $localBasePath" -ForegroundColor Yellow
Write-Host "Сетевая: $networkBasePath" -ForegroundColor Yellow
Write-Host "Флаг: $flagFile" -ForegroundColor Yellow
Write-Host "Буфер: $([math]::Round($BufferSize / 1MB)) MB" -ForegroundColor Yellow
Write-Host "Показ скорости: $ShowSpeed" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
if (!(Test-Path $networkBasePath)) {
Write-Host "ВНИМАНИЕ: сетевой путь недоступен: $networkBasePath" -ForegroundColor Red
Write-Host "Проверьте, что Z: примонтирован и доступен." -ForegroundColor Red
Write-Host "Продолжаем — папки будут созданы, если это возможно." -ForegroundColor Yellow
Write-Host ""
}
# --- ФАЗА 1: СКАЧИВАНИЕ ---
Write-Host "Шаг 1 - скачивание с FTP" -ForegroundColor Cyan
$plan = Invoke-DownloadPhase -mapping $folderMapping
if ($null -eq $plan) {
Write-Host ""
Write-Host "Фаза скачивания завершилась с ошибкой. Копирование на сеть НЕ выполняется." -ForegroundColor Red
Write-Host "success.flag не создан." -ForegroundColor Red
Write-Host ""
Read-Host "ENTER для закрытия"
return
}
Write-Host ""
Write-Host "Фаза скачивания завершена успешно. Записей в плане: $($plan.Count)" -ForegroundColor Green
# --- ФАЗА 2: КОПИРОВАНИЕ ---
Write-Host ""
Write-Host "Шаг 2 - копирование на сетевой диск" -ForegroundColor Cyan
$copyOk = Invoke-CopyPhase -plan $plan
if (-not $copyOk) {
Write-Host ""
Write-Host "Фаза копирования завершилась с ошибкой. success.flag не создан." -ForegroundColor Red
Write-Host ""
Read-Host "ENTER для закрытия"
return
}
# --- СОЗДАНИЕ success.flag ---
Write-Host ""
Write-Host "Шаг 3 - создание success.flag" -ForegroundColor Cyan
if($plan.Count -eq 0) {
Write-Host "success.flag не создан. Версии актуальны" -ForegroundColor Gray
Write-Host ""
Read-Host "ENTER для закрытия"
return
}
try {
if (!(Test-Path $networkBasePath)) {
New-Item -ItemType Directory -Path $networkBasePath -Force | Out-Null
}
$flagContent = "Скачивание архивов завершено: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`r`n"
$flagContent += "Обработано папок: $($folderMapping.Count) из $($folderMapping.Count)`r`n`r`n"
$flagContent += "Скачанные и скопированные архивы:`r`n"
foreach ($remoteFolder in $folderMapping.Keys) {
$localFolder = $folderMapping[$remoteFolder]
$networkFolder = Join-Path $networkBasePath $localFolder
if (Test-Path $networkFolder) {
$files = Get-ChildItem -Path $networkFolder -File -Filter "*.rar"
if ($files.Count -gt 0) {
foreach ($file in $files) {
$size = [math]::Round($file.Length / 1MB, 2)
$flagContent += " $localFolder : $($file.Name) ($size MB)`r`n"
}
} else {
$flagContent += " $localFolder : (нет .rar)`r`n"
}
} else {
$flagContent += " $localFolder : (папка не создана)`r`n"
}
}
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($flagFile, $flagContent, $utf8NoBom)
Write-Host ""
Write-Host "Файл success.flag создан: $flagFile" -ForegroundColor Green
Write-Host "Содержимое success.flag:" -ForegroundColor Gray
Write-Host $flagContent -ForegroundColor Gray
}
catch {
Write-Host "Ошибка при создании success.flag: $_" -ForegroundColor Red
}
Write-Host ""
Write-Host "Скрипт завершён." -ForegroundColor Cyan
Read-Host "ENTER для закрытия"
#Start-Sleep -Seconds 10
#exit 0
downloader.ps1
# --- 1. Проверка прав администратора ---
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "ОШИБКА: скрипт запущен без прав администратора!" -ForegroundColor Red
Write-Host "Проверьте, что watcher запущен от имени администратора." -ForegroundColor Red
Start-Sleep -Seconds 5
exit 1
}
Write-Host "=== АВТОМАТИЧЕСКАЯ УСТАНОВКА/ПЕРЕУСТАНОВКА ПРОГРАММ ===" -ForegroundColor Cyan
Write-Host "Запущено от имени администратора" -ForegroundColor Green
# --- 2. Пути ---
# Папка-источник, где лежат KPE, PPK, KOE, KOEIZ
$rootFolder = "C:\Users\n4200-01-031\Documents"
# --- Базовая папка: там, где лежит сам downloader.ps1 (= рядом с watcher.ps1) ---
$baseDir = $PSScriptRoot
if (-not $baseDir) {
$baseDir = Split-Path -Parent $PSCommandPath
}
if (-not $baseDir) {
$baseDir = Get-Location
}
# Рабочая папка = папка скрипта. Распаковываем прямо сюда.
$workBase = $baseDir
# Путь к WinRAR
$winRarPath = "C:\Program Files\WinRAR\WinRAR.exe"
if (!(Test-Path $winRarPath)) {
$winRarPath = "C:\Program Files (x86)\WinRAR\WinRAR.exe"
}
if (!(Test-Path $winRarPath)) {
Write-Host "ОШИБКА: WinRAR не найден по стандартным путям!" -ForegroundColor Red
Write-Host "Укажите правильный путь в переменной `$winRarPath" -ForegroundColor Red
Start-Sleep -Seconds 10
exit 1
}
Write-Host "Папка-источник: $rootFolder" -ForegroundColor Cyan
Write-Host "Рабочая папка: $workBase" -ForegroundColor Cyan
Write-Host "WinRAR: $winRarPath" -ForegroundColor Cyan
Write-Host ""
# --- 3. Список программ ---
# Folder — папка в $rootFolder (с архивом .rar)
# Name — точное имя для Get-Package
# InstallFolder — имя папки в C:\Program Files (x86) (для запуска утилиты индексации)
$programs = @(
@{ Folder = "KPE"; Name = "Клиент АИС Налог-3 Пром версия"; InstallFolder = "Ais3Prom" }
@{ Folder = "PPK"; Name = "Клиент АИС Налог-3 ПредПром версия"; InstallFolder = "Ais3PredProm" }
@{ Folder = "KOE"; Name = "Клиент АИС Налог-3 ОЭ версия"; InstallFolder = "Ais3FB3OE" }
@{ Folder = "KOEIZ"; Name = "Клиент АИС Налог-3 ОЭ ИЗ версия"; InstallFolder = "Ais3OEIZ" }
)
# Поиск установленной программы
function Find-InstalledProgram {
param([string]$exactName)
Write-Host "Поиск программы: $exactName" -ForegroundColor Cyan
$foundPackage = Get-Package -Name $exactName -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $foundPackage) {
$foundPackage = Get-Package -Name "*$exactName*" -ErrorAction SilentlyContinue |
Select-Object -First 1
}
if ($foundPackage) {
Write-Host "Программа найдена: $($foundPackage.Name) (v$($foundPackage.Version))" -ForegroundColor Green
} else {
Write-Host "Программа не найдена" -ForegroundColor Gray
}
return $foundPackage
}
# Удаление программы
function Uninstall-Program {
param(
[string]$displayName,
$package
)
Write-Host "Удаление программы: $displayName" -ForegroundColor Yellow
try {
Uninstall-Package -InputObject $package -Force -ErrorAction Stop
Write-Host "Удаление успешно завершено!" -ForegroundColor Green
Start-Sleep -Seconds 3
}
catch {
Write-Host "Ошибка при удалении: $($_.Exception.Message)" -ForegroundColor Red
}
}
# --- Очистка рабочей папки: удаляем ВСЁ, кроме downloader.ps1 и watcher.ps1 ---
function Clear-WorkFolder {
param([string]$FolderPath)
if (-not (Test-Path $FolderPath)) {
Write-Host "Папка для очистки не найдена: $FolderPath" -ForegroundColor Yellow
return
}
Write-Host "Очистка рабочей папки (кроме downloader.ps1 и watcher.ps1): $FolderPath" -ForegroundColor Cyan
try {
Get-ChildItem -Path $FolderPath -Force -ErrorAction SilentlyContinue |
Where-Object {
$_.Name -ne "watcher.ps1" -and
$_.Name -ne "downloader.ps1"
} |
ForEach-Object {
Write-Host " Удаление: $($_.FullName)" -ForegroundColor Gray
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
Write-Host "Очистка завершена (оставлены только downloader.ps1 и watcher.ps1)" -ForegroundColor Green
}
catch {
Write-Host "Ошибка при очистке: $($_.Exception.Message)" -ForegroundColor Red
}
}
# Очистка папки-источника, кроме .txt (маркер версии)
function Clear-FolderExceptTxt {
param([string]$FolderPath)
if (-not (Test-Path $FolderPath)) {
Write-Host "Папка для очистки не найдена: $FolderPath" -ForegroundColor Yellow
return
}
Write-Host "Очистка папки (кроме .txt): $FolderPath" -ForegroundColor Cyan
try {
Get-ChildItem -Path $FolderPath -Directory -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
Write-Host " Удаление папки: $($_.FullName)" -ForegroundColor Gray
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
Get-ChildItem -Path $FolderPath -File -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.Extension -ne ".txt" } |
ForEach-Object {
Write-Host " Удаление файла: $($_.Name)" -ForegroundColor Gray
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
Write-Host "Очистка завершена (оставлены только .txt)" -ForegroundColor Green
}
catch {
Write-Host "Ошибка при очистке: $($_.Exception.Message)" -ForegroundColor Red
}
}
# Распаковка RAR через WinRAR
function Extract-RarArchive {
param(
[string]$archivePath,
[string]$destinationPath
)
Write-Host "Распаковка: $archivePath" -ForegroundColor Cyan
Write-Host " в: $destinationPath" -ForegroundColor Gray
try {
$arguments = "x -o+ -y `"$archivePath`" `"$destinationPath\`""
$process = Start-Process -FilePath $winRarPath -ArgumentList $arguments -Wait -PassThru -NoNewWindow
if ($process.ExitCode -eq 0) {
Write-Host "Распаковка успешно завершена!" -ForegroundColor Green
return $true
} else {
Write-Host "Ошибка распаковки! Код: $($process.ExitCode)" -ForegroundColor Red
return $false
}
}
catch {
Write-Host "Ошибка при распаковке: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
# --- Установка MSI + убийство процесса индексации + запуск утилиты ---
function Install-Program {
param(
[string]$msiPath,
[string]$programName,
[string]$installFolder
)
$processToKill = "CommonComponents.Catalog.IndexationUtility"
$exeToRun = "CommonComponents.Catalog.IndexationUtility.exe"
Write-Host "Установка MSI: $msiPath" -ForegroundColor Cyan
# --- Запуск msiexec ---
$installArguments = "/i `"$msiPath`" /quiet"
$installProcess = Start-Process -FilePath "msiexec.exe" `
-ArgumentList $installArguments `
-PassThru `
-WindowStyle Hidden
Write-Host "Установка запущена (PID: $($installProcess.Id))" -ForegroundColor Green
# --- Ожидание появления процесса индексации и его убийство ---
$targetProcess = $null
$timeout = 1000
$elapsed = 0
Write-Host "Ожидание появления процесса $processToKill..." -ForegroundColor Cyan
while ($elapsed -lt $timeout) {
$targetProcess = Get-Process -Name $processToKill -ErrorAction SilentlyContinue
if ($targetProcess) {
Write-Host "Процесс $processToKill обнаружен!" -ForegroundColor Green
Write-Host "Завершение процесса (PID: $($targetProcess.Id))..." -ForegroundColor Yellow
Stop-Process -Id $targetProcess.Id -Force
Write-Host "Процесс завершён." -ForegroundColor Green
break
}
Start-Sleep -Seconds 2
$elapsed += 2
}
if (-not $targetProcess) {
Write-Host "Внимание: Процесс $processToKill не обнаружен" -ForegroundColor Red
}
# --- Ожидание завершения установки ---
Write-Host "Ожидание завершения установки..." -ForegroundColor Cyan
Wait-Process -Id $installProcess.Id -ErrorAction SilentlyContinue
Write-Host "Установка MSI успешно завершена!" -ForegroundColor Green
Write-Host "Установщик: $(Split-Path $msiPath -Leaf)" -ForegroundColor Green
Start-Sleep -Seconds 3
# --- Поиск папки программы по InstallFolder ---
Write-Host "Поиск папки с установленной программой..." -ForegroundColor Cyan
Write-Host "Ищем папку с именем $installFolder" -ForegroundColor Cyan
$programsPath = "C:\Program Files (x86)"
$programFolder = $null
if (-not (Test-Path $programsPath)) {
Write-Host "Внимание: Папка $programsPath не найдена" -ForegroundColor Red
}
else {
# Сначала точное совпадение
$programFolder = Get-ChildItem $programsPath -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -eq $installFolder } |
Select-Object -First 1
if (-not $programFolder) {
Write-Host "Точное совпадение не найдено, ищем по частичному..." -ForegroundColor Yellow
$programFolder = Get-ChildItem $programsPath -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -like "*$installFolder*" } |
Select-Object -First 1
}
}
if (-not $programFolder) {
Write-Host "Внимание: Папка с программой '$installFolder' не найдена" -ForegroundColor Yellow
return
}
Write-Host "Папка программы найдена: $($programFolder.FullName)" -ForegroundColor Green
# --- Поиск утилиты индексации ---
$exePath = Join-Path $programFolder.FullName "Client" | Join-Path -ChildPath $exeToRun
$exePathRoot = Join-Path $programFolder.FullName $exeToRun
$finalExe = $null
if (Test-Path $exePath) {
$finalExe = $exePath
} elseif (Test-Path $exePathRoot) {
$finalExe = $exePathRoot
}
if (-not $finalExe) {
Write-Host "Внимание: Утилита $exeToRun не найдена" -ForegroundColor Red
return
}
Write-Host "Запуск утилиты: $finalExe" -ForegroundColor Cyan
try {
$utilityProcess = Start-Process -FilePath $finalExe -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
Write-Host "Утилита завершила работу (ExitCode: $($utilityProcess.ExitCode))" -ForegroundColor Green
}
catch {
Write-Host "ОШИБКА запуска утилиты: $($_.Exception.Message)" -ForegroundColor Red
}
}
# --- Обработка одной программы ---
function Process-Program {
param(
[string]$folderName,
[string]$programName,
[string]$installFolder,
[string]$sourceFolder
)
Write-Host ""
Write-Host "=====================================================" -ForegroundColor Magenta
Write-Host ">>> Программа: $programName (папка $folderName)" -ForegroundColor Magenta
Write-Host "=====================================================" -ForegroundColor Magenta
# --- 1. Проверяем папку-источник ---
if (-not (Test-Path $sourceFolder)) {
Write-Host "Папка-источник не найдена: $sourceFolder" -ForegroundColor Red
return $false
}
# --- 2. Ищем .rar в папке-источнике ---
$rarFiles = Get-ChildItem -Path $sourceFolder -Filter "*.rar" -File -Recurse -ErrorAction SilentlyContinue
if ($rarFiles.Count -eq 0) {
Write-Host "В папке $folderName не найдено .rar архивов" -ForegroundColor Red
return $false
}
$rarToUse = $rarFiles | Select-Object -First 1
Write-Host "Найден архив: $($rarToUse.Name)" -ForegroundColor Green
# --- 3. Чистим рабочую папку от предыдущих распаковок ---
Clear-WorkFolder -FolderPath $workBase
# --- 4. Копируем .rar из сетевой папки в рабочую (локально) ---
$localRarPath = Join-Path $workBase $rarToUse.Name
Write-Host "Копирование архива: $($rarToUse.FullName) -> $localRarPath" -ForegroundColor Cyan
try {
Copy-Item -Path $rarToUse.FullName -Destination $localRarPath -Force -ErrorAction Stop
$sizeMb = [math]::Round((Get-Item $localRarPath).Length / 1MB, 2)
Write-Host "Архив скопирован локально ($sizeMb MB)" -ForegroundColor Green
}
catch {
Write-Host "ОШИБКА копирования архива: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
# --- 5. Распаковываем ЛОКАЛЬНУЮ копию ---
if (-not (Extract-RarArchive -archivePath $localRarPath -destinationPath $workBase)) {
Write-Host "Распаковка не удалась, пропускаем $programName" -ForegroundColor Red
return $false
}
# --- 6. Ищем .msi в распакованном ---
$msiFile = Get-ChildItem -Path $workBase -Filter "*.msi" -File -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $msiFile) {
Write-Host "В распакованном архиве не найден .msi" -ForegroundColor Red
return $false
}
$msiPath = $msiFile.FullName
Write-Host "Найден установщик: $($msiFile.Name)" -ForegroundColor Green
Write-Host "Путь: $msiPath" -ForegroundColor Gray
# --- 7. Удаляем старую версию ---
$existingPackage = Find-InstalledProgram -exactName $programName
if ($existingPackage) {
Write-Host "Программа найдена. Удаляем..." -ForegroundColor Yellow
Uninstall-Program -displayName $existingPackage.Name -package $existingPackage
} else {
Write-Host "Программа не найдена. Выполняется установка..." -ForegroundColor Green
}
# --- 8. Установка MSI + убийство процесса индексации + запуск утилиты ---
Install-Program -msiPath $msiPath -programName $programName -installFolder $installFolder
# --- 9. Чистим рабочую папку (удаляем распакованное и локальный .rar) ---
Clear-WorkFolder -FolderPath $workBase
# --- 10. Чистим папку-источник (кроме .txt — там маркер версии) ---
Clear-FolderExceptTxt -FolderPath $sourceFolder
Write-Host "Программа '$programName' успешно установлена!" -ForegroundColor Green
Write-Host "---------------------------------------------------" -ForegroundColor Gray
return $true
}
Write-Host ""
Write-Host "=====================================================" -ForegroundColor Cyan
Write-Host "НАЧАЛО ОБРАБОТКИ ПАПОК" -ForegroundColor Cyan
Write-Host "=====================================================" -ForegroundColor Cyan
$successCount = 0
$totalCount = $programs.Count
foreach ($program in $programs) {
$folderName = $program.Folder
$programName = $program.Name
$installFolder = $program.InstallFolder
$sourceFolder = Join-Path -Path $rootFolder -ChildPath $folderName
if (Process-Program -folderName $folderName -programName $programName -installFolder $installFolder -sourceFolder $sourceFolder) {
$successCount++
}
}
Write-Host ""
Write-Host "=====================================================" -ForegroundColor Green
Write-Host "ОБРАБОТКА ВСЕХ ПАПОК ЗАВЕРШЕНА" -ForegroundColor Green
Write-Host "Успешно: $successCount из $totalCount" -ForegroundColor Green
Write-Host "=====================================================" -ForegroundColor Green
Start-Sleep -Seconds 10
exit 0
watcher.ps1
# --- 1. Проверка и запрос прав администратора ---
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Host "Требуются права администратора. Запуск от имени администратора..." -ForegroundColor Yellow
Start-Process PowerShell -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
exit
}
Write-Host "=== WATCHER: наблюдение за success.flag ===" -ForegroundColor Cyan
Write-Host "Запущено от имени администратора" -ForegroundColor Green
Write-Host ""
# --- 2. Пути ---
# Папка, где создаётся success.flag (должна совпадать с FTP-скриптом)
$watcherPath = "C:\Users\n4200-01-031\Documents"
# Файл-флаг
$flagFile = Join-Path $watcherPath "success.flag"
# Lock-файл — защита от двойной обработки
$lockFile = Join-Path $watcherPath "watcher.processing.lock"
# Порог "старого" флага (в часах) — если старше, удаляем без обработки
$staleFlagHours = 24
# --- 3. Путь к downloader.ps1: ищем рядом с watcher.ps1 ---
$scriptDir = $PSScriptRoot
if (-not $scriptDir) {
$scriptDir = Split-Path -Parent $PSCommandPath
}
if (-not $scriptDir) {
$scriptDir = Get-Location
}
$scriptPath = Join-Path $scriptDir "downloader.ps1"
Write-Host "Папка watcher'а: $scriptDir" -ForegroundColor Cyan
Write-Host "Целевой скрипт: $scriptPath" -ForegroundColor Cyan
Write-Host "Отслеживаемая папка: $watcherPath" -ForegroundColor Cyan
Write-Host "Файл-флаг: $flagFile" -ForegroundColor Cyan
Write-Host ""
# --- 4. Проверка существования путей ---
if (-not (Test-Path $watcherPath)) {
Write-Host "ОШИБКА: папка наблюдения не существует: $watcherPath" -ForegroundColor Red
Write-Host "Проверьте путь и права доступа." -ForegroundColor Red
Read-Host "Нажмите Enter для выхода"
exit 1
}
if (-not (Test-Path $scriptPath)) {
Write-Host "ОШИБКА: downloader.ps1 не найден: $scriptPath" -ForegroundColor Red
Write-Host "Проверьте, что downloader.ps1 лежит рядом с watcher.ps1." -ForegroundColor Red
Read-Host "Нажмите Enter для выхода"
exit 1
}
function Invoke-FlagProcessing {
param([string]$FlagPath)
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "СИГНАЛ ПОЛУЧЕН!" -ForegroundColor Green
Write-Host "Файл: $FlagPath" -ForegroundColor Yellow
Write-Host "Время: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Cyan
# --- Проверка lock-файла (защита от двойной обработки) ---
if (Test-Path $lockFile) {
Write-Host "Обработка уже идёт (lock-файл существует). Пропускаем." -ForegroundColor Yellow
Write-Host "Lock-файл: $lockFile" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
return
}
# --- Ставим lock ---
try {
New-Item -ItemType File -Path $lockFile -Force -ErrorAction Stop | Out-Null
Write-Host "Lock-файл создан: $lockFile" -ForegroundColor Gray
}
catch {
Write-Host "ОШИБКА создания lock-файла: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
return
}
try {
# --- Небольшая задержка, чтобы файл гарантированно дописался ---
Start-Sleep -Milliseconds 500
if (-not (Test-Path $FlagPath)) {
Write-Host "ВНИМАНИЕ: файл-флаг исчез до начала обработки" -ForegroundColor Red
return
}
# --- Показываем содержимое ---
try {
$content = Get-Content $FlagPath -Raw -ErrorAction Stop
Write-Host "Содержимое файла:" -ForegroundColor Gray
Write-Host $content -ForegroundColor Gray
} catch {
Write-Host "Не удалось прочитать содержимое: $($_.Exception.Message)" -ForegroundColor Red
}
# --- Запуск downloader.ps1 в отдельном окне ---
Write-Host ""
Write-Host "Запуск downloader.ps1 в отдельном окне: $scriptPath" -ForegroundColor Cyan
$exitCode = -1
try {
$proc = Start-Process powershell.exe -ArgumentList @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", "`"$scriptPath`""
) -PassThru -Wait -ErrorAction Stop
$exitCode = $proc.ExitCode
Write-Host "downloader.ps1 завершён с кодом: $exitCode" -ForegroundColor $(if ($exitCode -eq 0) { "Green" } else { "Red" })
}
catch {
Write-Host "ОШИБКА запуска downloader.ps1: $($_.Exception.Message)" -ForegroundColor Red
$exitCode = -1
}
# --- Удаляем флаг только при успехе ---
if ($exitCode -eq 0) {
try {
Remove-Item $FlagPath -Force -ErrorAction Stop
Write-Host "Обработка успешна, файл-флаг удалён" -ForegroundColor Green
}
catch {
Write-Host "Не удалось удалить файл-флаг: $($_.Exception.Message)" -ForegroundColor Red
}
}
else {
Write-Host "downloader.ps1 завершился с кодом $exitCode — файл-флаг оставлен для повторной попытки" -ForegroundColor Red
}
}
finally {
# --- Снимаем lock в любом случае ---
Remove-Item $lockFile -Force -ErrorAction SilentlyContinue
Write-Host "Lock-файл снят" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
}
}
if (Test-Path $flagFile) {
$flagInfo = Get-Item $flagFile
$ageHours = ((Get-Date) - $flagInfo.CreationTime).TotalHours
Write-Host "ВНИМАНИЕ: success.flag уже существует при старте!" -ForegroundColor Yellow
Write-Host "Создан: $($flagInfo.CreationTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Yellow
Write-Host "Возраст: $([math]::Round($ageHours, 1)) ч" -ForegroundColor Yellow
if ($ageHours -gt $staleFlagHours) {
Write-Host "Флаг старше $staleFlagHours ч — удаляю как устаревший." -ForegroundColor Yellow
Remove-Item $flagFile -Force -ErrorAction SilentlyContinue
}
else {
Write-Host "Обрабатываю существующий success.flag немедленно..." -ForegroundColor Cyan
Invoke-FlagProcessing -FlagPath $flagFile
}
Write-Host ""
}
else {
Write-Host "success.flag отсутствует. Ждём появления..." -ForegroundColor Green
Write-Host ""
}
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $watcherPath
$watcher.Filter = "success.flag"
$watcher.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor [System.IO.NotifyFilters]::LastWrite
$watcher.EnableRaisingEvents = $true
$watcher.IncludeSubdirectories = $false
# --- Действие при создании файла ---
$action = {
$path = $Event.SourceEventArgs.FullPath
Invoke-FlagProcessing -FlagPath $path
}
# --- Регистрируем событие ---
$eventJob = Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action $action
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Наблюдатель запущен!" -ForegroundColor Green
Write-Host "Отслеживается папка: $watcherPath" -ForegroundColor Yellow
Write-Host "Ожидание файла: success.flag" -ForegroundColor Yellow
Write-Host ""
Write-Host "Для остановки нажмите Ctrl+C" -ForegroundColor Red
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# --- Держим скрипт запущенным ---
try {
while ($true) {
Start-Sleep -Seconds 1
}
}
finally {
Write-Host ""
Write-Host "Остановка watcher'а..." -ForegroundColor Yellow
Unregister-Event -SubscriptionId $eventJob.Id -ErrorAction SilentlyContinue
$watcher.Dispose()
# Снимаем lock, если он остался от прерванной обработки
Remove-Item $lockFile -Force -ErrorAction SilentlyContinue
Write-Host "Наблюдатель остановлен." -ForegroundColor Red
}