Настал тот момент когда необходимо уходить от всех зарубежных программ удаленного подключения, во всяком случае у нас в компании. Посмотрев отечественные аналоги мы пришли в ужас от стоимости и качества работы ПО. Поразмыслив какой функционал нам необходим для подключения 1-линии к пользователям поняли:

  1. Графический интерфейс

  2. Список ПК к которым нужно подключиться

  3. Управление ПК без согласия пользователя

А значит нам будет достаточно простого powershell'a.

Для выполнения дальнейших действий необходимо установить модуль Active Directory для PowerShell

Создаем форму в эту форму добавляем связку логин/пароля для подключения и список ПК

Add-Type -assembly System.Windows.Forms
$window_form = New-Object System.Windows.Forms.Form
$window_form.Text ='Подключение к удаленному рабочему столу'
$window_form.Width = 240
$window_form.Height = 550
$window_form.StartPosition = 'CenterScreen'

$FormLabel1 = New-Object System.Windows.Forms.Label
$FormLabel1.Text = "Введите логин:"
$FormLabel1.Location = New-Object System.Drawing.Point(10,10)
$FormLabel1.AutoSize = $true
$window_form.Controls.Add($FormLabel1)

$FormTextBox1 = New-Object System.Windows.Forms.TextBox
$FormTextBox1.Width = 200
$FormTextBox1.Location = New-Object System.Drawing.Point(10,25)

$FormLabel2 = New-Object System.Windows.Forms.Label
$FormLabel2.Text = "Введите пароль:"
$FormLabel2.Location = New-Object System.Drawing.Point(10,50)
$FormLabel2.AutoSize = $true

$FormTextBox2 = New-Object System.Windows.Forms.TextBox
$FormTextBox2.Width = 200
$FormTextBox2.text = $NULL
$FormTextBox2.Location = New-Object System.Drawing.Point(10,65)

$FormLabel3 = New-Object System.Windows.Forms.Label
$FormLabel3.Text = "Выберете компьютер для подключения:"
$FormLabel3.Location = New-Object System.Drawing.Point(10,90)
$FormLabel3.AutoSize = $true

$ListBox = New-Object System.Windows.Forms.ListBox
$ListBox.Width = 200
$ListBox.Height = 300
$ListBox.Location = New-Object System.Drawing.Point(10,105)

$FormButton = New-Object System.Windows.Forms.Button
$FormButton.Location = New-Object System.Drawing.Size(10,400)
$FormButton.Size = New-Object System.Drawing.Size(200,30)
$FormButton.Text = "Подключится"
$window_form.AcceptButton = $FormButton

$FormButton2 = New-Object System.Windows.Forms.Button
$FormButton2.Location = New-Object System.Drawing.Size(10,440)
$FormButton2.Size = New-Object System.Drawing.Size(200,30)
$FormButton2.Text = "Закрыть"
$window_form.CancelButton = $FormButton3
$FormButton2.Add_Click({$window_form.Close();$window_form.Visible=$false})

$FormLabel4 = New-Object System.Windows.Forms.Label
$FormLabel4.Text = ""
$FormLabel4.Location = New-Object System.Drawing.Point(10,480)
$FormLabel4.AutoSize = $true

$window_form.Controls.Add($FormButton)
$window_form.Controls.Add($FormButton2)
$window_form.Controls.Add($ListBox)
$window_form.Controls.Add($FormTextBox1)
$window_form.Controls.Add($FormTextBox2)
$window_form.Controls.Add($FormLabel1)
$window_form.Controls.Add($FormLabel2)
$window_form.Controls.Add($FormLabel3)
$window_form.Controls.Add($FormLabel4)

$window_form.Add_Shown({$FormTextBox1.Select()})
$window_form.Topmost = $true
$window_form.MaximizeBox = $false

$result = $window_form.ShowDialog()

Форму создали, заполним ее логином, сделаем поле пароля со звездочками и наполним списком ПК

# Прописываем ваш домен и имя пользователя
$FormTextBox1.text = "$Env:UserDomain\$Env:UserName"

# Поле пароля делаем скрытым
$FormTextBox2.PasswordChar = '*'

# Заполняем свой OU и домен
$OU = "OU=Computers,DC=domain,DC=local"

# Получаем список ПК и вносим его в поле выбора ПК
$comps = (Get-ADComputer -SearchBase $OU -Filter *).Name | Sort-Object
ForEach ($comp in $comps){
    [void] $listBox.Items.Add($comp)
    }

