Working in an IT outsourcing company as the head of the 3rd support line, I thought about how to automate the connection of employees via RDP, via VPN to the servers of dozens of clients.
Plates with addresses, passwords and other server settings, of course, are good, but finding a client and driving in addresses with accounts takes quite a lot of time.
Keeping all VPN connections on Windows is not a good idea, and when you reinstall it, creating VPNs is also not a pleasure.
Plus, in most cases, you need to establish a VPN connection to the client without using a gateway. so as not to drive all Internet traffic through the client.
The task, moreover, is complicated by the fact that some clients have pptp, some have l2tp, some have multiple subnets, tunnels, etc.
As a result, to begin with, scripts were written in Powershell for each client, but later, having learned that Winforms can be used in Powershell, they were reborn into an application written using the same Powershell.
Before writing this script application, I was not involved in programming at all, except that 20 years ago I wrote something on VBS in MS Excel and MS Access, therefore I do not guarantee the beautifulness of the code and accept criticism from experienced programmers on how to make it more beautiful.
Powershell, starting with Windows 8 and, of course, Windows 10, has a great opportunity to create VPN connections with the Add-VpnConnection command and specify which routes to use with these connections with the Add-VpnConnectionRoute command to use VPN without a gateway.
Based on these commands, this application was created. But first things first.
β (, , ) , .
Google Disk , - , .
, ( Google Disk) :
Number; Name; VPNname; ServerAddress; RemoteNetwork; VPNLogin; VPNPass; VPNType; l2tpPsk; RDPcomp; RDPuser; RDPpass; DefaultGateway; PortWinbox; WinboxLogin; WinboxPwd; Link; Inform
- CSV, CSV ( comma)
VPNname β VPN
ServerAddress β VPN
RemoteNetwork β , Β«;Β»
VPNLogin; VPNPass β VPN
VPNType - VPN ( pptp l2tp)
l2tpPsk β PSK l2tp, pptp
RDPcomp β RPD
RDPuser; RDPpass β RPD
DefaultGateway TRUE FALSE , Β« Β» . 90% = FALSE
PortWinbox; WinboxLogin; WinboxPwd β , Winbox, Mikrotik)
Link β , , Google, ,
Inform β
Number |
Name |
VPNname |
ServerAddress |
RemoteNetwork |
VPNLogin |
VPNPass |
VPNType |
l2tpPsk |
RDPcomp |
RDPuser |
RDPpass |
DefaultGateway |
PortWinbox |
WinboxLogin |
WinboxPwd |
Link |
Inform |
1 |
1 |
Test1 |
a.b.c.d |
192.168.10.0/24: 10.10.0.0/24 |
vpnuser |
passWord |
pptp |
none |
192.168.10.1 |
user |
passWord |
TRUE |
8291 |
Admin |
Admin |
|
|
2 |
2 |
Test2 |
e.f.j.k |
192.168.2.0/24 |
vpnuser |
passWord |
l2tp |
KdoSDtdP |
192.168.2.1 |
user |
passWord |
FALSE |
8291 |
Admin |
Admin |
|
|
Screenshot of a running application with overwritten data:
The following is a listing of the application with comments and explanations. If interested, but not clear, ask questions, I will try to comment
function Get-Clients # Google Drive
{
param
(
[string]$google_url = ""
)
[string]$xlsFile = $google_url
$csvFile = "$env:temp\clients.csv"
$Comma = ','
Invoke-WebRequest $xlsFile -OutFile $csvFile
$clients = Import-Csv -Delimiter $Comma -Path "$env:temp\clients.csv"
Remove-Item -Path $csvFile
return $clients
}
function Main {
<#
,
#>
Param ([String]$Commandline)
# . ,
$Global:Clients = $null
$Global:Current
$Global:CurrentRDPcomp
$Global:google_file = "https://docs.google.com/spreadsheets/d/1O-W1YCM4x3o5W1w6XahCJZpkTWs8cREXVF69gs1dD0U/export?format=csv" # csv-
$Global:Clients = Get-Clients ($Global:google_file) #
# Winbox64
$download_url = "https://download.mikrotik.com/winbox/3.27/winbox64.exe"
$Global:local_path = "$env:temp\winbox64.exe"
If ((Test-Path $Global:local_path) -ne $true)
{
$WebClient = New-Object System.Net.WebClient
$WebClient.DownloadFile($download_url, $Global:local_path)
}
# VPN ( )
foreach ($item in get-vpnconnection | where { $_.ConnectionStatus -eq "Connected" })
{
Rasdial $item.Name /disconnect
}
# , ,
get-vpnconnection | where { $_.Name -match "tmp" } | Remove-VpnConnection -Force
#
Show-MainForm_psf
}
#,
function Show-MainForm_psf
{
[void][reflection.assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
[void][reflection.assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
#
[System.Windows.Forms.Application]::EnableVisualStyles()
$form = New-Object 'System.Windows.Forms.Form'
$statusbar1 = New-Object 'System.Windows.Forms.StatusBar'
$groupboxTools = New-Object 'System.Windows.Forms.GroupBox'
$buttonPing = New-Object 'System.Windows.Forms.Button'
$button = New-Object 'System.Windows.Forms.Button'
$buttonWindox = New-Object 'System.Windows.Forms.Button'
$button = New-Object 'System.Windows.Forms.Button'
$buttonPingAll = New-Object 'System.Windows.Forms.Button'
$groupboxRDP = New-Object 'System.Windows.Forms.GroupBox'
$comboboxRDP = New-Object 'System.Windows.Forms.ComboBox'
$textboxRDPLogin = New-Object 'System.Windows.Forms.TextBox'
$textboxRdpPwd = New-Object 'System.Windows.Forms.TextBox'
$buttonRDP = New-Object 'System.Windows.Forms.Button'
$groupboxVPN = New-Object 'System.Windows.Forms.GroupBox'
$buttonVPN = New-Object 'System.Windows.Forms.Button'
$buttonVPN = New-Object 'System.Windows.Forms.Button'
$checkbox = New-Object 'System.Windows.Forms.CheckBox'
$richtextboxinfo = New-Object 'System.Windows.Forms.RichTextBox'
$listbox_clients = New-Object 'System.Windows.Forms.ListBox'
$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'
#----------------------------------------------
#
#----------------------------------------------
$form_Load = {
# ( )
$richtextboxinfo.Clear()
$Global:Clients | ForEach-Object {
[void]$listbox_clients.Items.Add($_.Name)
} #
}
$listbox_clients_SelectedIndexChanged = {
# listbox_clients (, Google)
$statusbar1.Text = ' : ' + $listbox_clients.SelectedItem.ToString() #
$Global:Current = $Global:Clients.Where({ $_.Name -eq $listbox_clients.SelectedItem.ToString() })
If ($Current.PortWinbox -ne 0) # Winbox , Mikrotik,
{
$buttonWindox.Enabled = $true
$buttonWindox.Text = "Winbox"
}
$VPNname = $Global:Current.VPNname + "-tmp" # VPN "-tmp" ,
switch ($Global:Current.VPNType) # VPN " pptp VPN" " l2tp VPN", VPN, " VPN"
{
"pptp" {
$buttonVPN.Enabled = $true
$buttonVPN.Text = " pptp VPN"
}
"l2tp" {
$buttonVPN.Enabled = $true
$buttonVPN.Text = " l2tp VPN"
}
DEFAULT
{
$buttonVPN.Enabled = $false
$buttonVPN.Text = " VPN"
}
}
switch ($Global:Current.DefaultGateway) # , " -"
{
"FALSE"
{ $checkbox.Checked = $false }
""
{ $checkbox.Checked = $false }
"TRUE"
{ $checkbox.Checked = $true }
""
{ $checkbox.Checked = $true }
DEFAULT
{ $checkbox.Checked = $false }
}
$VPNStatus = (ipconfig | Select-String $VPNname -Quiet) #, VPN ?
If ($VPNStatus) # , " RDP"
{
$buttonRDP.Enabled = $true
}
else
{
$buttonRDP.Enabled = $false
}
$richtextboxinfo.Clear() #
#
$richtextboxinfo.SelectionColor = 'Black'
$richtextboxinfo.Text = ": " + $Global:Current.Name + [System.Environment]::NewLine + `
" VPN: " + $Global:Current.VPNname + [System.Environment]::NewLine + `
" VPN: " + $Global:Current.VPNType + [System.Environment]::NewLine + `
" : " + $Global:Current.ServerAddress + [System.Environment]::NewLine + `
" : " + $Global:Current.RemoteNetwork + [System.Environment]::NewLine + `
" RDP: " + $Global:Current.RDPcomp + [System.Environment]::NewLine + [System.Environment]::NewLine + `
"DefaultGateway: " + $Global:Current.DefaultGateway + [System.Environment]::NewLine + [System.Environment]::NewLine + `
": " + [System.Environment]::NewLine + $Global:Current.Inform + [System.Environment]::NewLine + `
"Connection '" + $VPNname + "' status is " + $buttonRDP.Enabled + [System.Environment]::NewLine
$richtextboxinfo.AppendText($Global:Current.Link)
$RDPServers = $Global:Current.RDPcomp.Split(';') -replace '\s', '' # RDP
#
$comboboxRDP.Items.Clear()
$comboboxRDP.Text = $RDPServers[0]
foreach ($RDPServer in $RDPServers)
{
$comboboxRDP.Items.Add($RDPServer)
}
# RDP ( , )
$textboxRdpPwd.Text = $Global:Current.RDPpass
$textboxRdpLogin.Text = $Global:Current.RDPuser
} # ,
$buttonWindox_Click = {
# Winbox
If ($Global:Current.PortWinbox -ne 0) # Winbox , Winbox,
{
$runwinbox = "$env:temp\winbox64.exe"
$ServerPort = $Global:Current.ServerAddress + ":" + $Global:Current.PortWinbox
$ServerLogin = " """ + $Global:Current.WinboxLogin + """"
$ServerPass = " """ + $Global:Current.WinboxPwd + """"
$Arg = "$ServerPort $ServerLogin $ServerPass "
Start-Process -filePath $runwinbox -ArgumentList $Arg
}
}
$buttonVPN_Click = {
# VPN
$VPNname = $Global:Current.VPNname + "-tmp" # VPN "-tmp" ,
$richtextboxinfo.Clear() #
$richtextboxinfo.Text = ": " + $Global:Current.Name + [System.Environment]::NewLine
foreach ($item in get-vpnconnection | where { $_.ConnectionStatus -eq "Connected" }) #
{
$richtextboxinfo.Text = $richtextboxinfo.Text + " " + $item.Name + " " + [System.Environment]::NewLine
Rasdial $item.Name /disconnect
}
Remove-VpnConnection $VPNname -Force # ,
$RemoteNetworks = $Global:Current.RemoteNetwork.Split(';') -replace '\s', '' # ;
switch ($Global:Current.VPNType) # VPN pptp l2tp
{
"pptp" {
$richtextboxinfo.Text = $richtextboxinfo.Text + " pptp " + $VPNname + [System.Environment]::NewLine
If ($checkbox.Checked -eq $false) # " -", VPN
{
$Errcon = (Add-VpnConnection -Name $VPNname -ServerAddress $Global:Current.ServerAddress -TunnelType $Global:Current.VPNType -SplitTunneling -Force -RememberCredential -PassThru) # VPN
foreach ($RemoteNetwork in $RemoteNetworks) # VPN
{
$richtextboxinfo.AppendText(' ' + $RemoteNetwork + [System.Environment]::NewLine)
Add-VpnConnectionRoute -ConnectionName $VPNname -DestinationPrefix $RemoteNetwork -PassThru
}
}
else # " -", VPN
{
$Errcon = (Add-VpnConnection -Name $VPNname -ServerAddress $Global:Current.ServerAddress -TunnelType $Global:Current.VPNType -Force -RememberCredential -PassThru)
}
}
"l2tp" {
$richtextboxinfo.Text = $richtextboxinfo.Text + " l2tp " + $Global:Current.VPNname + [System.Environment]::NewLine
If ($checkbox.Checked -eq $false) # " -", VPN
{
$Errcon = (Add-VpnConnection -Name $VPNname -ServerAddress $Global:Current.ServerAddress -TunnelType $Global:Current.VPNType -L2tpPsk $Global:Current.l2tpPsk -SplitTunneling -Force -RememberCredential -PassThru) # VPN
foreach ($RemoteNetwork in $RemoteNetworks) # VPN
{
$richtextboxinfo.AppendText(' ' + $RemoteNetwork + [System.Environment]::NewLine)
Add-VpnConnectionRoute -ConnectionName $VPNname -DestinationPrefix $RemoteNetwork -PassThru
}
}
else # " -", VPN
{
$Errcon = (Add-VpnConnection -Name $VPNname -ServerAddress $Global:Current.ServerAddress -TunnelType $Global:Current.VPNType -L2tpPsk $Global:Current.l2tpPsk -Force -RememberCredential -PassThru)
}
}
}
$richtextboxinfo.AppendText(" " + $Global:Current.VPNType + " " + $VPNname + [System.Environment]::NewLine)
$Errcon = Rasdial $VPNname $Global:Current.VPNLogin $Global:Current.VPNPass # VPN
$richtextboxinfo.Text = $richtextboxinfo.Text + [System.Environment]::NewLine + $Errcon + [System.Environment]::NewLine
If ((ipconfig | Select-String $VPNname -Quiet)) # , , RDP " VPN"
{
$buttonRDP.Enabled = $true
$buttonVPN.Visible = $true
$buttonVPN.Enabled = $true
$statusbar1.Text = $Global:Current.Name + ' '
}
}
$form_FormClosing = [System.Windows.Forms.FormClosingEventHandler]{
# . .
foreach ($item in get-vpnconnection | where { $_.ConnectionStatus -eq "Connected" })
{
$richtextboxinfo.Text = $richtextboxinfo.Text + " " + $item.Name + " " + [System.Environment]::NewLine
Rasdial $item.Name /disconnect
}
$richtextboxinfo.Text = $richtextboxinfo.Text + " " + [System.Environment]::NewLine
get-vpnconnection | where { $_.Name -match "tmp" } | Remove-VpnConnection -Force
# RPD-
$Global:Clients | ForEach-Object {
$term = "TERMSRV/" + $_.RDPcomp
cmdkey /delete:$term
}
}
$buttonRDP_Click = {
# RDP
$RDPcomp = $comboboxRDP.Text
$RDPuser = $textboxRDPLogin.Text
$RDPpass = $textboxRdpPwd.Text
cmdkey /generic:"TERMSRV/$RDPcomp" /user:"$RDPuser" /pass:"$RDPpass"
mstsc /v:$RDPcomp
}
$buttonVPN_Click = {
# VPN
foreach ($item in get-vpnconnection | where { $_.ConnectionStatus -eq "Connected" })
{
$richtextboxinfo.Text = $richtextboxinfo.Text + " " + $item.Name + " " + [System.Environment]::NewLine
Rasdial $item.Name /disconnect
}
$richtextboxinfo.Text = $richtextboxinfo.Text + " " + [System.Environment]::NewLine
get-vpnconnection | where { $_.Name -match "tmp" } | Remove-VpnConnection -Force
$buttonVPN.Visible = $false
$buttonRDP.Enabled = $false
$statusbar1.Text = $Global:Current.Name + ' '
}
$buttonPingAll_Click={
#
$I=0
$richtextboxinfo.Clear()
$richtextboxinfo.SelectionColor = 'Black'
$clientscount = $Global:Clients.count
$Global:Clients | ForEach-Object {
if ((test-connection -Count 1 -computer $_.ServerAddress -quiet) -eq $True)
{
$richtextboxinfo.SelectionColor = 'Green'
$richtextboxinfo.AppendText($_.Name +' ('+ $_.ServerAddress +') ' + [System.Environment]::NewLine)
}
else
{
$richtextboxinfo.SelectionColor = 'Red'
$richtextboxinfo.AppendText($_.Name + ' (' + $_.ServerAddress + ') ( ICMP)' + [System.Environment]::NewLine)
}
$richtextboxinfo.ScrollToCaret()
$I = $I + 1
Write-Progress -Activity "Ping in Progress" -Status "$i clients of $clientscount pinged" -PercentComplete ($i/$clientscount*100)
}
$richtextboxinfo.SelectionColor = 'Black'
Write-Progress -Activity "Ping in Progress" -Status "Ready" -Completed
}
$button_Click={
# Google
$Global:Clients = Get-Clients ($Global:google_file)
$listbox_clients.Items.Clear()
$Global:Clients | ForEach-Object {
[void]$listbox_clients.Items.Add($_.Name)
}
}
$button_Click = {
#
$form.Close()
}
$richtextboxinfo_LinkClicked=[System.Windows.Forms.LinkClickedEventHandler]{
#
Start-Process $_.LinkText.ToString()
}
$buttonPing_Click={
# ip
if ((test-connection -Count 1 -computer $Global:Current.ServerAddress -quiet) -eq $True)
{
$richtextboxinfo.AppendText([System.Environment]::NewLine)
$richtextboxinfo.SelectionColor = 'Green'
$richtextboxinfo.AppendText($Global:Current.Name + ' (' + $Global:Current.ServerAddress + ') ' + [System.Environment]::NewLine)
}
else
{
$richtextboxinfo.AppendText([System.Environment]::NewLine)
$richtextboxinfo.SelectionColor = 'Red'
$richtextboxinfo.AppendText($Global:Current.Name + ' (' + $Global:Current.ServerAddress + ') ( ICMP)' + [System.Environment]::NewLine)
}
}
#----------------------------------------------
#
#----------------------------------------------
#
# form
#
$form.Controls.Add($statusbar1)
$form.Controls.Add($groupboxTools)
$form.Controls.Add($groupboxRDP)
$form.Controls.Add($groupboxVPN)
$form.Controls.Add($richtextboxinfo)
$form.Controls.Add($listbox_clients)
$form.AutoScaleDimensions = '6, 13'
$form.AutoScaleMode = 'Font'
$form.AutoSize = $True
$form.ClientSize = '763, 446'
$form.FormBorderStyle = 'FixedSingle'
$form.MaximizeBox = $False
$form.Name = 'form'
$form.SizeGripStyle = 'Hide'
$form.StartPosition = 'CenterScreen'
$form.Text = ' '
$form.add_FormClosing($form_FormClosing)
$form.add_Load($form_Load)
#
# statusbar1
#
$statusbar1.Location = '0, 424'
$statusbar1.Name = 'statusbar1'
$statusbar1.Size = '763, 22'
$statusbar1.TabIndex = 17
#
# groupboxTools
#
$groupboxTools.Controls.Add($buttonPing)
$groupboxTools.Controls.Add($button)
$groupboxTools.Controls.Add($buttonWindox)
$groupboxTools.Controls.Add($button)
$groupboxTools.Controls.Add($buttonPingAll)
$groupboxTools.Location = '308, 258'
$groupboxTools.Name = 'groupboxTools'
$groupboxTools.Size = '147, 163'
$groupboxTools.TabIndex = 10
$groupboxTools.TabStop = $False
$groupboxTools.Text = 'Tools'
$groupboxTools.UseCompatibleTextRendering = $True
#
# buttonPing
#
$buttonPing.Location = '7, 44'
$buttonPing.Name = 'buttonPing'
$buttonPing.Size = '133, 23'
$buttonPing.TabIndex = 12
$buttonPing.Text = 'Ping'
$buttonPing.UseCompatibleTextRendering = $True
$buttonPing.UseVisualStyleBackColor = $True
$buttonPing.add_Click($buttonPing_Click)
#
# button
#
$button.Location = '7, 125'
$button.Name = 'button'
$button.Size = '133, 23'
$button.TabIndex = 15
$button.Text = ''
$button.UseCompatibleTextRendering = $True
$button.UseVisualStyleBackColor = $True
$button.add_Click($button_Click)
#
# buttonWindox
#
$buttonWindox.Enabled = $False
$buttonWindox.Location = '7, 17'
$buttonWindox.Name = 'buttonWindox'
$buttonWindox.Size = '133, 23'
$buttonWindox.TabIndex = 11
$buttonWindox.Text = 'Windox'
$buttonWindox.UseCompatibleTextRendering = $True
$buttonWindox.UseVisualStyleBackColor = $True
$buttonWindox.add_Click($buttonWindox_Click)
#
# button
#
$button.Location = '7, 98'
$button.Name = 'button'
$button.Size = '133, 23'
$button.TabIndex = 14
$button.Text = ' '
$button.UseCompatibleTextRendering = $True
$button.UseVisualStyleBackColor = $True
$button.add_Click($button_Click)
#
# buttonPingAll
#
$buttonPingAll.Location = '7, 71'
$buttonPingAll.Name = 'buttonPingAll'
$buttonPingAll.Size = '133, 23'
$buttonPingAll.TabIndex = 13
$buttonPingAll.Text = 'Ping All'
$buttonPingAll.UseCompatibleTextRendering = $True
$buttonPingAll.UseVisualStyleBackColor = $True
$buttonPingAll.add_Click($buttonPingAll_Click)
#
# groupboxRDP
#
$groupboxRDP.Controls.Add($comboboxRDP)
$groupboxRDP.Controls.Add($textboxRDPLogin)
$groupboxRDP.Controls.Add($textboxRdpPwd)
$groupboxRDP.Controls.Add($buttonRDP)
$groupboxRDP.Location = '308, 128'
$groupboxRDP.Name = 'groupboxRDP'
$groupboxRDP.Size = '147, 126'
$groupboxRDP.TabIndex = 5
$groupboxRDP.TabStop = $False
$groupboxRDP.Text = 'RDP'
$groupboxRDP.UseCompatibleTextRendering = $True
#
# comboboxRDP
#
$comboboxRDP.FormattingEnabled = $True
$comboboxRDP.Location = '7, 17'
$comboboxRDP.Name = 'comboboxRDP'
$comboboxRDP.Size = '133, 21'
$comboboxRDP.TabIndex = 6
$comboboxRDP.Text = 'IP RDP '
#
# textboxRDPLogin
#
$textboxRDPLogin.Location = '7, 44'
$textboxRDPLogin.Name = 'textboxRDPLogin'
$textboxRDPLogin.Size = '133, 20'
$textboxRDPLogin.TabIndex = 7
$textboxRDPLogin.Text = 'RDP-login'
#
# textboxRdpPwd
#
$textboxRdpPwd.Location = '7, 69'
$textboxRdpPwd.Name = 'textboxRdpPwd'
$textboxRdpPwd.PasswordChar = '*'
$textboxRdpPwd.Size = '133, 20'
$textboxRdpPwd.TabIndex = 8
$textboxRdpPwd.Text = 'RDP-Password'
#
# buttonRDP
#
$buttonRDP.Enabled = $False
$buttonRDP.Location = '7, 94'
$buttonRDP.Name = 'buttonRDP'
$buttonRDP.Size = '133, 20'
$buttonRDP.TabIndex = 9
$buttonRDP.Text = ' RDP'
$buttonRDP.UseCompatibleTextRendering = $True
$buttonRDP.UseVisualStyleBackColor = $True
$buttonRDP.add_Click($buttonRDP_Click)
#
# groupboxVPN
#
$groupboxVPN.Controls.Add($buttonVPN)
$groupboxVPN.Controls.Add($buttonVPN)
$groupboxVPN.Controls.Add($checkbox)
$groupboxVPN.Location = '308, 27'
$groupboxVPN.Name = 'groupboxVPN'
$groupboxVPN.Size = '147, 98'
$groupboxVPN.TabIndex = 1
$groupboxVPN.TabStop = $False
$groupboxVPN.Text = 'VPN'
$groupboxVPN.UseCompatibleTextRendering = $True
#
# buttonVPN
#
$buttonVPN.Enabled = $False
$buttonVPN.Location = '7, 45'
$buttonVPN.Name = 'buttonVPN'
$buttonVPN.Size = '133, 20'
$buttonVPN.TabIndex = 3
$buttonVPN.Text = ' VPN'
$buttonVPN.UseCompatibleTextRendering = $True
$buttonVPN.UseVisualStyleBackColor = $True
$buttonVPN.add_Click($buttonVPN_Click)
#
# buttonVPN
#
$buttonVPN.Enabled = $False
$buttonVPN.Location = '7, 67'
$buttonVPN.Name = 'buttonVPN'
$buttonVPN.Size = '133, 20'
$buttonVPN.TabIndex = 4
$buttonVPN.Text = ' VPN'
$buttonVPN.UseCompatibleTextRendering = $True
$buttonVPN.UseVisualStyleBackColor = $True
$buttonVPN.Visible = $False
$buttonVPN.add_Click($buttonVPN_Click)
#
# checkbox
#
$checkbox.Location = '7, 19'
$checkbox.Name = 'checkbox'
$checkbox.Size = '133, 24'
$checkbox.TabIndex = 2
$checkbox.Text = ' -'
$checkbox.TextAlign = 'MiddleRight'
$checkbox.UseCompatibleTextRendering = $True
$checkbox.UseVisualStyleBackColor = $True
#
# richtextboxinfo
#
$richtextboxinfo.Cursor = 'Default'
$richtextboxinfo.ForeColor = 'WindowText'
$richtextboxinfo.HideSelection = $False
$richtextboxinfo.Location = '461, 27'
$richtextboxinfo.Name = 'richtextboxinfo'
$richtextboxinfo.ReadOnly = $True
$richtextboxinfo.ScrollBars = 'ForcedVertical'
$richtextboxinfo.ShowSelectionMargin = $True
$richtextboxinfo.Size = '290, 394'
$richtextboxinfo.TabIndex = 16
$richtextboxinfo.Text = ''
$richtextboxinfo.add_LinkClicked($richtextboxinfo_LinkClicked)
#
# listbox_clients
#
$listbox_clients.FormattingEnabled = $True
$listbox_clients.Location = '12, 27'
$listbox_clients.Name = 'listbox_clients'
$listbox_clients.Size = '290, 394'
$listbox_clients.TabIndex = 0
$listbox_clients.add_SelectedIndexChanged($listbox_clients_SelectedIndexChanged)
#
$InitialFormWindowState = $form.WindowState
#
$form.add_Load($Form_StateCorrection_Load)
#
$form.add_FormClosed($Form_Cleanup_FormClosed)
#
$form.add_Closing($Form_StoreValues_Closing)
#
return $form.ShowDialog()
}
# !
Main ($CommandLine)
The script can be run as a ps1 script or compiled to exe via ps2exe and used as a full-fledged application
UPD: the script can work directly in Powershell, just run PS as Administrator, copy and paste the script into the PS window