Powershell - Allow user to exit or continue script - powershell

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

Related

Comparing a String Variable via PowerShell

I'm trying to create an if and else statement within PowerShell that exits my code if the $value variable has a 0 or 1.
The below is my code which is executed remotely:
$MsgBox = {
Add-Type -AssemblyName PresentationFramework
$ButtonType = [System.Windows.MessageBoxButton]::OKCancel
$MesssageIcon = [System.Windows.MessageBoxImage]::Warning
$MessageBody = "Please save anything open in your current Web Browser, this includes Google Chrome, Microsoft Edge, and Mozilla FireFox and close each one respectively. Click Ok when done saving and closing browsers. IT Will be deleting your Cache and Cookies.
-IT"
$MessageTitle = "Read Me"
$Result = [System.Windows.MessageBox]::Show($MessageBody, $MessageTitle,$ButtonType,$MesssageIcon)
Switch ($Result){
'Ok' {
return "1"
}
'Cancel' {
return "0"
}
}
}
$value = invoke-ascurrentuser -scriptblock $MsgBox -CaptureOutput
$exit = "0"
Write-Host $value
if ($value.Equals($exit)){
Write-Host "Script Exiting"
exit
}
else{
Write-Host "Continuing Script"
}
Am I comparing the wrong way in PowerShell?
I tested the code with Write-Host and my scriptblock returns 0 or 1 as planned.
When it gets to the If and Else statement it doesn't seem to compare value and exit, and will instead go straight to the else statement and Write "Continuing Script"
I've also tried with $value -eq 0 and $value -eq "0".
Invoke-AsCurrentUser, from the third-party RunAsUser module, when used with -CaptureOutput invariably outputs text, as it would appear in the console, given that a call to the PowerShell CLI, is performed behind the scenes (powershell.exe, by default).
The captured text includes a trailing newline; to trim (remove) it, call .TrimEnd() before comparing values:
# .TrimEnd() removes the trailing newline.
$value = (Invoke-AsCurrentuser -scriptblock $MsgBox -CaptureOutput).TrimEnd()
if ($value -eq '0') {
Write-Host "Script Exiting"
exit
}
else {
Write-Host "Continuing Script"
}

How to test for a keypress or continue in 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

How can I interrupt an executable invoked inside a script without interrupting the script itself?

Let's say you have the following script saved in a file outermost.ps1:
powershell.exe -Command "while ( 1 -eq 1 ) {} "
echo "Done"
When running outermost.ps1 you can only abort this by pressing Ctrl+C, and no output will be written to console. How can I modify it so that the outermost script continues and executes echo "Done" when Ctrl+C is pressed?
This is a simplified version of a real-life scenario where the inner script is actually an executable which only is stoppable by pressing Ctrl+C.
Edit: The script could also be:
everlooping.exe
echo "Done"
but I wanted to provide an example everyone could copy-paste into an editor if they wanted to "try at home".
Start your infinite command/statement as a job, make your PowerShell script process Ctrl+C as regular input (see here), and stop the job when that input is received:
[Console]::TreatControlCAsInput = $true
$job = Start-Job -ScriptBlock {
powershell.exe -Command "while ( 1 -eq 1 ) {} "
}
while ($true) {
if ([Console]::KeyAvailable) {
$key = [Console]::ReadKey($true)
if (($key.Modifiers -band [ConsoleModifiers]::Control) -and $key.Key -eq 'c') {
$job.StopJob()
break
}
}
Start-Sleep -Milliseconds 100
}
Receive-Job -Id $job.Id
Remove-Job -Id $job.Id
echo "Done"
If you need to retrieve output from the job while it's running, you can do so like this in an else branch to the outer if statement:
if ($job.HasMoreData) { Receive-Job -Id $job.Id }
The simplest solution to this is:
Start-Process -Wait "powershell.exe" -ArgumentList "while ( 1 -eq 1 ) {}"
echo "Done"
This will spawn a second window unlinke ansgar-wiechers solution, but solves my problem with the least amount of code.
Thanks to Jaqueline Vanek for the tip

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