Загрузка данных


# ============================================================
#  downloader.ps1 — установка MSI, архивация установленных папок,
#                   выкладка готовых RAR на Z:\Documents
# ============================================================
#  Логика:
#   1. Берём ВСЕ .rar из $localBasePath (без подпапок).
#   2. Для каждого архива:
#        - распаковываем во временную рабочую папку;
#        - находим .msi и устанавливаем;
#        - ждём/убиваем CommonComponents.Catalog.IndexationUtility;
#        - запускаем утилиту индексации;
#        - находим установленную папку программы;
#        - архивируем её через WinRAR в <LocalFolder>\<ArchiveName>;
#        - обновляем файл-маркер версии;
#        - удаляем ТОЛЬКО временную распаковку.
#   3. Сам .rar НЕ трогаем, $localBasePath НЕ чистим
#      (чисткой занимается ftp.ps1 после успешного завершения).
# ============================================================

# --- Проверка прав администратора ---
$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 "Запустите от имени администратора." -ForegroundColor Red
    Start-Sleep -Seconds 5
    exit 1
}

Write-Host "=== УСТАНОВКА ПО + АРХИВАЦИЯ + ВЫКЛАДКА НА Z: ===" -ForegroundColor Cyan
Write-Host "Запущено от имени администратора" -ForegroundColor Green
Write-Host ""

# --- Пути ---
# Сюда ftp.ps1 скачал RAR-архивы (плоско, без подпапок)
$localBasePath = "C:\Users\n4200-01-031\Desktop\App"

# Сетевой диск, куда кладём готовые архивы
$networkBasePath = "Z:\Documents"

# Временная папка для распаковки (создаётся/удаляется по ходу)
$workBase = Join-Path $env:TEMP ("downloader_" + [guid]::NewGuid().ToString("N"))

# --- 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 "Установите WinRAR или укажите путь в `$winRarPath" -ForegroundColor Red
    Start-Sleep -Seconds 10
    exit 1
}

Write-Host "Источник RAR:   $localBasePath" -ForegroundColor Cyan
Write-Host "Сеть:           $networkBasePath" -ForegroundColor Cyan
Write-Host "Рабочая папка:  $workBase" -ForegroundColor Cyan
Write-Host "WinRAR:         $winRarPath" -ForegroundColor Cyan
Write-Host ""

# --- Проверка источника ---
if (-not (Test-Path $localBasePath)) {
    Write-Host "ОШИБКА: папка не найдена: $localBasePath" -ForegroundColor Red
    Start-Sleep -Seconds 5
    exit 1
}

# --- Собираем все .rar из корня $localBasePath ---
$rarFiles = Get-ChildItem -Path $localBasePath -Filter "*.rar" -File -ErrorAction SilentlyContinue

if ($rarFiles.Count -eq 0) {
    Write-Host "В $localBasePath нет .rar архивов — нечего устанавливать." -ForegroundColor Yellow
    Start-Sleep -Seconds 5
    exit 0
}

Write-Host "Найдено архивов: $($rarFiles.Count)" -ForegroundColor Green
foreach ($r in $rarFiles) {
    Write-Host "  - $($r.Name) ($([math]::Round($r.Length / 1MB, 2)) MB)" -ForegroundColor Gray
}
Write-Host ""

# --- Соответствие: имя папки на Z: + имя программы + папка установки ---
# Ключ — имя, которое может встретиться в имени архива (KPE, PPK, KOE, KOEIZ).
# KOEIZ должен идти ПЕРЕД KOE, иначе regex поймает "KOE" внутри "KOEIZ".
$programMap = @(
    @{ Key = "KOEIZ"; NetworkFolder = "KOEIZ"; ProgramName = "Клиент АИС Налог-3 ОЭ ИЗ версия";    InstallFolder = "Ais3OEIZ" }
    @{ Key = "KPE";   NetworkFolder = "KPE";   ProgramName = "Клиент АИС Налог-3 Пром версия";     InstallFolder = "Ais3Prom" }
    @{ Key = "PPK";   NetworkFolder = "PPK";   ProgramName = "Клиент АИС Налог-3 ПредПром версия"; InstallFolder = "Ais3PredProm" }
    @{ Key = "KOE";   NetworkFolder = "KOE";   ProgramName = "Клиент АИС Налог-3 ОЭ версия";       InstallFolder = "Ais3FB3OE" }
)

# --- Шаблон имени файла-маркера версии (совпадает с ftp.ps1) ---
$versionPattern = '^\d+_\d+_\d+_\d+$'

# ============================================================
#  Вспомогательные функции
# ============================================================

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
    }
}