Теперь нужно выполнить действие при нажатии на кнопку $FormButton в котором мы должны будем найти активный сеанс пользователя удаленного ПК и подключиться к этому сеансу

# Действие на нажатие кнопки
$FormButton.Add_Click({

# Получаем имя выбранного ПК из списка
$ps = $listBox.SelectedItem.ToString()

# Передаем логин и пароль в переменную
$pwsecur = ConvertTo-SecureString -String $FormTextBox2.text -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $FormTextBox1.text, $pwsecur

# Находим все сессии удаленного ПК и ищем активную 
 $active_sessions = quser /server:$ps | foreach {($_ -replace "\s\s+",",")} | ConvertFrom-Csv
    ForEach ($active_session in $active_sessions) {    
        #Не проверял работу на англ версии
        if (($active_session.СТАТУС -eq 'Активно') -or ($active_session.STATUS -eq 'Active')){
            $id = $active_session.ID
            }

# Подключаемся к активной сессии
Start-Process -FilePath "mstsc" -ArgumentList "/v:$ps /shadow:$id /control /noconsentprompt" -Credential $Cred -Wait -WindowStyle Maximized

Скрипт готов, бежим проверять

Так же можем добавить проверки:

  1. Заполнено поле с паролем

  2. Выбран ПК

  3. Пара логин/пароль (верные или нет)

  4. Доступность ПК

С такими проверками полная версия скрипта будет выглядеть так

Hidden text
[Console]::outputEncoding = [System.Text.Encoding]::GetEncoding('cp866')

$OU = "OU=Computers,DC=domain,DC=local"

Add-Type -assembly System.Windows.Forms
$window_form = New-Object System.Windows.Forms.Form
$window_form.Text ='Подключение к удаленному рабочему столу'
$window_form.Width = 240
$window_form.Height = 550
$window_form.StartPosition = 'CenterScreen'

$FormLabel1 = New-Object System.Windows.Forms.Label
$FormLabel1.Text = "Введите логин:"
$FormLabel1.Location = New-Object System.Drawing.Point(10,10)
$FormLabel1.AutoSize = $true
$window_form.Controls.Add($FormLabel1)

$FormTextBox1 = New-Object System.Windows.Forms.TextBox
$FormTextBox1.Width = 200
$FormTextBox1.text = "$Env:UserDomain\$Env:UserName"
$FormTextBox1.Location = New-Object System.Drawing.Point(10,25)

$FormLabel2 = New-Object System.Windows.Forms.Label
$FormLabel2.Text = "Введите пароль:"
$FormLabel2.Location = New-Object System.Drawing.Point(10,50)
$FormLabel2.AutoSize = $true

$FormTextBox2 = New-Object System.Windows.Forms.TextBox
$FormTextBox2.Width = 200
$FormTextBox2.text = $NULL
$FormTextBox2.PasswordChar = '*'
$FormTextBox2.Location = New-Object System.Drawing.Point(10,65)

$FormLabel3 = New-Object System.Windows.Forms.Label
$FormLabel3.Text = "Выберете компьютер для подключения:"
$FormLabel3.Location = New-Object System.Drawing.Point(10,90)
$FormLabel3.AutoSize = $true

$ListBox = New-Object System.Windows.Forms.ListBox
$ListBox.Width = 200
$ListBox.Height = 300
$ListBox.Location = New-Object System.Drawing.Point(10,105)
$comps = (Get-ADComputer -SearchBase $OU -Filter *).Name | Sort-Object
ForEach ($comp in $comps){
    [void] $listBox.Items.Add($comp)
    }

$FormButton = New-Object System.Windows.Forms.Button
$FormButton.Location = New-Object System.Drawing.Size(10,400)
$FormButton.Size = New-Object System.Drawing.Size(200,30)
$FormButton.Text = "Подключится"
$window_form.AcceptButton = $FormButton
$FormButton.Add_Click({
    $ps = $listBox.SelectedItem.ToString()
    If (($FormTextBox2.text).Length -gt 1){
    If ($ps -ne $NULL){
        Function Test-ADAuthentication {
            param($username,$password)
            (new-object directoryservices.directoryentry "",$username,$password).psbase.name -ne $null
        }
        $testcred = Test-ADAuthentication $FormTextBox1.text $FormTextBox2.text
        If ($testcred -eq 'True'){
        If (Test-Connection $ps -Count 1 -Quiet){
        $FormLabel4.Text = "Подключаемся..."
    $pwsecur = ConvertTo-SecureString -String $FormTextBox2.text -AsPlainText -Force
    $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $FormTextBox1.text, $pwsecur
    Invoke-Command –ComputerName $ps -Credential $cred –ScriptBlock {New-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -Name 'Shadow' -Value '2' -PropertyType 'DWord'}
    Invoke-Command –ComputerName $ps -Credential $cred –ScriptBlock {New-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -Name 'AllowRemoteRPC' -Value '1' -PropertyType 'DWord'}
    $active_sessions = quser /server:$ps | foreach {($_ -replace "\s\s+",",")} | ConvertFrom-Csv
    ForEach ($active_session in $active_sessions) {    
        #вот тут не знаю как будет на анг языке
        if (($active_session.СТАТУС -eq 'Активно') -or ($active_session.STATUS -eq 'Active')){
            $id = $active_session.ID
            }
    }
 Start-Process -FilePath "mstsc" -ArgumentList "/v:$ps /shadow:$id /control /noconsentprompt" -Credential $Cred -Wait -WindowStyle Maximized

}else {
    $FormLabel4.Text = "КОМПЬЮТЕР НЕ ДОСТУПЕН!"
}
 }else {
    $FormLabel4.Text = "ЛОГИН ИЛИ ПАРОЛЬ НЕ ВЕРНЫЕ!"
}
 }else {
    $FormLabel4.Text = "ВЫ НЕ ВЫБРАЛИ КОМПЬЮТЕР!"
}
 }else {
    $FormLabel4.Text = "ВЫ НЕ ВВЕЛИ ПАРОЛЬ!"
}
 })

$FormButton2 = New-Object System.Windows.Forms.Button
$FormButton2.Location = New-Object System.Drawing.Size(10,440)
$FormButton2.Size = New-Object System.Drawing.Size(200,30)
$FormButton2.Text = "Закрыть"
$window_form.CancelButton = $FormButton3
$FormButton2.Add_Click({$window_form.Close();$window_form.Visible=$false})

$FormLabel4 = New-Object System.Windows.Forms.Label
$FormLabel4.Text = ""
$FormLabel4.Location = New-Object System.Drawing.Point(10,480)
$FormLabel4.AutoSize = $true

$window_form.Controls.Add($FormButton)
$window_form.Controls.Add($FormButton2)
$window_form.Controls.Add($ListBox)
$window_form.Controls.Add($FormTextBox1)
$window_form.Controls.Add($FormTextBox2)
$window_form.Controls.Add($FormLabel1)
$window_form.Controls.Add($FormLabel2)
$window_form.Controls.Add($FormLabel3)
$window_form.Controls.Add($FormLabel4)

$window_form.Add_Shown({$FormTextBox1.Select()})
$window_form.Topmost = $true
$window_form.MaximizeBox = $false

$result = $window_form.ShowDialog()

Powershell это очень хорошо, но запускать его жутко не удобно. Есть прекрасная возможность конвертировать полученный скрипт в exe файл

Комментарии (3)


  1. lair
    05.04.2024 13:04
    +2

    Настал тот момент когда необходимо уходить от всех зарубежных программ удаленного подключения, во всяком случае у нас в компании. [...] Поразмыслив какой функционал нам необходим для подключения 1-линии к пользователям поняли: [...] А значит нам будет достаточно простого powershell'a.

    Мне нравится, как вы опустили кучу совершенно не важных вещей типа "на всех компьютерах Windows", "на всех компьютерах есть Remote Desktop", "к целевому компьютеру есть прямой сетевой доступ" и так далее.


    1. Re1ter
      05.04.2024 13:04
      +2

      я бы дополнил:

      • на всех целевых компьютерах Win8.1 Pro и выше;

      • на компьютере админа Win10 Pro и выше (для работы флага /shadow );

      • на целевых компьютерах разрешено подключение по RDP (по умолчанию нет);

      • на целевых компьютерах включены правила Firewall TCP Query User и UDP Query User;

      • все целевые компьютеры присоединены к домену;

      • админ имеет права локального администратора на всех целевых компьютерах.


  1. dyakalex
    05.04.2024 13:04

    ну и к вышедобавленному, добавлю, что возможность подключаться к теневой сессии, раз уж мы за собой не подтираем, лучше настраивать через GPO для целевых компьютеров