How to test for a keypress or continue in powershell - powershell

I have a basic powershell function that works as a spambot.
function Start-Spambot{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,HelpMessage="The text you wish to spam.")]
[string]$text,
[Parameter(Mandatory=$True,HelpMessage="How many milliseconds between messages.")]
[decimal]$speed,
[Parameter(Mandatory=$True,HelpMessage="The tota ammout you want to spam.")]
[decimal]$number
)
$count = $number
Invoke-BalloonTip -Message "You have 3 seconds before the program starts spamming." -Title "Start-Spambot $text $speed $number"
Start-Sleep -Seconds 3
while ($count -gt 0){
[System.Windows.Forms.SendKeys]::SendWait("$text")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -Milliseconds $speed
$count -= 1
}
[System.Windows.Forms.SendKeys]::SendWait("$text")
Invoke-BalloonTip -Message "$text has been typed $number times." -Title "Start-Spambot $text $speed $number"
}
The thing i want to add is a kill switch in the while loop. If you press 'esc' for example the script should break the while loop and continue as normal. (invoke-balloontip will make a popup in the bottem right). I have looked at a bunch and googled for hours but they all are just looking to go if the key is pressed and not the other way arround.
Any of you have a simple script or function for this?
Note:
(All of you who are complaining i dont have the code that i tried. Why would i save the things that dont work?)
Edit:
If possible it should work outside of the terminal.

After more searching i finaly found this method:
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName PresentationCore
1..10000000 | ForEach-Object {
"I am at $_"
$isDown = [Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift)
if ($isDown){
Write-Warning "ABORTED!!"
break
}
start-sleep -Milliseconds 10
}
Edit:
It wont work in the ise wich is kinda anoying

Related

Powershell - Allow user to exit or continue script

I'm a beginner at powershell script. I've written the following script but can't seem to get it to work. When the script is run, after every minute it should output the number of minutes elapsed into a notepad. This should continue non-stop until the user intervenes. If the user presses the "s" key then the script will pause and they'll be asked if they want to continue the script or exit the script. If they type "y" the script will continue from where it left off, else it will stop and exit.
Below is my code:
$myshell = New-Object -com "Wscript.Shell"
$i=1
do
{
$key = if ($host.UI.RawUI.KeyAvailable) {
$host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
}
if ($key.Character -eq 's') {
write-host -nonewline "Continue? (Y/N) "
$response = read-host
if ( $response -ne "Y" ) {exit}
}
Start-Sleep -Seconds 60
$myshell.sendkeys("$i.")
$i++
} while ($true)
This doesn't seem to do anything at all. Any assistance will be appreciated

stopwatch PowerShell input

I have simple issue, but it is very hard to me to solve it.
I want a stopwatch, when I put a time in seconds and next MessageBox appear.
It works when I input a number (10, 50, 120), but doesn't work when I put 60+5 or 60*2.
How I can convert 60*2 to 120 in PowerShell?
[int]$time = Read-host "Write a time"
Start-Sleep $time
[System.Windows.Forms.MessageBox]::Show("Tea!")
Using Invoke-Expression might be safe if it can be limited to only numeric calculations.
Add-Type -AssemblyName System.Windows.Forms
$userentry = Read-Host -Prompt "Write a time"
if ($userentry -match '^[\d+\-\*/\(\) ]*$') {
try {
$time = Invoke-Expression -Command $userentry -ErrorAction Stop
Start-Sleep $time
[System.Windows.Forms.MessageBox]::Show('Teal')
} catch {
Write-Host 'ERROR: Invalid numeric expression'
}
} else {
Write-Host 'ERROR: Not a valid numeric expression'
}
You could try Invoke-Expression $time to evaluate expressions like this. But be aware, that all types of PowerShell-Code can be send by this

Start Process and read StandardOutput

