Настал тот момент когда необходимо уходить от всех зарубежных программ удаленного подключения, во всяком случае у нас в компании. Посмотрев отечественные аналоги мы пришли в ужас от стоимости и качества работы ПО. Поразмыслив какой функционал нам необходим для подключения 1-линии к пользователям поняли:
Список ПК к которым нужно подключиться
Управление ПК без согласия пользователя
А значит нам будет достаточно простого 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Скрипт готов, бежим проверять
Так же можем добавить проверки:
Заполнено поле с паролем
С такими проверками полная версия скрипта будет выглядеть так
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 файл
This article will guide you step by step on how to run a powershell script to return
and populate a CheckList.
As Developers and IT Pros, we often have to extend the capabilities of an installer.
We can use a custom action type to retrieve specific values to populate a
CheckList.
One way to populate a CheckList with data from a custom script is by using Powershell
scripts. But, that’s not the only way.
Let’s see how you can do this!
How to populate a CheckList with data from a custom script?
For this example, we run a PowerShell script to retrieve a list of all
the drives on a target machine. Then, the same script will use that data to populate a
CheckList — in our case, the list of drives.
If you are more familiar with VBScript, JavaScript, C# or C++, you can use any of these
programming languages to write your script. The logic will be the same.
The same logic
applies if you need to populate a ComboBox or a ListBox instead of a CheckList.
Here is our PowerShell script that retrieves the list of drives on the
target machine:
# Block for declaring the script parameters.
Param()
# Gets the drives by their root property and saves them into a variable
Add-Type -AssemblyName PresentationFramework
$drives = Get-PSDrive -PSProvider FileSystem | Select Root
# The result is an array of elements. We will have to browse it and create a string composed of the array elements,
# separated by a pipe character ("|")
# For instance, on my machine, the $new variable looks like this: A:\|C:\|D:\|
for($i = 0; $i -lt $drives.Count; $i++){
$temp = -join ($drives[$i].Root,'|')
$new += $temp
# Replace the "\" from our path with "\\". It is needed to escape the "\" character with another "\",
# otherwise the "PopulateListBox" custom action will ignore it (this is a limitation of the "PopulateListBox" Custom Action)
$final = $new.Replace("\","\\")
# The AI_LISTBOX_DATA must be in the following format: CHECKLIST_1_PROP|Value 1|Value 2| Value 3|...
$conc = -join("CHECKLIST_1_PROP|",$final.Substring(0,$final.Length-2)) How to retrieve the list of drives using Custom Action?
Based on the above PowerShell script, all we have to do is set a
property (in our case, AI_LISTBOX_DATA) to the list of drives. We do
this by adding the below line at the end of our PowerShell script.
Here, we set the AI_LISTBOX_DATA property to the list of
drives:
AI_SetMsiProperty AI_LISTBOX_DATA $conc
Now, let’s add the updated PowerShell script as a “PowerShellScriptInLine”
Custom Action without sequence. The Custom Action should be set as the one in the
image below:

Create the “Populate ListBox” using Custom Action
To populate the CheckList, use the predefined “PopulateListBox” Custom Action in
Advanced Installer.
The Custom Action setting should look like this:

How to execute the Custom Actions?
After you configure both Custom Actions, it is time to execute them. We deliberately
added both of them as Custom Actions without sequence so that we can trigger them as Dialog
events.
Now, we will execute them when our custom Dialog is initialized, so we need to add
the two Custom Actions as “Ini Events”.
- Go to the Dialogs Page page
- Select the custom “CheckListDlg”
- Add the following two events:

That’s it! The two custom actions will get triggered when the custom CheckList dialog
is initialized.
Keep in mind that you can use a similar approach if you need to populate a ComboBox.
You only have to: – Replace the ListBox control with a ComboBox control – Use AI_COMBOBOX_DATA
property instead of AI_LISTBOX_DATA – Use PopulateComboBox custom action instead of
PopulateListBox
We hope you found this how-to article useful. Let us know if you have any questions
and what articles you would like to see in the future.
Заранее благодарю за вашу помощь.
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form = New-Object System.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(460,350)
$Form.Text ="Pass info"
$Form.AutoSize = $false
$Form.MaximizeBox = $false
$Form.MinimizeBox = $true
$Form.BackColor = "#c08888"
$Form.ShowIcon = $true
$Form.SizeGripStyle = [System.Windows.Forms.SizeGripStyle]::Hide
$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen"
$Form.Opacity = 1.0
$Form.TopMost = $false
############################################## Function start ##############################################
function Info {
$wks=$InputBox.text;
Write-Host $wks
$regex1 = "[^-a-zA-Z0-9_#.!@]+"
$regex2 = "[^-а-яА-Я0-9_#.!@]+"
If($wks -match $regex2) {
$Result1=Get-ADUser -identity $wks -Properties * | select CN -ExpandProperty CN
$outputBox.text=$Result1
$Result2=Get-ADUser -identity $wks -Properties * | select PasswordLastset -ExpandProperty PasswordLastset
$outputBox2.text=$Result2
}
If($wks -match $regex1) {
$wks2 = "$wks*"
Write-Host $wks2
$Result3=Get-AdUser -Filter 'name -Like $wks2' | Select Name -expandproperty Name| Sort Name | fl | out-string
Write-Host $Result3
$ListBox.text = $Result3
}
}
############################################## End Function ##############################################
############################################## GroupBox ##############################################
$groupBox = New-Object System.Windows.Forms.GroupBox
$groupBox.Location = New-Object System.Drawing.Size(10,230)
$groupBox.size = New-Object System.Drawing.Size(280,80)
$groupBox.text = "Info:"
$Form.Controls.Add($groupBox)
$FormLabel1 = New-Object System.Windows.Forms.Label
$FormLabel1.Text = "User AD:"
$FormLabel1.ForeColor = "#3009f1"
$FormLabel1.Font = "Microsoft Sans Serif,8"
$FormLabel1.Location = New-Object System.Drawing.Point(10,10)
$FormLabel1.AutoSize = $true
$Form.Controls.Add($FormLabel1)
$FormLabel2 = New-Object System.Windows.Forms.Label
$FormLabel2.Text = "ФИО:"
$FormLabel2.Location = New-Object System.Drawing.Point(10,25)
$FormLabel2.ForeColor = "#3009f1"
$FormLabel2.Font = "Microsoft Sans Serif,8"
$FormLabel2.AutoSize = $true
$groupBox.Controls.Add($FormLabel2)
$FormLabel3 = New-Object System.Windows.Forms.Label
$FormLabel3.Text = "Дата:"
$FormLabel3.Location = New-Object System.Drawing.Point(10,47)
$FormLabel3.ForeColor = "#3009f1"
$FormLabel3.Font = "Microsoft Sans Serif,8"
$FormLabel3.AutoSize = $true
$groupBox.Controls.Add($FormLabel3)
############################################## End GroupBox ##############################################
############################################ InputBox and OutputBox #########################################
$InputBox = New-Object System.Windows.Forms.TextBox
$InputBox.Location = New-Object System.Drawing.Size(65,5)
$InputBox.Size = New-Object System.Drawing.Size(150,20)
$Form.Controls.Add($InputBox)
$outputBox = New-Object System.Windows.Forms.TextBox
$outputBox.Location = New-Object System.Drawing.Size(80,20)
$outputBox.Size = New-Object System.Drawing.Size(180,20)
$outputBox.ReadOnly = $True
$groupBox.Controls.Add($outputBox)
$outputBox2 = New-Object System.Windows.Forms.TextBox
$outputBox2.Location = New-Object System.Drawing.Size(80,42)
$outputBox2.Size = New-Object System.Drawing.Size(180,42)
$outputBox2.ReadOnly = $True
$groupBox.Controls.Add($outputBox2)
############################################ End InputBox and OutputBox #########################################
############################################## ListBox ##############################################
$ListBox = New-Object System.Windows.Forms.TextBox
$ListBox.Location = New-Object System.Drawing.Size(65,30)
$ListBox.Size = New-Object System.Drawing.Size(220,200)
$ListBox.MultiLine = $True #declaring the text box as multi-line
$ListBox.AcceptsReturn = $true
$ListBox.ScrollBars = "Vertical"
$ListBox.AcceptsTab = $true
$ListBox.WordWrap = $True
$ListBox.ReadOnly = $True
$Form.Controls.Add($ListBox)
############################################## End ListBox ##############################################
############################################## search in Russian and in English ##############################################
$regex1 = "[^-a-zA-Z0-9_#.!@]+"
$regex2 = "[^-а-яА-Я0-9_#.!@]+"
$TestName = "Mouse" # Cat или кот
If($TestName -match $regex1){echo "English '$TestName'"}
If($TestName -match $regex2){echo "Русский '$TestName'"}
get-aduser -filter 'name -like "*" ' | select name -expandproperty name
############################################## End search in Russian and in English ##############################################
############################################## Button ##############################################
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(310,20)
$Button.Size = New-Object System.Drawing.Size(110,80)
$Button.Text = "Загрузить данные"
$Button.BackColor = "#d7f705"
$Button.Add_Click({Info})
$Form.Controls.Add($Button)
############################################## End Button ##############################################
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()


