Перейти к содержимому

Как сделать «Автоматическую установку Cisco Secure Client, .NET 8 и VMware Horizon Client с помощью PowerShell»

Задача сделать автоматическую установку на клиентах вне домена

  • Проверяет доступность серверов vdi.adminbd.ru и so.adminbd.ru.
  • Устанавливает/настраивает Cisco Secure Client (с профилем link_adminbd_ru.xml, ярлыком на общем рабочем столе и preferences.xml с BlockUntrustedServers=false).
  • Устанавливает .NET 8 Desktop Runtime (при необходимости).
  • Устанавливает VMware Horizon Client с параметром VDM_Server=vdi.adminbd.ru.
  • Логирует все действия в %TEMP%\vdi-client-setup.log.
  • Требует права администратора (автоматически перезапускается с повышением).
  • После завершения всех операций перезагружает компьютер (с подтверждением пользователя).
#requires -Version 3.0

<#
.SYNOPSIS
    Автоматическая установка и запуск VMware Horizon Client.
.DESCRIPTION
    Скрипт проверяет доступность сервера so.admindb.ru (репозиторий установщиков),
    при необходимости устанавливает Cisco Secure Client, .NET 8 Runtime
    и VMware Horizon Client, после чего перезагружает компьютер.
    Примечание: сервер VDI (vdi.admindb.ru) проверяется только в момент запуска Horizon Client,
    так как он доступен только при активном VPN-подключении.
#>

$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

# === Настройки ===
$VdiServer = "vdi.admindb.ru"
$soServer = "so.admindb.ru"

# URL‑ы для скачивания
$RuntimeUrl = "https://$soServer/portal/horizon/windowsdesktop-runtime-8.0.24-win-x64.exe"
$HorizonUrl = "https://$soServer/portal/horizon/VMware-Horizon-Client-2406.exe"
$CiscoUrl = "https://$soServer/portal/files/cisco-secure-client5.msi"

# Локальные пути к установщикам
$RuntimeInstallerPath = "$env:TEMP\windowsdesktop-runtime-8.0.24-win-x64.exe"
$HorizonInstallerPath = "$env:TEMP\VMware-Horizon-Client-2406.exe"
$CiscoInstallerPath = "$env:TEMP\cisco-secure-client5.msi"

# Путь к клиенту Horizon
$ClientPath = "${env:ProgramFiles}\VMware\VMware Horizon View Client\vmware-view.exe"
$LogPath = "$env:TEMP\vdi-client-setup.log"

# === Функция логирования ===
function Write-Log {
    param(
        [string]$Message,
        [ValidateSet("Info", "Warning", "Error", "Success", "Debug")]
        [string]$Type = "Info"
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] [$Type] $Message"

    try {
        Add-Content -Path $LogPath -Value $logEntry -Encoding UTF8 -ErrorAction SilentlyContinue
    } catch {
        # Игнорируем ошибки записи в лог
    }

    $color = switch ($Type) {
        "Success" { "Green" }
        "Warning" { "Yellow" }
        "Error"   { "Red" }
        "Debug"   { "DarkGray" }
        default   { "White" }
    }
    Write-Host "[ $($Type.ToUpper()) ] $Message" -ForegroundColor $color
}

# === Функция проверки доступности сервера (ping) ===
function Test-ServerAccess {
    param([string]$ServerName)
    try {
        if (Test-Connection -ComputerName $ServerName -Count 1 -Quiet) {
            Write-Log "Сервер $ServerName доступен по сети." "Success"
            return $true
        } else {
            throw "Сервер $ServerName не отвечает на ping."
        }
    } catch {
        Write-Log "Ошибка доступа к $ServerName : $($_.Exception.Message)" "Error"
        return $false
    }
}

# === Функция скачивания файла с индикацией прогресса ===
function Download-File {
    param(
        [string]$Url,
        [string]$Destination,
        [string]$Activity
    )
    $webClient = New-Object System.Net.WebClient
    try {
        $webClient.DownloadFileAsync($Url, $Destination)
        while ($webClient.IsBusy) {
            if ($webClient.DownloadProgressTotalBytes -gt 0) {
                $percent = [math]::Round(($webClient.DownloadProgress * 100) / $webClient.DownloadProgressTotalBytes, 0)
                Write-Progress -Activity $Activity -Status "Загрузка..." -PercentComplete $percent
            } else {
                Write-Progress -Activity $Activity -Status "Загрузка..." -PercentComplete -1
            }
            Start-Sleep -Milliseconds 200
        }
    } finally {
        $webClient.Dispose()
        Write-Progress -Activity $Activity -Completed
    }
}

