381 lines
13 KiB
PowerShell
381 lines
13 KiB
PowerShell
param(
|
||
[Parameter(Mandatory = $true)]
|
||
[string]$InstallerPath,
|
||
|
||
[Parameter(Mandatory = $true)]
|
||
[string]$ConfigurationPath,
|
||
|
||
[Parameter(Mandatory = $true)]
|
||
[string]$ErrorPath
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
$logDirectory = Join-Path $env:ProgramData 'Inventera Client'
|
||
$LogPath = Join-Path $logDirectory 'rustdesk-install.log'
|
||
|
||
function Write-InstallLog {
|
||
param([string]$Message)
|
||
|
||
try {
|
||
if (-not (Test-Path -LiteralPath $logDirectory)) {
|
||
$null = New-Item -Path $logDirectory -ItemType Directory -Force
|
||
}
|
||
Add-Content -LiteralPath $LogPath -Encoding UTF8 -Value (
|
||
'{0:yyyy-MM-dd HH:mm:ss} {1}' -f (Get-Date), $Message
|
||
)
|
||
}
|
||
catch {
|
||
# A logging failure must not prevent RustDesk installation.
|
||
}
|
||
}
|
||
|
||
trap {
|
||
$message = $_.Exception.Message
|
||
Write-InstallLog "ОШИБКА: $message"
|
||
if ($_.ScriptStackTrace) {
|
||
Write-InstallLog "Стек: $($_.ScriptStackTrace -replace '[\r\n]+', ' ')"
|
||
}
|
||
try {
|
||
[System.IO.File]::WriteAllText(
|
||
$ErrorPath,
|
||
"$message Журнал: $LogPath",
|
||
[System.Text.UTF8Encoding]::new($true)
|
||
)
|
||
}
|
||
catch {
|
||
}
|
||
exit 1
|
||
}
|
||
|
||
if (-not (Test-Path -LiteralPath $ConfigurationPath)) {
|
||
throw "Файл параметров RustDesk не найден: $ConfigurationPath"
|
||
}
|
||
|
||
$configuration = @{}
|
||
foreach ($line in Get-Content -LiteralPath $ConfigurationPath) {
|
||
$separatorIndex = $line.IndexOf('=')
|
||
if ($separatorIndex -lt 0) {
|
||
continue
|
||
}
|
||
$name = $line.Substring(0, $separatorIndex)
|
||
$value = $line.Substring($separatorIndex + 1)
|
||
$configuration[$name] = $value
|
||
}
|
||
|
||
$Mode = [string]$configuration['Mode']
|
||
$IdServer = [string]$configuration['IdServer']
|
||
$RelayServer = [string]$configuration['RelayServer']
|
||
$Key = [string]$configuration['Key']
|
||
$Password = [string]$configuration['Password']
|
||
|
||
if ($Mode -notin @('automatic', 'manual')) {
|
||
throw "Неизвестный режим настройки RustDesk: $Mode"
|
||
}
|
||
|
||
Write-InstallLog '------------------------------------------------------------'
|
||
Write-InstallLog "Запуск установки RustDesk. Режим: $Mode"
|
||
|
||
function Find-SystemRustDeskExecutable {
|
||
$candidates = @()
|
||
foreach ($basePath in @($env:ProgramFiles, ${env:ProgramFiles(x86)})) {
|
||
if ($basePath) {
|
||
$candidates += Join-Path $basePath 'RustDesk\rustdesk.exe'
|
||
}
|
||
}
|
||
|
||
foreach ($candidate in $candidates) {
|
||
if ($candidate -and (Test-Path -LiteralPath $candidate)) {
|
||
return $candidate
|
||
}
|
||
}
|
||
|
||
return $null
|
||
}
|
||
|
||
function Stop-RustDeskDesktopProcesses {
|
||
$serviceProcessId = 0
|
||
try {
|
||
$serviceInstance = Get-CimInstance `
|
||
-ClassName Win32_Service `
|
||
-Filter "Name = 'RustDesk'" `
|
||
-ErrorAction SilentlyContinue
|
||
if ($serviceInstance) {
|
||
$serviceProcessId = [int]$serviceInstance.ProcessId
|
||
}
|
||
}
|
||
catch {
|
||
Write-InstallLog "Не удалось определить PID службы RustDesk: $($_.Exception.Message)"
|
||
}
|
||
|
||
try {
|
||
$rustDeskProcesses = @(
|
||
Get-CimInstance `
|
||
-ClassName Win32_Process `
|
||
-Filter "Name = 'rustdesk.exe'" `
|
||
-ErrorAction SilentlyContinue
|
||
)
|
||
foreach ($process in $rustDeskProcesses) {
|
||
if ([int]$process.SessionId -eq 0) {
|
||
continue
|
||
}
|
||
|
||
if (($serviceProcessId -gt 0) -and
|
||
([int]$process.ProcessId -eq $serviceProcessId)) {
|
||
continue
|
||
}
|
||
|
||
$commandLine = [string]$process.CommandLine
|
||
if ($commandLine -match '(?i)--[^\s"]*install[^\s"]*|--(?:option|password)') {
|
||
continue
|
||
}
|
||
|
||
Write-InstallLog "Закрывается пользовательский процесс RustDesk, PID: $($process.ProcessId)."
|
||
Stop-Process -Id $process.ProcessId -Force -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
catch {
|
||
Write-InstallLog "Не удалось закрыть пользовательское окно RustDesk: $($_.Exception.Message)"
|
||
}
|
||
}
|
||
|
||
if (-not (Test-Path -LiteralPath $InstallerPath)) {
|
||
throw "Установщик RustDesk не найден: $InstallerPath"
|
||
}
|
||
|
||
Stop-RustDeskDesktopProcesses
|
||
|
||
Write-InstallLog 'Запускается встроенный установщик RustDesk.'
|
||
$installJob = Start-Job -ScriptBlock {
|
||
param([string]$Path)
|
||
|
||
$process = Start-Process `
|
||
-FilePath $Path `
|
||
-ArgumentList '--silent-install' `
|
||
-Wait `
|
||
-PassThru `
|
||
-WindowStyle Hidden
|
||
[int]$process.ExitCode
|
||
} -ArgumentList $InstallerPath
|
||
|
||
try {
|
||
for ($attempt = 0; $attempt -lt 120; $attempt++) {
|
||
$installJob = Get-Job -Id $installJob.Id
|
||
if ($installJob.State -ne 'Running') {
|
||
break
|
||
}
|
||
|
||
# RustDesk opens its desktop window as a child of the installer.
|
||
# Start-Process -Wait also waits for that window, so close it here.
|
||
Stop-RustDeskDesktopProcesses
|
||
Start-Sleep -Seconds 1
|
||
}
|
||
|
||
$installJob = Get-Job -Id $installJob.Id
|
||
if ($installJob.State -eq 'Running') {
|
||
throw 'Тихая установка RustDesk не завершилась за 120 секунд.'
|
||
}
|
||
if ($installJob.State -ne 'Completed') {
|
||
$jobError = ($installJob.ChildJobs[0].JobStateInfo.Reason | Out-String).Trim()
|
||
throw "Процесс установки RustDesk завершился с ошибкой: $jobError"
|
||
}
|
||
|
||
$installJobOutput = @(Receive-Job -Job $installJob -ErrorAction Stop)
|
||
if ($installJobOutput.Count -eq 0) {
|
||
throw 'Установщик RustDesk завершился без кода возврата.'
|
||
}
|
||
$installExitCode = [int]$installJobOutput[-1]
|
||
}
|
||
finally {
|
||
if ($installJob) {
|
||
if ($installJob.State -eq 'Running') {
|
||
Stop-Job -Job $installJob -ErrorAction SilentlyContinue
|
||
}
|
||
Remove-Job -Job $installJob -Force -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
Write-InstallLog "Установщик RustDesk завершён с кодом: $installExitCode"
|
||
if ($installExitCode -ne 0) {
|
||
throw "Установщик RustDesk завершился с кодом ошибки: $installExitCode."
|
||
}
|
||
|
||
$rustDeskExecutable = $null
|
||
for ($attempt = 0; $attempt -lt 60; $attempt++) {
|
||
$rustDeskExecutable = Find-SystemRustDeskExecutable
|
||
if ($rustDeskExecutable) {
|
||
break
|
||
}
|
||
Start-Sleep -Seconds 1
|
||
}
|
||
|
||
if (-not $rustDeskExecutable) {
|
||
throw "После установки не найден системный rustdesk.exe в Program Files. Код установщика RustDesk: $installExitCode."
|
||
}
|
||
|
||
Write-InstallLog "Найден RustDesk: $rustDeskExecutable"
|
||
|
||
function Invoke-RustDeskCommand {
|
||
param([string[]]$Arguments)
|
||
|
||
$output = (& $rustDeskExecutable @Arguments 2>&1 | Out-String).Trim()
|
||
$exitCode = if ($null -eq $LASTEXITCODE) { 0 } else { [int]$LASTEXITCODE }
|
||
return [PSCustomObject]@{
|
||
ExitCode = $exitCode
|
||
Output = $output
|
||
}
|
||
}
|
||
|
||
function Set-RustDeskOption {
|
||
param(
|
||
[string]$Name,
|
||
[string]$Value
|
||
)
|
||
|
||
$lastSetExitCode = -1
|
||
$lastReadExitCode = -1
|
||
$lastReadOutput = ''
|
||
|
||
for ($attempt = 1; $attempt -le 5; $attempt++) {
|
||
Write-InstallLog "Применение параметра '$Name', попытка $attempt."
|
||
|
||
$setResult = Invoke-RustDeskCommand -Arguments @('--option', $Name, $Value)
|
||
$lastSetExitCode = $setResult.ExitCode
|
||
Start-Sleep -Seconds 2
|
||
|
||
$readResult = Invoke-RustDeskCommand -Arguments @('--option', $Name)
|
||
$lastReadExitCode = $readResult.ExitCode
|
||
$lastReadOutput = $readResult.Output
|
||
|
||
if (($lastSetExitCode -eq 0) -and
|
||
($lastReadExitCode -eq 0) -and
|
||
($lastReadOutput.Trim() -eq $Value.Trim())) {
|
||
Write-InstallLog "Параметр '$Name' успешно применён."
|
||
return
|
||
}
|
||
|
||
Start-Sleep -Seconds 2
|
||
}
|
||
|
||
$readState = 'значение отличается от введённого'
|
||
if ([string]::IsNullOrWhiteSpace($lastReadOutput)) {
|
||
$readState = 'пустое значение'
|
||
}
|
||
throw "Параметр RustDesk '$Name' не был применён после 5 попыток. Код записи: $lastSetExitCode; код чтения: $lastReadExitCode; результат проверки: $readState."
|
||
}
|
||
|
||
function Remove-RustDeskService {
|
||
$existingService = Get-Service -Name 'RustDesk' -ErrorAction SilentlyContinue
|
||
if (-not $existingService) {
|
||
return
|
||
}
|
||
|
||
if ($existingService.Status -ne 'Stopped') {
|
||
Stop-Service -Name 'RustDesk' -Force -ErrorAction SilentlyContinue
|
||
try {
|
||
$existingService.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(20))
|
||
}
|
||
catch {
|
||
Write-InstallLog 'Служба RustDesk не остановилась штатно; выполняется её пересоздание.'
|
||
}
|
||
}
|
||
|
||
$existingService.Dispose()
|
||
$null = & sc.exe delete 'RustDesk' 2>&1
|
||
for ($attempt = 0; $attempt -lt 30; $attempt++) {
|
||
if (-not (Get-Service -Name 'RustDesk' -ErrorAction SilentlyContinue)) {
|
||
return
|
||
}
|
||
Start-Sleep -Seconds 1
|
||
}
|
||
|
||
throw 'Не удалось удалить некорректную службу RustDesk.'
|
||
}
|
||
|
||
function Install-RustDeskService {
|
||
Write-InstallLog 'Устанавливается служба RustDesk.'
|
||
$installServiceResult = Invoke-RustDeskCommand -Arguments @('--install-service')
|
||
Write-InstallLog "Команда установки службы завершена с кодом: $($installServiceResult.ExitCode)"
|
||
|
||
for ($attempt = 0; $attempt -lt 30; $attempt++) {
|
||
$installedService = Get-Service -Name 'RustDesk' -ErrorAction SilentlyContinue
|
||
if ($installedService) {
|
||
return $installedService
|
||
}
|
||
Start-Sleep -Seconds 1
|
||
}
|
||
|
||
throw 'Служба RustDesk не была установлена.'
|
||
}
|
||
|
||
$serviceInstance = Get-CimInstance `
|
||
-ClassName Win32_Service `
|
||
-Filter "Name = 'RustDesk'" `
|
||
-ErrorAction SilentlyContinue
|
||
if ($serviceInstance) {
|
||
$servicePath = [Environment]::ExpandEnvironmentVariables(
|
||
[string]$serviceInstance.PathName
|
||
)
|
||
if ($servicePath.IndexOf(
|
||
$rustDeskExecutable,
|
||
[StringComparison]::OrdinalIgnoreCase
|
||
) -lt 0) {
|
||
Write-InstallLog "Обнаружена служба RustDesk с некорректным путём: $servicePath"
|
||
Remove-RustDeskService
|
||
}
|
||
}
|
||
|
||
$service = Get-Service -Name 'RustDesk' -ErrorAction SilentlyContinue
|
||
if (-not $service) {
|
||
$service = Install-RustDeskService
|
||
}
|
||
|
||
if ($service.Status -ne 'Running') {
|
||
Write-InstallLog 'Запускается служба RustDesk.'
|
||
try {
|
||
Start-Service -Name 'RustDesk'
|
||
}
|
||
catch {
|
||
Write-InstallLog "Первый запуск службы завершился ошибкой: $($_.Exception.Message)"
|
||
Write-InstallLog 'Служба RustDesk будет пересоздана из системного rustdesk.exe.'
|
||
$service.Dispose()
|
||
Remove-RustDeskService
|
||
$service = Install-RustDeskService
|
||
Start-Service -Name 'RustDesk'
|
||
}
|
||
$service = Get-Service -Name 'RustDesk'
|
||
$service.WaitForStatus('Running', [TimeSpan]::FromSeconds(30))
|
||
}
|
||
|
||
Write-InstallLog 'Служба RustDesk работает.'
|
||
|
||
if ($Mode -eq 'manual') {
|
||
Set-RustDeskOption -Name 'custom-rendezvous-server' -Value $IdServer
|
||
Set-RustDeskOption -Name 'relay-server' -Value $RelayServer
|
||
Set-RustDeskOption -Name 'key' -Value $Key
|
||
}
|
||
|
||
if ($Password) {
|
||
$passwordWasSet = $false
|
||
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
||
Write-InstallLog "Задание фиксированного пароля, попытка $attempt."
|
||
$passwordResult = Invoke-RustDeskCommand -Arguments @('--password', $Password)
|
||
if (($passwordResult.ExitCode -eq 0) -and
|
||
($passwordResult.Output -match 'Done!')) {
|
||
$passwordWasSet = $true
|
||
break
|
||
}
|
||
Start-Sleep -Seconds 2
|
||
}
|
||
if (-not $passwordWasSet) {
|
||
throw "Не удалось задать фиксированный пароль RustDesk после 3 попыток. Код: $($passwordResult.ExitCode)."
|
||
}
|
||
Write-InstallLog 'Фиксированный пароль успешно задан.'
|
||
}
|
||
|
||
Write-InstallLog 'Перезапускается служба RustDesk для применения настроек.'
|
||
Restart-Service -Name 'RustDesk' -Force
|
||
$service = Get-Service -Name 'RustDesk'
|
||
$service.WaitForStatus('Running', [TimeSpan]::FromSeconds(30))
|
||
|
||
Write-InstallLog 'Установка и настройка RustDesk успешно завершены.'
|