function Compress-FolderToRar {
    param(
        [string]$sourceFolder,
        [string]$rarPath
    )
    Write-Host "  Архивация: $sourceFolder" -ForegroundColor Cyan
    Write-Host "       в:    $rarPath" -ForegroundColor Gray

    try {
        # Убедимся, что родительская папка существует
        $parent = Split-Path -Parent $rarPath
        if (!(Test-Path $parent)) {
            New-Item -ItemType Directory -Path $parent -Force | Out-Null
        }

        # Удаляем старый архив, если есть
        if (Test-Path $rarPath) {
            Remove-Item -Path $rarPath -Force -ErrorAction SilentlyContinue
        }

        # a -r -ep1 : добавить рекурсивно, сохранить только имя верхней папки
        $arguments = "a -r -ep1 -o+ -y `"$rarPath`" `"$sourceFolder\`""
        $process = Start-Process -FilePath $winRarPath -ArgumentList $arguments -Wait -PassThru -NoNewWindow

        # WinRAR: 0 — успех, 1 — предупреждения (всё равно архив создан)
        if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 1) {
            $sizeMb = [math]::Round((Get-Item $rarPath).Length / 1MB, 2)
            Write-Host "  Архив создан ($sizeMb MB)" -ForegroundColor Green
            return $true
        } else {
            Write-Host "  Ошибка архивации! Код: $($process.ExitCode)" -ForegroundColor Red
            return $false
        }
    }
    catch {
        Write-Host "  Ошибка архивации: $($_.Exception.Message)" -ForegroundColor Red
        return $false
    }
}

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
    }
}

function Install-Msi {
    param([string]$msiPath, [string]$programName)

    $processToKill = "CommonComponents.Catalog.IndexationUtility"

    Write-Host "  Установка MSI: $msiPath" -ForegroundColor Cyan

    $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 "  Процесс обнаружен! PID: $($targetProcess.Id)" -ForegroundColor Green
            Write-Host "  Завершение процесса..." -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
    Start-Sleep -Seconds 3
}

function Find-ProgramInstallFolder {
    param([string]$installFolder)

    $programsPath = "C:\Program Files (x86)"
    if (!(Test-Path $programsPath)) { return $null }

    $found = Get-ChildItem $programsPath -Directory -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -eq $installFolder } | Select-Object -First 1

    if (-not $found) {
        $found = Get-ChildItem $programsPath -Directory -ErrorAction SilentlyContinue |
            Where-Object { $_.Name -like "*$installFolder*" } | Select-Object -First 1
    }

    if ($found) { return $found.FullName }
    return $null
}

function Invoke-IndexationUtility {
    param([string]$installFolderPath)

    if (-not $installFolderPath) { return }
    $exeToRun = "CommonComponents.Catalog.IndexationUtility.exe"

    $exePath     = Join-Path $installFolderPath "Client" | Join-Path -ChildPath $exeToRun
    $exePathRoot = Join-Path $installFolderPath $exeToRun

    $finalExe = $null
    if (Test-Path $exePath) { $finalExe = $exePath }
    elseif (Test-Path $exePathRoot) { $finalExe = $exePathRoot }

    if (-not $finalExe) {
        Write-Host "  Внимание: утилита $exeToRun не найдена в $installFolderPath" -ForegroundColor Yellow
        return
    }

    Write-Host "  Запуск утилиты: $finalExe" -ForegroundColor Cyan
    try {
        $p = Start-Process -FilePath $finalExe -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
        Write-Host "  Утилита завершила работу (ExitCode: $($p.ExitCode))" -ForegroundColor Green
    }
    catch {
        Write-Host "  ОШИБКА запуска утилиты: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# --- Работа с файлом-маркером версии на Z: ---

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
    }
}

# --- Определение версии из имени архива (если она там есть) ---
# Ищем в имени шаблон вида 1_2_3_4 — если найдём, используем как имя версии.
function Get-VersionFromArchiveName {
    param([string]$archiveName)
    if ($archiveName -match '(\d+_\d+_\d+_\d+)') {
        return $matches[1]
    }
    return $null
}

# ============================================================
#  MAIN — по одному архиву
# ============================================================

$successCount = 0
$totalCount   = $rarFiles.Count
$index        = 0

