Check if mouse\keyboard is active using Batch or PowerShell - powershell

I have been searching for this for a long time, and can't find one single answer.
Is it possible to check if my mouse or keyboard is in use (the mouse is currently moving or keys are being pressed) using only a Batch or PowerShell script? If yes, how?

As for the mouse movement, you could check the position of the pointer and calculate if there is a change over time.
$p1 = [System.Windows.Forms.Cursor]::Position
Start-Sleep -Seconds 5 # or use a shorter intervall with the -milliseconds parameter
$p2 = [System.Windows.Forms.Cursor]::Position
if($p1.X -eq $p2.X -and $p1.Y -eq $p2.Y) {
"The mouse did not move"
} else {
"The mouse moved"
}
As for the keys, you might want to try a similar technique utilizing the get-keystroke script (which is basically a keylogger).

Related

Is it possible to click a button in an application using Powershell?

i am trying to write a powershell script that checks connectivity thru a continuous ping, if the ping is unsuccessful the script should start a process and when a window is opened have the script click on a specific button, i have done my research and have not found much help other than this
but this is dependant on Actions having schortcuts that's why it doesn't work for me, i would like to know if it's even possible to do this using powershell before i procced with my work.
this is my script so far.
$IP = "192.X.X.X"
$TimeOut = 500
$FailureThreshold = 10
$Ping = New-Object System.Net.NetworkInformation.Ping
Do {
$Result = $Ping.Send($IP,$Timeout)
if ($Result.Status -eq "Success") {
Write-Output "Working as intended."
Exit 0
}
else {
Write-Output "Ping Failed!"
$Failures += 1
}
} until ($Failures -ge $FailureThreshold)
Write-Output "Main DHCP is Down, Starting Backup DHCP Server..."
start-process "C:\Users\XXXX\Desktop\DHCP\dhcpsrv2.5.2\dhcpsrv.exe"
everything works great, i just need to get that button clicked.
and here is a photo of the window that pops up and the button that needs to be clicked.
i got it! Maybe this will help someone.
start-process "C:\Users\XXXX\Desktop\DHCP\dhcpsrv2.5.2\dhcpsrv.exe"
$StartDHCP = New-Object -ComObject wscript.shell;
Sleep 1
$StartDHCP.SendKeys('%C')
where % = ALT
Yes it's possible, u can use an app called Auto-it where u Send a mouse click to a specific button in the Window.
it's explained here in details on the Autoit website
https://www.autoitscript.com/autoit3/docs/functions/ControlClick.htm

Powershell IE Automation- Can't specify textbox by ID or TagName

I am trying to use powershell to enter text into two text boxes. I can enter a value into the first box, but not the second. This is due to the fact that I don't know how to isolate the second textbox as it has the same code as the first text box including things such as ID, Class, TagName, etc.
Below is my code with the URL taken out (due to work). I had initially thought to isolate the second textbox by using -ne on the value of the first since by inputting a value it differentiated the code, however this doesn't seem to work. I am new to coding so my apologies if I'm expressing myself poorly, but any help you could provide would be appreciated.
Here are two text boxes, I can enter a value into the first one using powershell but I am unable to isolate the second text box to enter a value into it. This is due to the two lines of code being identical- See second image
As you can see the two lines of code for input are identical and as such I cannot use GetElementById/TagName/Name to identify which text box I want powershell to enter the value into.
$Web = "URL"
$Internet = New-Object -ComObject InternetExplorer.Application
$Internet.visible = $true
$Internet.Navigate($web)
While($Internet.Busy -eq $true){
Start-Sleep -Seconds 1
}
$Internet.document.getElementById("filterValue").value="Number"
$link = $Internet.Document.getElementsByTagName('a') | where-object {$_.innerText -eq 'Next Prompt'}
$link.click()
While($Internet.Busy -eq $true){
Start-Sleep -Seconds 1
}
**#Question about coding starts here**
$Input = $Internet.Document.IHTMLDocument3_getElementById("filterValue")
$Input.value = "1/1/2020"
While($Internet.Busy -eq $true){
Start-Sleep -Seconds 1
}
$Input2 = $Internet.Document.IHTMLDocument3_getElementById("filterValue") | ? {$_.value -ne "1/1/2020"}
Start-Sleep -Seconds 4
$Input2.value = "1/2/2020"
I checked the image of HTML code and looks like there are some issues with the HTML code.
The ID of the HTML element should be unique. That means there cannot be more than one element that has the same ID on a single web page.
I also notice that the input element has / at the end of it for closing it. There are 2 more closing input tags after it. In HTML, there is no end tag for the Input element. So this is invalid HTML code.
Verify and confirm that you are referring to the correct code for those 2 textboxes. Try to use developer tools to view the HTML for those 2 textboxes.
I suggest you contact the developer of the website and inform them about this issue.

