Задача сделать автоматическую установку на клиентах вне домена
- Проверяет доступность серверов 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:
- Как автоматизировать установку horizon client на пк пользователей не в домене
- Как сделать что бы настройки cisco ip communicator мог править сам пользователь. Без run as administrator
- Как найти битые профили fslogix и найти профили которые не монтировались на сервер
- Как очистить Recoverable Items. Проблема долгая обработки почты в exchange 2016.
- Как скопировать файл на компьютеры из группы
