How to send keys to GUICtrl in remote desktop? - user-interface

I want to send Windows + R to my GUICtrl using AutoIt. When I do Send("#r") it works on my computer but not in remote desktop. I want to do it in the RDP session.
Code :
$host = "" ;<<<<<<< enter here the host name or ip address
$hGUI = GUICreate("Terminal server", 900, 700, -1, -1, $WS_OVERLAPPEDWINDOW + $WS_CLIPSIBLINGS + $WS_CLIPCHILDREN)
$oRDP = ObjCreate("MsTscAx.MsTscAx.2")
$oRDP_Ctrl = GUICtrlCreateObj($oRDP, 0, 0, 900, 700)
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetStyle($oRDP_Ctrl, $WS_VISIBLE)
$oRDP.DesktopWidth = 900
$oRDP.DesktopHeight = 700
$oRDP.Fullscreen = False
$oRDP.ColorDepth = 16
$oRDP.AdvancedSettings3.SmartSizing = True
$oRDP.Server = $host
$oRDP.UserName = "" ;<<<<<<< enter here the user name
$oRDP.Domain = ""
$oRDP.AdvancedSettings2.ClearTextPassword = ""
$oRDP.ConnectingText = "Connecting to " & $host
$oRDP.DisconnectedText = "Disconnected from " & $host
$oRDP.StartConnected = True
$oRDP.Connect()
GUISetState(#SW_SHOW, $hGUI)
$oShel = ObjCreate("shell.application")
$oShel_Ctrl = GUICtrlCreateObj($oShel, 0, 0, 900, 700)
GUICtrlSetStyle($oShel_Ctrl, $WS_VISIBLE)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
$oRDP.Disconnect()
Exit
EndSwitch

You will want to use the special shortcut key for use when connected via RDP. You can find a list here: Remove Desktop Services Shortcut Keys
Try sending ALT+HOME:
Send("{ALT}{HOME}")

I found the solution. I use PsExec.exe, it's easier !
PS : Don't forget the session's ID after options. Without it, PsExec will works but only in processes and will not make a window

Related

Execute PowerShell GUI locally but send output over the network

I am using the excellent Chrome-Kiosk script from https://github.com/alex-tomin/Tomin.Tools.KioskMode and it works great. I have modified it for our display boards at work and we use it flawlessly with 11 screens.
I wanted to modify it to make a single screen launcher, so I can open a small GUI box, enter the URL to display, and then the screen number that it should display on. I have created a small script and it works perfectly on my local machine. What I want to do is open the GUI on my screen and then send the two variables over the network to the display PC on the network. I had hoped that I would be able to do this with remote execution as found here: https://www.howtogeek.com/117192/how-to-run-powershell-commands-on-remote-computers/, but no luck.
Here is the GUI code:
function button ($title,$mailbx, $WF, $TF) {
[void][System.Reflection.Assembly]::LoadWithPartialName( "System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName( "Microsoft.VisualBasic")
$form = New-Object "System.Windows.Forms.Form";
$form.Width = 500;
$form.Height = 150;
$form.Text = $title;
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
$textLabel1 = New-Object "System.Windows.Forms.Label";
$textLabel1.Left = 25;
$textLabel1.Top = 15;
$textLabel1.Text = $mailbx;
$textLabel2 = New-Object "System.Windows.Forms.Label";
$textLabel2.Left = 25;
$textLabel2.Top = 50;
$textLabel2.Text = $WF;
$textBox1 = New-Object "System.Windows.Forms.TextBox";
$textBox1.Left = 150;
$textBox1.Top = 10;
$textBox1.width = 200;
$textBox2 = New-Object "System.Windows.Forms.TextBox";
$textBox2.Left = 150;
$textBox2.Top = 50;
$textBox2.width = 200;
$defaultValue = ""
$textBox1.Text = $defaultValue;
$textBox2.Text = $defaultValue;
$button = New-Object "System.Windows.Forms.Button";
$button.Left = 360;
$button.Top = 85;
$button.Width = 100;
$button.Text = "Ok";
$eventHandler = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
$form.Close();
};
$button.Add_Click($eventHandler) ;
# Add controls to all the above objects defined
$form.Controls.Add($button);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textLabel3);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$form.Controls.Add($textBox3);
$ret = $form.ShowDialog();
return $textBox1.Text, $textBox2.Text#, $textBox3.Text
}
$return= button "Monitoring Screen Selector" "Enter URL" "Enter Screen # from 1 to 11" #"Target Folder"
$return[0]
$return[1]
The first part of the script is the GUI, it passes $return[0] and $return[1] into the second part of the script which is below:
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$chromeArguments = '--new-window'
# if Window not moved (especially on machine start) - try increasing the delay.
$ChromeStartDelay = 3
Set-Location $PSScriptRoot
. .\HelperFunctions.ps1
# Kill all running instances
# &taskkill /im chrome* /F
Chrome-Kiosk $return[0] -MonitorNum $return[1]
So the GUI should open on the local PC, then send $return[0] and $return[1] to the computer with all of the displays plugged into it so that the second part of the script can receive those two inputs from the GUI and then activate the screen and URL.
The idea as that during an incident or event that isn't covered by our normal screens, we can throw a web page up there until it is resolved, then close it manually afterwards (unless somebody knows how to catch the PID of a specific Chrome instance, which I very much doubt, so that it can be terminated somehow)
Any hints on how I could do this?
Ok, so here is what I have done to make this work. I have created server end scripts that check a folder for 2 specific files, and once it sees them it sends that data to the main script that is expecting a monitor number and a URL. Hope somebody finds this useful.
You will need to go and download the original Chrome-Kiosk from https://alextomin.wordpress.com/2015/04/10/kiosk-mode-in-windows-chrome-on-multiple-displays/
SERVER SCRIPTS
I have put these into a folder called c:\scripts\ICVT
looper.PS1 - This will run constantly
Set-Location -Path C:\scripts\ICVT
while ($true) {
.\file_checker.ps1;
}
file_checker.PS1 - This is the script that looper runs. file_checker scans the folder for web.txt and mon.txt . Both must be present for the rest of the script to execute.
#Checks folder for web.txt and mon.txt . Both must be present for the rest of the
script to execute
Set-Location -Path C:\scripts\ICVT
$a = Test-Path web.txt
$b = Test-Path mon.txt
IF (($a -and $b -eq $True)) {
.\launcher.ps1
}
else {
Write-Host "Scanning For Files"
}
Start-Sleep -Seconds 5
launcher.PS1 - This is just a modified version of the original script
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
$chromeArguments = '--new-window'
$web = (Get-Content -Path web.txt)
$mon = (Get-Content -Path mon.txt)
# if Window not moved (especially on machine start) - try increasing the delay.
$ChromeStartDelay = 5
Set-Location $PSScriptRoot
. .\HelperFunctions.ps1
Chrome-Kiosk $web -MonitorNum $mon
#Delete parameters after use
Start-Sleep -Seconds 5
del web.txt
del mon.txt
CLIENT SIDE
menu.PS1 - If you are wanting to push a specific screen to the display computer over the network then setup Network Path, but if you are connected to the local PC then Local Path is the one to setup. As long as looper is able to see the folder then it will work. There is a little logic in the menu so that the script wont execute if you close the window without putting in any details. (if you run launcher with no parameters it still executes chrome and sends it to a screen that is out of the array normally number 2 for some reason)
#################Local Path###################
Set-Location -Path c:\scripts\ICVT
#################Network Path#################
#Set-Location -Path \\somecomputer\c$\scripts\ICVT
function button ($title,$mailbx, $WF, $TF) {
###################Load Assembly for creating form & button######
[void][System.Reflection.Assembly]::LoadWithPartialName( “System.Windows.Forms”)
[void][System.Reflection.Assembly]::LoadWithPartialName( “Microsoft.VisualBasic”)
#####Define the form size & placement
$form = New-Object “System.Windows.Forms.Form”;
$form.Width = 500;
$form.Height = 150;
$form.Text = $title;
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;
##############Define text label1
$textLabel1 = New-Object “System.Windows.Forms.Label”;
$textLabel1.Left = 25;
$textLabel1.Top = 15;
$textLabel1.Text = $mailbx;
##############Define text label2
$textLabel2 = New-Object “System.Windows.Forms.Label”;
$textLabel2.Left = 25;
$textLabel2.Top = 50;
$textLabel2.Text = $WF;
##############Define text label3
#$textLabel3 = New-Object “System.Windows.Forms.Label”;
#$textLabel3.Left = 25;
#$textLabel3.Top = 85;
#$textLabel3.Text = $TF;
############Define text box1 for input
$textBox1 = New-Object “System.Windows.Forms.TextBox”;
$textBox1.Left = 150;
$textBox1.Top = 10;
$textBox1.width = 200;
############Define text box2 for input
$textBox2 = New-Object “System.Windows.Forms.TextBox”;
$textBox2.Left = 150;
$textBox2.Top = 50;
$textBox2.width = 200;
############Define text box3 for input
#$textBox3 = New-Object “System.Windows.Forms.TextBox”;
#$textBox3.Left = 150;
#$textBox3.Top = 90;
#$textBox3.width = 200;
#############Define default values for the input boxes
$defaultValue = “”
$textBox1.Text = $defaultValue;
$textBox2.Text = $defaultValue;
#$textBox3.Text = $defaultValue;
#############define OK button
$button = New-Object “System.Windows.Forms.Button”;
$button.Left = 360;
$button.Top = 85;
$button.Width = 100;
$button.Text = “Ok”;
############# This is when you have to close the form after getting values
$eventHandler = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
#$textBox3.Text;
$form.Close();};
$button.Add_Click($eventHandler) ;
#############Add controls to all the above objects defined
$form.Controls.Add($button);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textLabel3);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$form.Controls.Add($textBox3);
$ret = $form.ShowDialog();
#################return values
return $textBox1.Text, $textBox2.Text#, $textBox3.Text
}
$return= button “Monitoring Screen Selector” “Enter URL” “Enter Screen # from 1 to 11” #“Target Folder”
if ($return[0] -ne "") {
$return[0] > web.txt
}
if ($return[0] -eq "") {
exit
}
if ($return[1] -ne "") {
$return[1] > mon.txt
}
if ($return[0] -eq "") {
exit
}

