Waiting for an process to quit in PowerShell - powershell

Is there a possibility to wait for an process to quit, without it needs to running?
I know there is the keyword WaitForExit, but to use this the process needs to run.
My second question is, if there is a possibility to use an else-Statement in an while loop.
Tried it already, but it always said that there isnt an function called else.

Do Until
Do {
Sleep 5
} Until (Get-Process iexplore);
Will wait until iexplore is found
While
While (Get-Process iexplore) {
Sleep 5
}
Will wait until iexplore is no longer running
Else after while
You cannot use an else statement after a while loop.
It needs to come after an if.

if there is a possibility to use an else-Statement in an while loop.
If you mean something like:
while (cond) {
} else {
}
?
Then NO. (how would the content of the else block be any different to code immediately following the while block?)
Is there a possibility to wait for an process to quit,
Yes. There are different ways of doing this, depending on the nature of the target process. Is it one created by the same script? Is the same session? A service? Or just an arbitrary process?

Does it seems to fits your needs (1st question) ? http://technet.microsoft.com/library/hh849813.aspx

You can use wait-process cmdlet.
Check link for details http://ss64.com/ps/wait-process.html
Example: wait-process -name notepad.exe

Related

Alternative to Thread. Sleep with different hardware

I am writing a autologin script in Powershell. With main purpose of doing autologon with keystrokes on remote clients in our environment after installation, with the desired AD and password entered.
Works fine on my i9. But most people using Tablets and Elitebooks so using
Thread Sleep
Works bad since i would need to have custom timing on Every hardware, or very high default numbers for lower end clients using my script
Is there any way adding an "wait for row above to completed" Before continuation to next.
I don't have enough on your current code to produce a more accurate answer but the idea, in all cases, remains the same.
You should periodically wake up the thread to check whether or not the machine is in the state you want it in and from there, you either go back to sleep or exit the loop and continue.
The delay is up to you but you want to find a sweet spot to have great performance and reactivity.
Example (based on your description)
$IsLoggedIn = $false
while (! $IsLoggedIn) {
$IsLoggedIn = 'Custom Logic returning $true if the user is logged in'
if ($IsLoggedIn) { break }
Start-Sleep -Milliseconds 100
}
You just need to figure out the thing you want to use as the check to validate the computer is in the correct state you need it in before proceeding further.

Why can't I read a KeyPress more than once in PowerShell?