foreach ($rar in $rarFiles) {
    $index++
    Write-Host ""
    Write-Host "=====================================================" -ForegroundColor Magenta
    Write-Host ">>> [$index/$totalCount] Архив: $($rar.Name)" -ForegroundColor Magenta
    Write-Host "=====================================================" -ForegroundColor Magenta

    # --- Определяем, к какой программе относится архив ---
    $matched = $null
    foreach ($p in $programMap) {
        if ($rar.Name -match [regex]::Escape($p.Key)) {
            $matched = $p
            break
        }
    }

    if (-not $matched) {
        Write-Host "  Не удалось определить программу по имени архива: $($rar.Name)" -ForegroundColor Red
        Write-Host "  Пропускаем." -ForegroundColor Red
        continue
    }

    Write-Host "  Программа:     $($matched.ProgramName)" -ForegroundColor Green
    Write-Host "  Папка на Z:    $($matched.NetworkFolder)" -ForegroundColor Green
    Write-Host "  Папка установки: $($matched.InstallFolder)" -ForegroundColor Green

    # --- Временная папка для распаковки именно этого архива ---
    $extractDir = Join-Path $workBase ([System.IO.Path]::GetFileNameWithoutExtension($rar.Name))
    if (!(Test-Path $extractDir)) {
        New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
    }

    # --- 1. Распаковка ---
    if (-not (Extract-RarArchive -archivePath $rar.FullName -destinationPath $extractDir)) {
        Write-Host "  Пропускаем $($rar.Name) — распаковка не удалась" -ForegroundColor Red
        Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue
        continue
    }

    # --- 2. Поиск MSI ---
    $msiFile = Get-ChildItem -Path $extractDir -Filter "*.msi" -File -Recurse -ErrorAction SilentlyContinue |
        Select-Object -First 1

    if (-not $msiFile) {
        Write-Host "  MSI не найден в $($rar.Name) — пропускаем" -ForegroundColor Red
        Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue
        continue
    }

    Write-Host "  Найден установщик: $($msiFile.Name)" -ForegroundColor Green

    # --- 3. Удаление старой версии ---
    $existingPackage = Find-InstalledProgram -exactName $matched.ProgramName
    if ($existingPackage) {
        Uninstall-Program -displayName $existingPackage.Name -package $existingPackage
    } else {
        Write-Host "  Программа не найдена — будет установлена" -ForegroundColor Green
    }

    # --- 4. Установка MSI + процесс индексации ---
    Install-Msi -msiPath $msiFile.FullName -programName $matched.ProgramName

    # --- 5. Поиск установленной папки ---
    $installedFolder = Find-ProgramInstallFolder -installFolder $matched.InstallFolder
    if (-not $installedFolder) {
        Write-Host "  Установленная папка '$($matched.InstallFolder)' не найдена — архивация невозможна" -ForegroundColor Red
        Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue
        continue
    }
    Write-Host "  Установленная папка: $installedFolder" -ForegroundColor Green

    # --- 6. Запуск утилиты индексации ---
    Invoke-IndexationUtility -installFolderPath $installedFolder

    # --- 7. Архивация установленной папки на Z: ---
    $targetNetworkFolder = Join-Path $networkBasePath $matched.NetworkFolder
    if (!(Test-Path $targetNetworkFolder)) {
        try {
            New-Item -ItemType Directory -Path $targetNetworkFolder -Force | Out-Null
            Write-Host "  Создана сетевая папка: $targetNetworkFolder" -ForegroundColor Gray
        } catch {
            Write-Host "  ОШИБКА создания $targetNetworkFolder : $($_.Exception.Message)" -ForegroundColor Red
            Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue
            continue
        }
    }

    # Имя итогового архива: <NetworkFolder>_<версия>.rar
    # Если версии в имени архива нет — используем имя исходного архива.
    $version = Get-VersionFromArchiveName -archiveName $rar.Name
    if ($version) {
        $finalRarName = "$($matched.NetworkFolder)_$version.rar"
    } else {
        $finalRarName = "$($matched.NetworkFolder)_$([System.IO.Path]::GetFileNameWithoutExtension($rar.Name)).rar"
    }
    $finalRarPath = Join-Path $targetNetworkFolder $finalRarName

    if (-not (Compress-FolderToRar -sourceFolder $installedFolder -rarPath $finalRarPath)) {
        Write-Host "  Не удалось создать архив $finalRarPath" -ForegroundColor Red
        Remove-Item -Path $extractDir -Recurse -Force -ErrorAction SilentlyContinue
        continue
    }

    # --- 8. Обновление файла-маркера версии (если известна версия) ---
    if ($version) {
        $versionFile = Get-VersionFile -folderPath $targetNetworkFolder
        Update-VersionFile -folderPath $targetNetworkFolder -latestFolder $version -versionFile $versionFile
    } else {
        Write-Host "  Версия не определена — файл-маркер не обновляем" -ForegroundColor Yellow
    }

    # --- 9. Удаляем ТОЛЬКО временную распаковку ---
    try {
        Remove-Item -Path $extractDir -Recurse -Force -ErrorAction Stop
        Write-Host "  Временная распаковка удалена: $extractDir" -ForegroundColor Gray
    } catch {
        Write-Host "  Не удалось удалить $extractDir : $($_.Exception.Message)" -ForegroundColor Yellow
    }

    Write-Host "  Архив $($rar.Name) обработан (сам файл оставлен)" -ForegroundColor Green
    $successCount++
}

# --- Удаляем только общий workBase, если он остался ---
if (Test-Path $workBase) {
    try {
        Remove-Item -Path $workBase -Recurse -Force -ErrorAction SilentlyContinue
    } catch {
        # игнорируем
    }
}

Write-Host ""
Write-Host "=====================================================" -ForegroundColor Green
Write-Host "ЗАВЕРШЕНО: $successCount из $totalCount" -ForegroundColor Green
Write-Host "=====================================================" -ForegroundColor Green

if ($successCount -eq $totalCount) {
    exit 0
} else {
    exit 1
}