How to prevent input from displaying in console while script is running

I have a script that runs several loops of code and relies on specific input at various phases in order to advance. That functionality is working. My current issue revolves around extraneous input being supplied by the user displaying on screen in the console window wherever I have the cursor position currently aligned.
I have considered ignoring this issue since the functionality of the script is intact, however, I am striving for high standards with the console display of this script, and I would like to know a way to disable all user input period, unless prompted for. I imagine the answer has something to do with being able to command the Input Buffer to store 0 entries, or somehow disabling and then re-enabling the keyboard as needed.
I have tried using $HOST.UI.RawUI.Flushinputbuffer() at strategic locations in order to prevent characters from displaying, but I don't think there's anywhere I could put that in my loop that will perfectly block all input from displaying during code execution (it works great for making sure nothing gets passed when input is required, though). I've tried looking up the solution, but the only command I could find for manipulating the Input Buffer is the one above. I've also tried strategic implementation of the $host.UI.RawUI.KeyAvailable variable to detect keystrokes during execution, then $host.UI.RawUI.ReadKey() to determine if these keystrokes are unwanted and do nothing if they are, but the keystrokes still display in the console no matter what.
I am aware that this code is fairly broken as far as reading the key to escape the loop goes, but bear with me. I hashed up this example just so that you could see the issue I need help eliminating. If you hold down any letter key during this code's execution, you'll see unwanted input displaying.
$blinkPhase = 1
# Set Coordinates for cursor
$x = 106
$y = 16
$blinkTime = New-Object System.Diagnostics.Stopwatch
$blinkTime.Start()
$HOST.UI.RawUI.Flushinputbuffer()
do {
# A fancy blinking ellipses I use to indicate when Enter should be pressed to advance.
$HOST.UI.RawUI.Flushinputbuffer()
while ($host.UI.RawUI.KeyAvailable -eq $false) {
if ($blinkTime.Elapsed.Milliseconds -gt 400) {
if ($blinkPhase -eq 1) {
[console]::SetCursorPosition($x,$y)
write-host ". . ." -ForegroundColor gray
$blinkPhase = 2
$blinkTime.Restart()
} elseif ($blinkPhase -eq 2) {
[console]::SetCursorPosition($x,$y)
write-host " "
$blinkPhase = 1
$blinkTime.Restart()
}
}
start-sleep -m 10
}
# Reading for actual key to break the loop and advance the script.
$key = $host.UI.RawUI.ReadKey()
} while ($key.key -ne "Enter")
The expected result is that holding down any character key will NOT display the input in the console window while the ellipses is blinking. The actual result, sans error message, is that a limited amount of unwanted/unnecessary input IS displaying in the console window, making the script look messy and also interfering with the blinking process.
What you're looking for is to not echo (print) the keys being pressed, and that can be done with:
$key = $host.UI.RawUI.ReadKey('IncludeKeyDown, NoEcho')
Also, your test for when Enter was pressed is flawed[1]; use the following instead:
# ...
} while ($key.Character -ne "`r")
Caveat: As of at least PSReadLine version 2.0.0-beta4, a bug causes $host.UI.RawUI.KeyAvailable to report false positives, so your code may not work as intended - see this GitHub issue.
Workaround: Use [console]::KeyAvailable instead, which is arguably the better choice anyway, given that you're explicitly targeting a console (terminal) environment with your cursor-positioning command.
As an aside: You can simplify and improve the efficiency of your solution by using a thread job to perform the UI updates in a background thread, while only polling for keystrokes in the foreground:
Note: Requires the ThreadJob module, which comes standard with PowerShell Core, and on Windows PowerShell can be installed with Install-Module ThreadJob -Scope CurrentUser, for instance.
Write-Host 'Press Enter to stop waiting...'
# Start the background thread job that updates the UI every 400 msecs.
# NOTE: for simplicity, I'm using a simple "spinner" here.
$jb = Start-ThreadJob {
$i=0
while ($true) {
[Console]::Write("`r{0}" -f '/-\|'[($i++ % 4)])
Start-Sleep -ms 400
}
}
# Start another thread job to do work in the background.
# ...
# In the foreground, poll for keystrokes in shorter intervals, so as
# to be more responsive.
While (-not [console]::KeyAvailable -or ([Console]::ReadKey($true)).KeyChar -ne "`r" ) {
Start-Sleep -Milliseconds 50
}
$jb | Remove-Job -Force # Stop and remove the background UI thread.
Note the use of [Console]::Write() in the thread job, because Write-Host output wouldn't actually be passed straight through to the console.
[1] You tried to access a .Key property, which only the [SystemConsoleKeyInfo] type returned by [console]::ReadKey() has; the approximate equivalent in the $host.UI.rawUI.ReadKey() return type, [System.Management.Automation.Host.KeyInfo], is .VirtualKeyCode, but its specific type differs, so you can't (directly) compare it to "Enter"; The latter type's .Character returns the actual [char] instance pressed, which is the CR character ("`r") in the case of Enter.

