Product: PowerShell Studio 2024 (64 Bit)
Build: v5.8.237
OS: Windows 10.0.14393
PS Version: 5.1.14393.0, 7.4.1
Using powershell core 7.4.1, when I run the app via Run button app works fine, powershell-core windows logs records this event:
Changing back from Powershell7 to Powershell5 exe works fine.
Please advise. Happy to send you a test project to reproduce error.
@echo off&cls
setlocal enabledelayedexpansion
set working_directory=%~dp0
if %working_directory% NEQ %cd% (
set working_directory=%cd%
)
call chooser.bat :: Активируем выбор файла
set filename=!chose!
set "filename=%filename:~0,-12%" :: обрезка
echo Path to file %filename%
pauseКод для выбора файла.
<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
set "chose=%%~I"
echo !chose!
)
goto :EOF
: end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Program executable (program.exe)|program.exe"
$f.ShowHelp = $true
$f.Multiselect = $false
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName } I’m using powershell core 7.4.2 to run an own .Net module
[Reflection.Assembly]::LoadFile("C:\test\test.dll")
[Some.NameSpace.ClassName]::DoSth('...')If test.dll is compiled for .Net Framework 4.8 this works as expected.
If test.dll is compiled for .Net 8.0 this fails. Fiddling around with Add-Type reveals a ReflectionTypeLoadException. Some parts of the assembly are missing
try
{ Add-Type -Path "C:\test\test.dll"
}
catch [System.Reflection.ReflectionTypeLoadException]
{ $e = $PSItem.Exception $e.LoaderExceptions
}None of the listed assemblies in LoaderExceptions are used in my code (e.g. System.Text.RegularExpressions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) but more of interest is “System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” which indicates to me that basically .Net 8 is not loaded at all.
I did some more tests by adding the assemblies in question System.Runtime.dll, System.Private.CoreLib.dll, System.Text.RegularExpressions.dll but gave up after the error that
“System.Object” of the assembly “System.Private.CoreLib” can not be found.
test.dll does not include fancy usings:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Win32;
namespace Some.NameSpace
{ public static class ClassName { public static void DoSth(string fileName) { } }
}What am I doing wrong?
Настал тот момент когда необходимо уходить от всех зарубежных программ удаленного подключения, во всяком случае у нас в компании. Посмотрев отечественные аналоги мы пришли в ужас от стоимости и качества работы ПО. Поразмыслив какой функционал нам необходим для подключения 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 файл