# === Функция установки MSI (тихая установка с прогрессом) ===
function Install-Msi {
    param(
        [string]$MsiPath,
        [string]$Activity
    )
    Write-Progress -Activity $Activity -Status "Установка..." -PercentComplete -1
    $proc = Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$MsiPath`" /quiet /norestart" -Wait -PassThru
    $exitCode = $proc.ExitCode
    Write-Progress -Activity $Activity -Completed
    return $exitCode
}

# === Функция проверки наличия Cisco Secure Client ===
function Test-CiscoSecureClient {
    $paths = @(
        "${env:ProgramFiles}\Cisco\Cisco Secure Client\",
        "${env:ProgramFiles(x86)}\Cisco\Cisco Secure Client\",
        "${env:ProgramFiles}\Cisco\AnyConnect Secure Mobility Client\",
        "${env:ProgramFiles(x86)}\Cisco\AnyConnect Secure Mobility Client\"
    )
    foreach ($path in $paths) {
        if (Test-Path $path) {
            Write-Log "Cisco Secure Client найден в $path" "Success"
            return $true
        }
    }
    # Проверка через реестр
    $regPaths = @(
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
        "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
    )
    foreach ($regPath in $regPaths) {
        $products = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue | Where-Object {
            $_.DisplayName -like "*Cisco Secure Client*" -or $_.DisplayName -like "*Cisco AnyConnect*"
        }
        if ($products) {
            Write-Log "Cisco Secure Client найден в реестре: $($products[0].DisplayName)" "Success"
            return $true
        }
    }
    return $false
}

# === Функция проверки .NET 8 Desktop Runtime ===
function Test-DotNetRuntime {
    $regPath = "HKLM:\SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.NETCore.App"
    if (Test-Path $regPath) {
        $version = (Get-ItemProperty -Path $regPath -Name "Version" -ErrorAction SilentlyContinue).Version
        if ($version -and [version]$version -ge [version]"8.0.0") {
            Write-Log "Найден .NET Runtime $version (x64) в реестре." "Success"
            return $true
        }
    }
    $dotnetPath = "C:\Program Files\dotnet\shared\Microsoft.NETCore.App"
    if (Test-Path $dotnetPath) {
        $folders = Get-ChildItem -Path $dotnetPath -Directory | Where-Object { $_.Name -match '^8\.' }
        if ($folders) {
            Write-Log "Найден .NET Runtime $($folders[0].Name) в папке." "Success"
            return $true
        }
    }
    return $false
}

# === Функция настройки Cisco Secure Client ===
function Configure-CiscoSecureClient {
    Write-Log "Настройка Cisco Secure Client..." "Info"

    # 1. Определяем путь к исполняемому файлу для ярлыка
    $cscPaths = @(
        "${env:ProgramFiles(x86)}\Cisco\Cisco Secure Client\UI\csc_ui.exe",
        "${env:ProgramFiles}\Cisco\Cisco Secure Client\UI\csc_ui.exe",
        "${env:ProgramFiles(x86)}\Cisco\Cisco Secure Client\vpnui.exe",
        "${env:ProgramFiles}\Cisco\Cisco Secure Client\vpnui.exe"
    )
    $cscExe = $null
    foreach ($path in $cscPaths) {
        if (Test-Path $path) {
            $cscExe = $path
            break
        }
    }
    if (-not $cscExe) {
        Write-Log "Не найден csc_ui.exe или vpnui.exe, ярлык не будет создан." "Warning"
    }

    # 2. Создаём папку для общесистемных профилей, если её нет
    $profileDir = "C:\ProgramData\Cisco\Cisco Secure Client\VPN\Profile"
    if (-not (Test-Path $profileDir)) {
        try {
            New-Item -Path $profileDir -ItemType Directory -Force -ErrorAction Stop | Out-Null
            Write-Log "Создана папка профилей: $profileDir" "Success"
        } catch {
            Write-Log "Не удалось создать папку профилей: $($_.Exception.Message)" "Error"
            return
        }
    }

    # 3. Сохраняем XML профиля с отключённой блокировкой ненадёжных серверов
    $xmlContent = @'
<?xml version="1.0" encoding="UTF-8"?>
<AnyConnectProfile xmlns="http://schemas.xmlsoap.org/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/encoding/ AnyConnectProfile.xsd">
    <ClientInitialization>
        <UseStartBeforeLogon UserControllable="true">true</UseStartBeforeLogon>
        <AutomaticCertSelection UserControllable="false">false</AutomaticCertSelection>
        <ShowPreConnectMessage>false</ShowPreConnectMessage>
        <CertificateStore>All</CertificateStore>
        <CertificateStoreMac>All</CertificateStoreMac>
        <CertificateStoreLinux>All</CertificateStoreLinux>
        <CertificateStoreOverride>false</CertificateStoreOverride>
        <ProxySettings>Native</ProxySettings>
        <AllowLocalProxyConnections>true</AllowLocalProxyConnections>
        <AuthenticationTimeout>30</AuthenticationTimeout>
        <AutoConnectOnStart UserControllable="true">false</AutoConnectOnStart>
        <MinimizeOnConnect UserControllable="true">true</MinimizeOnConnect>
        <LocalLanAccess UserControllable="true">true</LocalLanAccess>
        <DisableCaptivePortalDetection UserControllable="true">false</DisableCaptivePortalDetection>
        <ClearSmartcardPin UserControllable="true">true</ClearSmartcardPin>
        <IPProtocolSupport>IPv4</IPProtocolSupport>
        <AutoReconnect UserControllable="false">true
            <AutoReconnectBehavior UserControllable="false">ReconnectAfterResume</AutoReconnectBehavior>
        </AutoReconnect>
        <SuspendOnConnectedStandby>false</SuspendOnConnectedStandby>
        <AutoUpdate UserControllable="true">false</AutoUpdate>
        <RSASecurIDIntegration UserControllable="true">Automatic</RSASecurIDIntegration>
        <WindowsLogonEnforcement>SingleLocalLogon</WindowsLogonEnforcement>
        <LinuxLogonEnforcement>SingleLocalLogon</LinuxLogonEnforcement>
        <WindowsVPNEstablishment>AllowRemoteUsers</WindowsVPNEstablishment>
        <LinuxVPNEstablishment>LocalUsersOnly</LinuxVPNEstablishment>
        <AutomaticVPNPolicy>false</AutomaticVPNPolicy>
        <PPPExclusion UserControllable="false">Disable
            <PPPExclusionServerIP UserControllable="false"></PPPExclusionServerIP>
        </PPPExclusion>
        <EnableScripting UserControllable="false">false</EnableScripting>
        <EnableAutomaticServerSelection UserControllable="false">false
            <AutoServerSelectionImprovement>20</AutoServerSelectionImprovement>
            <AutoServerSelectionSuspendTime>4</AutoServerSelectionSuspendTime>
        </EnableAutomaticServerSelection>
        <RetainVpnOnLogoff>false
        </RetainVpnOnLogoff>
        <CaptivePortalRemediationBrowserFailover>false</CaptivePortalRemediationBrowserFailover>
        <AllowManualHostInput>true</AllowManualHostInput>
        <BlockUntrustedServers UserControllable="false">false</BlockUntrustedServers>
    </ClientInitialization>
    <ServerList>
        <HostEntry>
            <HostName>adminbd (IPSec)</HostName>
            <HostAddress>adminbd.admindb.ru</HostAddress>
            <PrimaryProtocol>IPsec
                <StandardAuthenticationOnly>false</StandardAuthenticationOnly>
            </PrimaryProtocol>
        </HostEntry>
    </ServerList>
</AnyConnectProfile>
'@

    $profilePath = Join-Path $profileDir "adminbd_admindb_ru.xml"
    try {
        Set-Content -Path $profilePath -Value $xmlContent -Encoding UTF8 -Force -ErrorAction Stop
        Write-Log "Общесистемный профиль сохранён: $profilePath" "Success"
    } catch {
        Write-Log "Не удалось сохранить профиль: $($_.Exception.Message)" "Error"
    }

    # 4. Создаём ярлык на общем рабочем столе
    if ($cscExe) {
        $desktopPath = [System.Environment]::GetFolderPath('CommonDesktopDirectory')
        $shortcutPath = Join-Path $desktopPath "Cisco Secure Client.lnk"
        if (-not (Test-Path $shortcutPath)) {
            try {
                $shell = New-Object -ComObject WScript.Shell
                $shortcut = $shell.CreateShortcut($shortcutPath)
                $shortcut.TargetPath = $cscExe
                $shortcut.WorkingDirectory = Split-Path $cscExe -Parent
                $shortcut.Description = "Cisco Secure Client"
                $shortcut.Save()
                Write-Log "Ярлык создан: $shortcutPath" "Success"
            } catch {
                Write-Log "Ошибка при создании ярлыка: $($_.Exception.Message)" "Error"
            }
        } else {
            Write-Log "Ярлык уже существует: $shortcutPath" "Info"
        }
    }

    # 5. Настройка preferences.xml для текущего пользователя (отключение BlockUntrustedServers)
    $userLocalCiscoPath = Join-Path $env:USERPROFILE "AppData\Local\Cisco\Cisco Secure Client\VPN"
    if (-not (Test-Path $userLocalCiscoPath)) {
        try {
            New-Item -Path $userLocalCiscoPath -ItemType Directory -Force -ErrorAction Stop | Out-Null
            Write-Log "Создана папка пользовательских настроек: $userLocalCiscoPath" "Success"
        } catch {
            Write-Log "Не удалось создать папку пользовательских настроек: $($_.Exception.Message)" "Warning"
        }
    }
    $preferencesPath = Join-Path $userLocalCiscoPath "preferences.xml"
    $preferencesContent = @'
<?xml version="1.0" encoding="UTF-8"?>
<AnyConnectPreferences>
<DefaultUser></DefaultUser>
<DefaultSecondUser></DefaultSecondUser>
<ClientCertificateThumbprint></ClientCertificateThumbprint>
<MultipleClientCertificateThumbprints></MultipleClientCertificateThumbprints>
<ServerCertificateThumbprint></ServerCertificateThumbprint>
<DefaultHostName></DefaultHostName>
<DefaultHostAddress></DefaultHostAddress>
<DefaultGroup></DefaultGroup>
<ProxyHost></ProxyHost>
<ProxyPort></ProxyPort>
<SDITokenType>none</SDITokenType>
<ControllablePreferences>
<BlockUntrustedServers>false</BlockUntrustedServers>
</ControllablePreferences>
</AnyConnectPreferences>
'@
    try {
        Set-Content -Path $preferencesPath -Value $preferencesContent -Encoding UTF8 -Force -ErrorAction Stop
        Write-Log "Пользовательские настройки сохранены: $preferencesPath (BlockUntrustedServers = false)" "Success"
    } catch {
        Write-Log "Не удалось сохранить пользовательские настройки: $($_.Exception.Message)" "Warning"
    }
}

# === Проверка прав администратора и автоматическое повышение ===
function Test-Admin {
    $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object System.Security.Principal.WindowsPrincipal($identity)
    $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}

if (-not (Test-Admin)) {
    Write-Host "Скрипт требует прав администратора. Перезапускаем с повышением..." -ForegroundColor Yellow
    Start-Process powershell.exe -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
    exit
}

# === Очистка старого лога ===
if (Test-Path $LogPath) {
    try { Remove-Item $LogPath -Force -ErrorAction SilentlyContinue } catch { }
}

Clear-Host

Write-Log "=== ЗАПУСК СКРИПТА ===" "Info"
Write-Host @"
===========================================================
   Добро пожаловать в автоматический запуск VDI-клиента!
===========================================================

Этот скрипт:
  1. Проверит доступность сервера $soServer (репозиторий установщиков)
  2. При необходимости установит Cisco Secure Client
  3. При необходимости установит .NET 8 Desktop Runtime
  4. При необходимости установит VMware Horizon Client
  5. Перезагрузит компьютер после завершения

Лог сохраняется в: $LogPath

Убедитесь, что у вас есть подключение к корпоративной сети.
Примечание: сервер VDI ($VdiServer) будет доступен только после подключения VPN.
"@ -ForegroundColor Cyan

Read-Host "Нажмите Enter для продолжения"

# ====================================================================
# === Шаг 1: Проверка доступности репозитория (so.admindb.ru) ===
# ====================================================================
Write-Log "Проверка доступности сервера репозитория $soServer..." "Info"
if (-not (Test-ServerAccess $soServer)) {
    Write-Host "Сервер $soServer недоступен. Проверьте подключение к корпоративной сети." -ForegroundColor Red
    Read-Host "Нажмите Enter для выхода"
    exit 1
}

# ====================================================================
# === Шаг 2: Установка Cisco Secure Client (при необходимости) ===
# ====================================================================
Write-Log "Проверка наличия Cisco Secure Client..." "Info"
$ciscoInstalled = Test-CiscoSecureClient
if (-not $ciscoInstalled) {
    Write-Log "Cisco Secure Client не найден. Начинаем установку..." "Warning"
    
    if (Test-Path $CiscoInstallerPath) {
        try { Remove-Item -Path $CiscoInstallerPath -Force } catch { }
    }
    
    Write-Log "Скачивание установщика Cisco Secure Client из: $CiscoUrl" "Info"
    try {
        Download-File -Url $CiscoUrl -Destination $CiscoInstallerPath -Activity "Скачивание Cisco Secure Client"
        Write-Log "Установщик Cisco Secure Client успешно скачан." "Success"
    } catch {
        Write-Log "Не удалось скачать Cisco Secure Client: $($_.Exception.Message)" "Error"
        Read-Host "Нажмите Enter для выхода"
        exit 10
    }
    
    Write-Log "Установка Cisco Secure Client (тихо)..." "Info"
    try {
        $exitCode = Install-Msi -MsiPath $CiscoInstallerPath -Activity "Установка Cisco Secure Client"
        Write-Log "Установка Cisco Secure Client завершена с кодом: $exitCode" "Debug"
        if ($exitCode -eq 0) {
            Write-Log "Cisco Secure Client успешно установлен." "Success"
            Configure-CiscoSecureClient
        } elseif ($exitCode -eq 3010) {
            Write-Log "Cisco Secure Client установлен, требуется перезагрузка. (Код 3010)" "Warning"
            Write-Host "Для завершения установки Cisco Secure Client требуется перезагрузка. После перезагрузки запустите скрипт снова." -ForegroundColor Yellow
            Read-Host "Нажмите Enter для выхода"
            exit 11
        } else {
            throw "Установка Cisco Secure Client завершилась с кодом $exitCode"
        }
    } catch {
        Write-Log "Ошибка при установке Cisco Secure Client: $($_.Exception.Message)" "Error"
        Read-Host "Нажмите Enter для выхода"
        exit 12
    }
} else {
    Write-Log "Cisco Secure Client уже установлен, пропускаем." "Info"
    Configure-CiscoSecureClient
}

# ====================================================================
# === Шаг 3: Проверка и установка Horizon Client ===
# ====================================================================
Write-Log "Проверяем наличие Horizon Client по пути: $ClientPath" "Info"
if (Test-Path $ClientPath) {
    $version = (Get-Item $ClientPath).VersionInfo.FileVersion
    Write-Log "Horizon Client найден. Версия: $version" "Success"
    Write-Log "Запуск подключения к $VdiServer..." "Info"
    Start-Process -FilePath $ClientPath -ArgumentList "-serverURL $VdiServer"
    Write-Log "Клиент запущен с параметром: -serverURL $VdiServer" "Success"
    Read-Host "Нажмите Enter для завершения"
    exit 0
} else {
    Write-Log "Horizon Client не найден. Начинаем подготовку к установке..." "Warning"
}

# ====================================================================
# === Шаг 4: Установка .NET 8 Desktop Runtime (при необходимости) ===
# ====================================================================
if (-not (Test-DotNetRuntime)) {
    Write-Log ".NET 8 Desktop Runtime не обнаружен. Начинаем установку..." "Info"
    
    if (Test-Path $RuntimeInstallerPath) {
        try { Remove-Item -Path $RuntimeInstallerPath -Force } catch { }
    }
    
    Write-Log "Скачивание установщика .NET Runtime из: $RuntimeUrl" "Info"
    try {
        Download-File -Url $RuntimeUrl -Destination $RuntimeInstallerPath -Activity "Скачивание .NET Runtime"
        Write-Log "Установщик .NET Runtime успешно скачан." "Success"
    } catch {
        Write-Log "Не удалось скачать .NET Runtime: $($_.Exception.Message)" "Error"
        Read-Host "Нажмите Enter для выхода"
        exit 2
    }
    
    Write-Log "Установка .NET Runtime (тихо)..." "Info"
    try {
        $proc = Start-Process -FilePath $RuntimeInstallerPath -ArgumentList "/quiet", "/norestart" -Wait -PassThru
        $exitCode = $proc.ExitCode
        Write-Log "Установка .NET Runtime завершена с кодом: $exitCode" "Debug"
        if ($exitCode -eq 0) {
            Write-Log ".NET Runtime успешно установлен." "Success"
        } elseif ($exitCode -eq 3010) {
            Write-Log ".NET Runtime установлен, требуется перезагрузка. (Код 3010)" "Warning"
            Write-Host "Для завершения установки .NET Runtime требуется перезагрузка. После перезагрузки запустите скрипт снова." -ForegroundColor Yellow
            Read-Host "Нажмите Enter для выхода"
            exit 4
        } else {
            throw "Установка .NET Runtime завершилась с кодом $exitCode"
        }
    } catch {
        Write-Log "Ошибка при установке .NET Runtime: $($_.Exception.Message)" "Error"
        Read-Host "Нажмите Enter для выхода"
        exit 3
    }
} else {
    Write-Log ".NET 8 Desktop Runtime уже установлен, пропускаем." "Info"
}

# ====================================================================
# === Шаг 5: Скачивание и установка Horizon Client ===
# ====================================================================
Write-Log "Подготовка к установке Horizon Client..." "Info"

if (Test-Path $HorizonInstallerPath) {
    try {
        Remove-Item -Path $HorizonInstallerPath -Force
        Write-Log "Старый установщик Horizon удалён." "Debug"
    } catch {
        Write-Log "Не удалось удалить старый установщик: $($_.Exception.Message)" "Warning"
    }
}

Write-Log "Скачивание установщика Horizon Client из: $HorizonUrl" "Info"
try {
    Download-File -Url $HorizonUrl -Destination $HorizonInstallerPath -Activity "Скачивание Horizon Client"
    Write-Log "Установщик Horizon успешно скачан." "Success"
} catch {
    Write-Log "Не удалось скачать Horizon Client: $($_.Exception.Message)" "Error"
    Read-Host "Нажмите Enter для выхода"
    exit 5
}

Write-Log "Запуск тихой установки Horizon Client (параметр /S /norestart VDM_Server=vdi.admindb.ru)..." "Info"
try {
    $proc = Start-Process -FilePath $HorizonInstallerPath -ArgumentList "/S /norestart VDM_Server=vdi.admindb.ru" -Wait -PassThru
    $exitCode = $proc.ExitCode
    Write-Log "Установка Horizon Client завершена с кодом: $exitCode" "Debug"
    if ($exitCode -eq 0) {
        Write-Log "Установка Horizon Client успешна." "Success"
    } elseif ($exitCode -eq 3010) {
        Write-Log "Установка Horizon Client требует перезагрузки (код 3010)." "Warning"
        Write-Host "Для завершения установки Horizon Client требуется перезагрузка. После перезагрузки запустите скрипт снова." -ForegroundColor Yellow
        Read-Host "Нажмите Enter для выхода"
        exit 6
    } else {
        throw "Установка завершилась с кодом $exitCode"
    }
    
    $timeout = 90
    Write-Log "Ожидание появления файла клиента: $ClientPath (макс. $timeout сек)..." "Info"
    while (!(Test-Path $ClientPath) -and $timeout -gt 0) {
        Start-Sleep -Seconds 1
        $timeout--
        if ($timeout % 10 -eq 0) {
            Write-Log "Ожидание... осталось $timeout сек" "Debug"
        }
    }
    
    if (Test-Path $ClientPath) {
        $version = (Get-Item $ClientPath).VersionInfo.FileVersion
        Write-Log "Horizon Client успешно установлен. Версия: $version" "Success"
    } else {
        throw "Файл клиента не найден после установки"
    }
} catch {
    Write-Log "Ошибка при установке Horizon Client: $($_.Exception.Message)" "Error"
    Write-Host "Проверьте, что установка прошла корректно. Возможно, требуется ручная установка." -ForegroundColor Red
    Read-Host "Нажмите Enter для выхода"
    exit 7
}

# ====================================================================
# === Завершение и перезагрузка ===
# ====================================================================
Write-Log "Скрипт завершил работу успешно. Система будет перезагружена." "Success"
Write-Host "Нажмите Enter для перезагрузки компьютера..." -ForegroundColor Cyan
Read-Host
Restart-Computer -Force

 

Similar Posts:

Добавить комментарий

Яндекс.Метрика