I am looking for a way to start a process in a new console window or the same window and catch its output, I can open process in new window using:
[Diagnostics.Process]::Start("C:\test.exe","-verbose -page")
This will open new window witch I can interact with but I cannot redirect output for it (output I mean whole interaction with window like key press and messages)
So I thought I can try with:
Start-Transcript -path "C:\test.txt" -append
$ps = new-object System.Diagnostics.Process
$ps.StartInfo.Filename = "C:\test.exe"
$ps.StartInfo.Arguments = " -verbose -page"
$ps.StartInfo.RedirectStandardOutput = $True
$ps.StartInfo.UseShellExecute = $false
$ps.start()
while ( ! $ps.HasExited ) {
write-host = $ps.StandardOutput.ReadToEnd();
}
Now here I get get output but without interaction, so I need some sort of option or procedure to start this process in same or different console and catch my interaction with it to file.
It is important as application sometimes asks for press any key and if Ill launch it in background it will never ask it because this app measures console window and checks id output will fit?
Is such thing possible?
You should be able to do
myprocess.StandardInput.WriteLine("some input");
or
myprocess.StandardInput.Write(" ");
As I was having big problem with this kind of interactivity in powershell, I mean run console app and press key, I finally got it right and I am shearing my solution.
Press button to continue function:
Function Press-Button
{
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('~');
}
Start process, log whole transaction and press to continue:
Function Run-Tool
{
Start-Transcript -path "C:\test.txt" -append
$ps = new-object System.Diagnostics.Process
$ps.StartInfo.Filename = "C:\test.exe"
$ps.StartInfo.Arguments = " -verbose -page"
$ps.StartInfo.RedirectStandardInput = $true;
$ps.StartInfo.UseShellExecute = $false
$ps.start()
while ( ! $ps.HasExited )
{
Start-Sleep -s 5
write-host "I will press button now..."
Press-Button
}
Stop-Transcript
}
No matter how you do this it will be unreliable in an active system:
Function Run-Tool {
Start-Transcript -path "C:\test.txt" -append
Add-Type -AssemblyName System.Windows.Forms
$ps = new-object System.Diagnostics.Process
$ps.StartInfo.Filename = "C:\test.exe"
$ps.StartInfo.Arguments = " -verbose -page"
$ps.StartInfo.RedirectStandardInput = $true;
$ps.StartInfo.UseShellExecute = $false
$ps.start()
do{
Start-Sleep -s 5
write-host "I will press button now..."
[System.Windows.Forms.SendKeys]::SendWait('~');
}
until($ps.HasExited)
Stop-Transcript
}

Powershell wait for keypress

I would like to make this script to pause after typing "Hello this is a test" automatically and after pressing the enter key it should wait for F2 key to be pressed.
How can that be done?
function wait {
param([int]$stop = 3)
Start-Sleep -seconds $stop
}
[void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
& "$env:Windir\notepad.exe"
$a = Get-Process | Where-Object {$_.Name -eq "Notepad"}
wait
[System.Windows.Forms.SendKeys]::SendWait("Hello this is a test")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
wait
# here I want something like wait for F2 key to be pressed
# after the F2 key was pressed I want the script to continue
[System.Windows.Forms.SendKeys]::SendWait("This is After the key was pressed")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
exit
Here is a modified version of your script that achieves what you want. Keep in mind that this will not work in the PowerShell Integrated Scripting Editor (ISE).
$Wait = 3;
[void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
& "$env:Windir\notepad.exe"
$a = Get-Process | Where-Object {$_.Name -eq "Notepad"}
Start-Sleep -Seconds $Wait;
[System.Windows.Forms.SendKeys]::SendWait("Hello this is a test")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -Seconds $Wait;
while ([System.Console]::ReadKey().Key -ne [System.ConsoleKey]::F2) { };
[System.Windows.Forms.SendKeys]::SendWait("This is After the key was pressed")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
exit
The following will loop until F2 is pressed, with a prompt to the user.
do{ echo "Press F2";$x = [System.Console]::ReadKey() } while( $x.Key -ne "F2" )

PowerShell console timer

I am attempting to create a simple console timer display.
...
$rpt = $null
write-status "Opening report", $rpt
# long-running
$rpt = rpt-open -path "C:\Documents and Settings\foobar\Desktop\Calendar.rpt"
...
function write-status ($msg, $obj) {
write-host "$msg" -nonewline
do {
sleep -seconds 1
write-host "." -nonewline
[System.Windows.Forms.Application]::DoEvents()
} while ($obj -eq $null)
write-host
}
The example generates 'Opening report ....', but the loop never exits.
I should probably use a call-back or delegate, but I'm not sure of the pattern in this situation.
What am I missing?
You should be using Write-Progress to inform the user of the run status of your process and update it as events warrant.
If you want to do some "parallel" computing with powershell use jobs.
$job = Start-Job -ScriptBlock {Open-File $file} -ArgumentList $file
while($job.status -eq 'Running'){
Write-Host '.' -NoNewLine
}
Here is what I think about Write-Host.
The script runs in sequence. When you input a $null object, the while condition will always be true. The function will continue forever until something breaks it (which never happends in your script.
First then will it be done with the function and continue with your next lines:
# long-running
$rpt = rpt-open -path "C:\Documents and Settings\foobar\Desktop\Calendar.rpt"
Summary: Your while loop works like while($true) atm = bad design