Check if a Powershell script has frozen using a separate script

So I'm preforming some automated testing using powershell in jenkins. I'm testing a web application where I must fill out forms, retrieve values, etc.
It is all fine but the web app contains some pop up messages that appear every now and then, which causes the main script to freeze until they are manually closed in the application. Below is a link to a stack overflow thread with a similar problem.
Powershell Website Automation: Javascript Popup Box Freeze
I followed the advice of the first answer. I created a separate powershell script that is executing constantly and can tell if there is a pop up window present (as they have their own process ids, so if there is more then one iexplore process id present it must be a popup) and then uses sendkeys to close it.
Main Script example:
#start application
start C:\Users\Webapp
#start the monitor script
Start-Process Powershell.exe -Argumentlist "-file C:\Users\Monitor.ps1"
#Get app as object
$app = New-Object -ComObject Shell.Application
$ClientSelectPage = $app.Windows() | where {$_.LocationURL -like "http:webapp.aspx"}
#Input value to cause popup message
$MemNumberInput = $ClientSelectPage.Document.getElementByID("MemNum")
$MemNumberInput.Select()
$MemNumberInput.value = "22"
$FindBtn.click()
It is at this point my script will freeze (as pop up window appears to tell me info abotu the client I've inserted) If this popup can be seen as a process, the monitor code will close it.
Example of monitor
$i = 0
while($i -eq 0)
{
#Check what process are currently running under the webapps name
$Mainprocid = Get-Process | where {$_.mainWindowTitle -like "*webapp*" } | select -expand id
$Mainprocid.COUNT
$integer = [int]$Mainprocid
#If there is only one process, no action
if( $Mainprocid.count -eq 1)
{
echo "no popup"
}
else
{
if($integer -eq '0')
{
#If there are no processes close the script
$i = 1
echo "close process"
}
else
#If there are two processes one must be a pop, send 'enter' to the app
{
echo "POP UP!"
$title = Get-Process |where {$_.mainWindowTItle -like "*webapp*"}
#Code to sendkeys 'ENTER' to the application to close the popup follows here
}
}
}
However, for whatever reason, some pop ups cannot be found as processes and the monitor script is useless with them. These are few and far between, so I figured the best way was for the monitor script to check and see if the main script has frozen for a certain amount of time. If so, it can use the sendkeys method it does for the other popups.
Is there a way for me to check and see if the main script has frozen, from the monitor script? I understand I could pass a parameter from the main script every now and then, to let the monitor script know it is still active, but this seems like a messy way of doing it, and an alternative method would be preferable.
Both scripts are saved as .ps1 files.

Gracefully stopping in Powershell

How do I catch and handle Ctrl+C in a PowerShell script? I understand that I can do this from a cmdlet in v2 by including an override for the Powershell.Stop() method, but I can't find an analog for use in scripts.
I'm currently performing cleanup via an end block, but I need to perform additional work when the script is canceled (as opposed to run to completion).
The documentation for try-catch-finally says:
A Finally block runs even if you use CTRL+C to stop the script. A Finally
block also runs if an Exit keyword stops the script from within a Catch
block.
See the following example. Run it and cancel it by pressing ctrl-c.
try
{
while($true)
{
"Working.."
Start-Sleep -Seconds 1
}
}
finally
{
write-host "Ended work."
}
You could use the method described on here on PoshCode
Summary:
Set
[console]::TreatControlCAsInput = $true
then poll for user input using
if($Host.UI.RawUI.KeyAvailable -and (3 -eq
[int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
There is also a Stopping property on $PSCmdlet that can be used for this.
Here is recent, working solution. I use the if part in a loop where I need to control the execution interruption (closing filehandles).
[Console]::TreatControlCAsInput = $true # at beginning of script
if ([Console]::KeyAvailable){
$readkey = [Console]::ReadKey($true)
if ($readkey.Modifiers -eq "Control" -and $readkey.Key -eq "C"){
# tasks before exit here...
return
}
}
Also note that there is a bug which leads KeyAvailable to be true upon start of scripts. You can mitigate by read calling ReadKey once at start. Not needed for this approach, just worth knowing in this context.