$KeyOption = 'Y','N'
while ($KeyOption -notcontains $KeyPress.Character) {
$KeyPress = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
The first time I run this, I'm able to read the character, but the next time that I run this, not so much...
Yes, I am running it in a PowerShell window
No, I'm not running it
from PowerShell ISE.
I looked at the docs for this and there's a related function called $host.UI.RawUI.FlushInputBuffer, but running it doesn't seem to change the fact that I can only make it work once...is there something else I need to be doing?
If you run your code again in the same scope, $KeyPress still has the value from the previous run, and if the previous run managed to exit the while loop based on a valid keypress, subsequent runs won't even enter the loop.
Therefore, switch to a do { ... } while (...) loop:
$KeyOption = 'Y','N'
do {
$KeyPress = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
} while ($KeyOption -notcontains $KeyPress.Character)

How to stop a powershell block after a timeout for powershell script

I want to invoke the command
$myArray = Get-Wmiobject -Class Win32-printer
But, on rare occasions, this command sometimes never fails nor succeed, returning the list of available printer.
I would like to assign $myArray only if the invocation takes less than a few seconds, lets say 5. Otherwise, I want to display a dialog telling that printers are unavailable at this moment.
How to start a powershell block with a timeout?
You can use a job for that:
$job = Start-Job { Get-Wmiobject -Class Win32-printer }
$job | Wait-Job -Timeout 5
if ($job.State -eq 'Running') {
# Job is still running, cancel it
$job.StopJob()
} else {
# Job completed normally, get the results
$myArray = $job | Receive-Job
}
I would say to create your own customized WMI queries using type casting and the native .NET providers. This way the work is still being done in the same opened console and you have physical control on the time outs.
I basically had the same frustration as you did. I would be querying servers all day until I hit the one that had a broken WMI. After so much, I started researching how to create my own WMI function to get around this. That was my solution to the problem. Learned a lot along the way.
Here is an article to help you along your way.
http://stevenmurawski.com/powershell/2009/01/dealing-with-wmi-timeouts/
Just to add to the above- powershell also has a built in stopwatch diagnostic for timeout functionality.
https://technet.microsoft.com/en-us/magazine/2009.03.heyscriptingguy.aspx

powershell - How to wait for user input

I am trying to prevent users from shutting down the computer in certain situations. I am displaying a confirm message to do that. This is how my script looks like:
$sysevent = [microsoft.win32.systemevents]
Register-ObjectEvent -InputObject $sysevent -EventName "SessionEnding" -Action $OnShutdown -SourceIdentifier "ExecuteOnShutdown"
$OnShutdown =
{
Write-Host -ForeGround Green $event.SourceEventArgs.Reason
$OUTPUT= [System.Windows.Forms.MessageBox]::Show("Do you really want to shutdown the computer?." , "confirm" , 4)
Write-Host $OUTPUT
}
This works fine but i dont know how do i suspend the shutdown command till user clicks "yes" or "no". Is there a way to prevent the system shutdown and wait for the user to click "yes" or "no" and then shutdown the server based on the answer?
In your event handler scriptblock there are a number of automatic variables defined one of which is $EventArgs. In this case there will be a Cancel property on this object you can set to $true but the docs warn:
When set to true, this property requests that the session continue to
run. It provides no guarantee that the session will not end.
There is also another variable defined in this context - $Sender. Execute man about_automatic_variables for more info.
Consider deploying your script via group policy or a local policy shutdown / logoff script which should prevent shutdown until your condition is met. You might need to wrap your messagebox call in conditional sleep loop (which is what I did for something similar in VBScript years ago!), maybe not.
If you choose to use this method, you may also want to include a preferred default selection for your messagebox (perhaps after a specified timeout period has elapsed?); a user may not hang around to see your mesaagebox as it will be drawn after the interactive desktop has unloaded.
Here's a link to a Technet article about how to Use Startup, Shutdown, Logon, and Logoff Scripts.
I'm not sure if this answers your question as this won't prevent the shutdown, it just stops it until your condition is met.

Creating batch jobs in PowerShell

Imagine a DOS style .cmd file which is used to launch interdependent windowed applications in the right order.
Example:
1) Launch a server application by calling an exe with parameters.
2) Wait for the server to become initialized (or a fixed amount of time).
3) Launch client application by calling an exe with parameters.
What is the simplest way of accomplishing this kind of batch job in PowerShell?
Remember that PowerShell can access .Net objects. The Start-Sleep as suggested by Blair Conrad can be replaced by a call to WaitForInputIdle of the server process so you know when the server is ready before starting the client.
$sp = get-process server-application
$sp.WaitForInputIdle()
You could also use Process.Start to start the process and have it return the exact Process. Then you don't need the get-process.
$sp = [diagnostics.process]::start("server-application", "params")
$sp.WaitForInputIdle()
$cp = [diagnostics.process]::start("client-application", "params")
#Lars Truijens suggested
Remember that PowerShell can access
.Net objects. The Start-Sleep as
suggested by Blair Conrad can be
replaced by a call to WaitForInputIdle
of the server process so you know when
the server is ready before starting
the client.
This is more elegant than sleeping for a fixed (or supplied via parameter) amount of time. However,
WaitForInputIdle
applies only to processes with a user
interface and, therefore, a message
loop.
so this may not work, depending on the characteristics of launch-server-application. However, as Lars pointed out to me, the question referred to a windowed application (which I missed when I read the question), so his solution is probably best.
To wait 10 seconds between launching the applications, try
launch-server-application serverparam1 serverparam2 ...
Start-Sleep -s 10
launch-client-application clientparam1 clientparam2 clientparam3 ...
If you want to create a script and have the arguments passed in, create a file called runlinkedapps.ps1 (or whatever) with these contents:
launch-server-application $args[0] $args[1]
Start-Sleep -s 10
launch-client-application $args[2] $args[3] $args[4]
Or however you choose to distribute the server and client parameters on the line you use to run runlinkedapps.ps1. If you want, you could even pass in the delay here, instead of hardcoding 10.
Remember, your .ps1 file need to be on your Path, or you'll have to specify its location when you run it. (Oh, and I've assumed that launch-server-application and launch-client-application are on your Path - if not, you'll need to specify the full path to them as well.)