rdp session terminal server sendKeys

I don't know how can I send "windows + r" in order to open the small window (execute ...) to the terminal serveur.. Anybody can help me ? I tried Send("#r") but it doesn't work
$host = "" ; <---- IP
$hGUI = GUICreate("Terminal Serveur", 952, 675, -1, -1, $WS_OVERLAPPEDWINDOW + $WS_CLIPSIBLINGS + $WS_CLIPCHILDREN)
$oRDP = ObjCreate("MsTscAx.MsTscAx.2")
$oRDP_Ctrl = GUICtrlCreateObj($oRDP, 64, 44, 800, 600)
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetStyle($oRDP_Ctrl , $WS_VISIBLE)
$oRDP.DesktopWidth = 800
$oRDP.DesktopHeight = 600
$oRDP.Fullscreen = False
$oRDP.ColorDepth = 16
$oRDP.AdvancedSettings3.SmartSizing = True
$oRDP.Server = $host
$oRDP.UserName = "" ; <--- Username
$oRDP.Domain = ""
$oRDP.AdvancedSettings2.ClearTextPassword = "" ; <--- Password
$oRDP.ConnectingText = "Connecting to " & $host
$oRDP.DisconnectedText = "Disconnected from " & $host
$oRDP.StartConnected = True
$oRDP.Connect()
$oShel = ObjCreate("shell.application")
$oShel_Ctrl = GUICtrlCreateObj($oShel, 64, 44, 800, 600)
GUICtrlSetStyle($oShel_Ctrl , $WS_VISIBLE)
GUISetState(#SW_SHOW, $hGUI)
Send ("#r") !!!!
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
$oRDP.Disconnect()
Exit
EndSwitch
Did u try to do it with ShellExecute instead of opening the window first?
//Edit I just saw tht u asked the question before and tht u want to run the command at the other computer

How to use PixelSearch() on inactive windows?

Because of the $hwnd parameter I assume PixelSearch() should work on an inactive window but I can't make it do so. When another window is put in front of the one to search, it fails.
My script :
$hwnd = WinGetHandle("[CLASS:MSPaintApp]")
$Cor = PixelSearch(0, 0, #DesktopWidth, #DesktopHeight, 0x39B6EF, 0, 1, $hwnd)
If Not #error Then
MouseMove($Cor[0], $Cor[1])
Else
MsgBox(0, "", #error)
EndIf
How can I make this work on an inactive window?
Simple fix of making sure that the window you want to search on is active (If I read the question correctly). The WinActive checks to see if the window is active, and if it is 0 (not active). Then, we active the window using WinActivate.
Local $hwnd, $Cor
$hwnd = WinGetHandle("[CLASS:MSPaintApp]")
If WinActive($hwnd) = 0 Then
WinActivate($hwnd)
EndIf
$Cor = PixelSearch(0, 0, #DesktopWidth, #DesktopHeight, 0x39B6EF, 0, 1, $hwnd)
If Not #error Then
MouseMove($Cor[0], $Cor[1])
Else
MsgBox(0, "", #error)
EndIf

Button = Website Link in AutoIT

I have made a button in AutoIT for this program we are making for work we will call it $okmystery and I want $okmystery to like to my company website. Here is a snippet of the code I have so far:
Dim $msg
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okbutton
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
; Take Screen Shots and Logs
ScreenShotAndLogs()
; Compress Artifacts
If FileExists( $ZIPFILEPATH ) Then FileDelete( $ZIPFILEPATH )
_Zip_Create( $ZIPFILEPATH )
_Zip_AddFolderContents( $ZIPFILEPATH, $OUTPUTROOT )
DeleteOriginals()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;------------ Screen Shot
Case $msg = $okshot
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
ScreenShot()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;----------------------------------
$okmystery = ShellExecute ("basic")
Run("Http://www.IT-Networks.org")
Case Default
; Do Nothing
EndSelect
WEnd
Exit( 0 )
It looks like you need to change the "$okmystery" case statement to match the other case statements (if those are all working like they're supposed to).
You can then try to ShellExecute() the url.
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
Here's a working example of a GUI with a button that opens your company website in your default web browser:
#include <GUIConstantsEx.au3>
Global $Button_1, $msg
GUICreate("Test GUI Button")
$okmystery = GUICtrlCreateButton("okmystery Button", 10, 30, 100)
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
EndSelect
WEnd

Best way to wrap rsync progress in a gui?

I use rsync to synchronize files to Windows clients in a server agnostic way. What methods are available to send the progress of rsync to the parent process for display in a gui progress bar?
I imagine two or three choices exist. (1) Watch STDOUT (2) Watch rsync.exe log file, similar to unix tail (3) Watch rsync console output in memory.
Which one is best/preferred?
For this type of tasks, I use my own AutoIt script (freeware, Windows only). The script redirects the standard output into a graphical window, displaying it with the ability to scroll back, etc (very useful in long processes like XCOPYs / PKZIPs to check if any error did happen).
I use AutoIt because it's free, very easy to use, and can compile quickly into an .EXE. I think it's an excellent alternative to a complete programming language for this type of tasks. The downside is that it's for Windows only.
$sCmd = "DIR E:\*.AU3 /S" ; Test command
$nAutoTimeout = 10 ; Time in seconds to close window after finish
$nDeskPct = 60 ; % of desktop size (if percent)
; $nHeight = 480 ; height/width of the main window (if fixed)
; $nWidth = 480
$sTitRun = "Executing process. Wait...." ;
$sTitDone = "Process done" ;
$sSound = #WindowsDir & "\Media\Ding.wav" ; End Sound
$sButRun = "Cancel" ; Caption of "Exec" button
$sButDone = "Close" ; Caption of "Close" button
#include <GUIConstants.au3>
#include <Constants.au3>
#Include <GuiList.au3>
Opt("GUIOnEventMode", 1)
if $nDeskPct > 0 Then
$nHeight = #DesktopHeight * ($nDeskPct / 100)
$nWidth = #DesktopWidth * ($nDeskPct / 100)
EndIf
If $CmdLine[0] > 0 Then
$sCmd = ""
For $nCmd = 1 To $CmdLine[0]
$sCmd = $sCmd & " " & $CmdLine[$nCmd]
Next
; MsgBox (1,"",$sCmd)
EndIf
; AutoItSetOption("GUIDataSeparatorChar", Chr(13)+Chr(10))
$nForm = GUICreate($sTitRun, $nWidth, $nHeight)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseForm")
$nList = GUICtrlCreateList ("", 10, 10, $nWidth - 20, $nHeight - 50, $WS_BORDER + $WS_VSCROLL)
GUICtrlSetFont (-1, 9, 0, 0, "Courier New")
$nClose = GUICtrlCreateButton ($sButRun, $nWidth - 100, $nHeight - 40, 80, 30)
GUICtrlSetOnEvent (-1, "CloseForm")
GUISetState(#SW_SHOW) ;, $nForm)
$nPID = Run(#ComSpec & " /C " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD)
; $nPID = Run(#ComSpec & " /C _RunErrl.bat " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD) ; # Con ésto devuelve el errorlevel en _ERRL.TMP
While 1
$sLine = StdoutRead($nPID)
If #error Then ExitLoop
If StringLen ($sLine) > 0 then
$sLine = StringReplace ($sLine, Chr(13), "|")
$sLine = StringReplace ($sLine, Chr(10), "")
if StringLeft($sLine, 1)="|" Then
$sLine = " " & $sLine
endif
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
EndIf
Wend
$sLine = " ||"
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
GUICtrlSetData ($nClose, $sButDone)
WinSetTitle ($sTitRun, "", $sTitDone)
If $sSound <> "" Then
SoundPlay ($sSound)
EndIf
$rInfo = DllStructCreate("uint;dword") ; # LASTINPUTINFO
DllStructSetData($rInfo, 1, DllStructGetSize($rInfo));
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
$nLastInput = DllStructGetData($rInfo, 2)
$nTime = TimerInit()
While 1
If $nAutoTimeout > 0 Then
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
If DllStructGetData($rInfo, 2) <> $nLastInput Then
; Tocó una tecla
$nAutoTimeout = 0
EndIf
EndIf
If $nAutoTimeout > 0 And TimerDiff ($nTime) > $nAutoTimeOut * 1000 Then
ExitLoop
EndIf
Sleep (100)
Wend
Func CloseForm()
Exit
EndFunc
.NET has a pretty straight forward way to read and watch STDOUT.
I guess this would be the cleanest way, since it is not dependent on any external files, just the path to rsync. I would not be too surprised if there is a wrapper library out there either. If not, write and open source it :)
I've built my own simple object for this, I get a lot of reuse out of it, I can wrap it with a cmdline, web page, webservice, write output to a file, etc---
The commented items contain some rsync examples--
what I'd like to do sometime is embed rsync (and cygwin) into a resource & make a single .net executable out of it--
Here you go:
Imports System.IO
Namespace cds
Public Class proc
Public _cmdString As String
Public _workingDir As String
Public _arg As String
Public Function basic() As String
Dim sOut As String = ""
Try
'Set start information.
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 192.168.42.6::cdsERP /cygdrive/s/cdsERP_rsync/gwy")
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 10.1.1.6::user /cygdrive/s/cdsERP_rsync/gws/user")
'Dim startinfo As New ProcessStartInfo("C:\windows\system32\cscript", "//NoLogo c:\windows\system32\prnmngr.vbs -l")
Dim si As New ProcessStartInfo(_cmdString, _arg)
si.UseShellExecute = False
si.CreateNoWindow = True
si.RedirectStandardOutput = True
si.RedirectStandardError = True
si.WorkingDirectory = _workingDir
' Make the process and set its start information.
Dim p As New Process()
p.StartInfo = si
' Start the process.
p.Start()
' Attach to stdout and stderr.
Dim stdout As StreamReader = p.StandardOutput()
Dim stderr As StreamReader = p.StandardError()
sOut = stdout.ReadToEnd() & ControlChars.NewLine & stderr.ReadToEnd()
'Dim writer As New StreamWriter("out.txt", FileMode.CreateNew)
'writer.Write(sOut)
'writer.Close()
stdout.Close()
stderr.Close()
p.Close()
Catch ex As Exception
sOut = ex.Message
End Try
Return sOut
End Function
End Class
End Namespace
Check out DeltaCopy. It is a Windows GUI for rsync.
Check NAsBackup Its open source software that give Windows user Rsync GUI using Watch STDOUT.

Resources