Powershell script waiting for user input and wont exit - powershell

I am trying to run a script silently, its runs fine but then after its run it displays
Succeeded : 0
Press 'Enter' to continue
How can i check if succeeded and then send the enter key..
Note I am running this via the start process command as below but as it is waiting for the user to press enter it never exits:
Start-Process -Wait -FilePath "C:\windows\temp\abc.exe" -ArgumentList '/S','/v','/qn' -passthru

Your best bet is to check if your executable supports a command-line parameter (option) that skips the prompt at the end.
If there is none, you can try the following approach, but note that, as with all attempts to control an application via simulated user interaction, the solution is awkward and brittle:
# Comment this out to hide the verbose messages.
$VerbosePreference = 'Continue'
# Load helper assemblies.
Add-Type -ErrorAction Stop -AssemblyName Microsoft.VisualBasic, System.Windows.Forms
# Launch the external program.
# In this simple example, cmd.exe is invoked with its internal pause
# command, which waits for a keystroke to continue.
Write-Verbose 'Launching the external program asynchronously...'
# IMPORTANT: Do NOT use -Wait, as that will block execution
# indefinitely, and prevent you from sending the Enter keystroke.
$process = Start-Process -PassThru cmd '/c pause'
Write-Verbose 'Sleeping for as long as execution is expected to last at a minimum...'
Start-Sleep 5 # Adjust this as needed.
Write-Verbose 'Sending ENTER keystrokes until the window closes...'
while (-not $process.HasExited) {
# To be safe, activate the external program's window. If that fails, it must be closed already.
try { [Microsoft.VisualBasic.Interaction]::AppActivate($process.Id) } catch { break }
# Send the keystroke.
[System.Windows.Forms.SendKeys]::SendWait('{Enter}')
Start-Sleep -Milliseconds 200 # Sleep a little between attempts.
}
Write-Verbose 'The external program''s window is now closed.'

Related

How do I send keys to an active window in Powershell?

I want my script to open an application and send keys to it after it's opened. Currently, if I run the script, it opens the app but does not send the keys.
If I run just the send keys after the app has already been opened, it works.
Here is what I've got so far:
Start-Process -FilePath "C:\Program Files\VMware\VMware Horizon View Client\vmware-view.exe" -Wait -WindowStyle Normal
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('VMware')
Sleep 1
$wshell.SendKeys('~')
Sleep 3
$wshell.SendKeys('username')
Sleep 2
$wshell.SendKeys('{TAB}')
Sleep 1
$wshell.SendKeys('password')
By using -Wait with Start-Process, you're blocking the call until the launched process terminates.
Thus, your attempts to send keystrokes will invariably fail, because they'll be sent after the target program has terminated.
Therefore:
Don't use -Wait
Use -PassThru, which makes Start-Process emit a process-information object representing the newly launched process, whose .ID property contains the PID (process ID).
For more reliable targeting, you can pass a PID to $wshell.AppActivate()
The general caveat applies: sending keystrokes, i.e. simulating user input is inherently unreliable.
$ps = Start-Process -PassThru -FilePath "C:\Program Files\VMware\VMware Horizon View Client\vmware-view.exe" -WindowStyle Normal
$wshell = New-Object -ComObject wscript.shell
# Wait until activating the target process succeeds.
# Note: You may want to implement a timeout here.
while (-not $wshell.AppActivate($ps.Id)) {
Start-Sleep -MilliSeconds 200
}
$wshell.SendKeys('~')
Sleep 3
$wshell.SendKeys('username')
Sleep 2
$wshell.SendKeys('{TAB}')
Sleep 1
$wshell.SendKeys('password')

kill child processes when parent ends

My goal is to kill (or somehow gracefully shutdown) child processes that were started by powershell script, so that nothing will keep running after the parent process dies (either normally by hitting end of script or via crash or ctrl+c or any other way).
I've tried several approaches but none worked as expected:
# only one line was active at time, all other were commented
start-job -scriptblock { & 'notepad.exe' } # notepad.exe started, script continues to end, notepad.exe keep running
start-job -scriptblock { 'notepad.exe' } # notepad.exe not started, script continues to end
notepad.exe # notepad.exe started, script continues to end, notepad.exe keep running
& notepad.exe # notepad.exe started, script continues to end, notepad.exe keep running
start-Process -passthru -FilePath notepad.exe # notepad.exe started, script continues to end, notepad.exe keep running
# give script some time before ending
Write-Host "Begin of sleep section"
Start-Sleep -Seconds 5
Write-Host "End of sleep section"
You can to this kind of thing with a finally clause. A finally clause gets executed after a try block, even if the execution of the try block threw an exception or if the execution was aborted by the user.
So one way to approach your problem would be the following:
keep track of the process ids of the child processes, your script is spawning and
kill these processes in the finally clause.
try
{
$process = Start-Process 'notepad.exe' -PassThru
# give script some time before ending
Write-Host "Begin of sleep section"
Start-Sleep -Seconds 5
Write-Host "End of sleep section"
}
finally
{
# Kill the process if it still exists after the script ends.
# This throws an exception, if process ended before the script.
Stop-Process -Id $process.Id
}

Calling print verb in windows powershell without using Start-Sleep

I have an electron app (nodejs) and have a requirement to print pictures from it. I am using the powershell command:
$path = "C:\person.jpg";
Start-Process -FilePath $path -Verb Print | Out-Null;
Start-Sleep -s 150;
This works but as soon as I remove Start-Sleep, the print window opens for half a second and closes by itself. Then, if I don't do this and the window opens, even after the user presses the close button on the title bar, the powershell process still remains open until the timeout is completed. Is there a way to have this window open and to clean up it's memory when the user closes it?
Many Thans
Add the -Wait parameter to you Start-Process call. From Start-Process:
-Wait
Indicates that this cmdlet waits for the specified process and its descendants to complete before accepting more input. This parameter suppresses the command prompt or retains the window until the processes finish.
Otherwise, PowerShell fires up the process and moves on the script execution. That's the reason why you need a Start-Sleep. So, change your code to:
$path = "C:\person.jpg";
Start-Process -FilePath $path -Verb Print -Wait | Out-Null;
if you are using PowerShell 5.x you can also try `Out-PrinterĀ“ see this link for additional docu.
Hope that helps.

powershell how to close a .exe process

I want to start a .exe file from powershell and wait for it to finish and then continue to the next line in the powershell. However after the .exe file finished it's job the window remain there to be manually closed. Just like notepad. Here is what I got
start-process -FilePath notepad -Wait -NoNewWindow
echo "it's done!"
I specified -NoNewWindow but it still comes with a window and the powershell have to wait until I manually close it. How can I close it automatically? The .exe file is a third party app that I have no control over.
Please note that I want to wait for the task that the .exe file completes and then automatically close that window so that I can continue to the next line in powershell.
I also tried -WindowStyle hidden.
start-process -FilePath notepad -Wait -WindowStyle hidden
echo "it's done!"
But this is even worse I have to go to task manager to kill the hidden window without knowing it is completed or not.
Is there a parameter better than -NoNewWindow that can force no new window show up?
Thanks,
The script below will:
Open Notepad.
Wait for you to type "Finished".
Close Notepad.
You will need to install AutoIt. (I selected "x86" in the installer BTW.)
You will also need to adapt the Get-AU3ControlHandle call to suit your needs. The AutoIt Window Info Tool will be useful there. You may have to do some reading of the AutoIt documentation.
See also AutoIt Cmdlets for Windows PowerShell.
import-module "${env:ProgramFiles(x86)}\AutoIt3\AutoItX\AutoItX.psd1"
$p = Start-Process notepad -PassThru
# Wait for the window to open
while($p.MainWindowHandle -eq 0)
{
Start-Sleep 1
}
$c = Get-AU3ControlHandle -WinHandle $p.MainWindowHandle -Control "Edit1"
while($true)
{
$t = Get-AU3ControlText $p.MainWindowHandle $c
if ($p.HasExited)
{
break;
}
elseif ($t -eq "Finished")
{
$p.CloseMainWindow();
break;
}
else
{
Write-Output "Waiting 1 sec."
Start-Sleep 1
}
}
Write-Output "Done"
This is what I use to kill iTunes automatically. But, as mentioned in my comment, if you want to wait for it to be done, you'd have to add either a sleep or do some application-specific check to see that its job is done. What that check is depends on what the exe is doing.
$itunesProc = Get-Process -name iTunes -ErrorAction "Ignore"
if ($itunesProc -ne $null) {
echo "Stopping iTunes..."
Stop-Process -Name iTunes
} else {
echo "No running iTunes process found"
}

Disable close button of MSBuild child process

I have a PowerShell script that launches an MSBuild child process. I would like to disable the "close" button on the child process window, so that the user cannot interrupt the process. However, I have not been able to find any information indicating whether this is possible.
If someone could either confirm (and tell me how I would go about doing this) or deny whether this is possible I would greatly appreciate it.
MSBuild.exe is a console application, and as such by default it will run in a console window. You can't really "disable" the close button anymore than you could stop someone (with the right privileges) from just terminating the msbuild.exe process...
What you could do to mitigate some risk would be to use the the jobs feature that was introduced in PowerShell 2.0:
$job = Start-Job -ScriptBlock {
& msbuild app.csproj
if ($LASTEXITCODE -ne 0) { throw "MSBuild failed. Exit code: $LASTEXITCODE" }
}
This will schedule the script block to be run on a background thread of your PowerShell session and it will not show a window for msbuild. All of the output will be captured and held until you decide to retrieve the job. You can check the status of all background jobs with the Get-Job cmdlet, and receive the results with Receive-Job
Wait-Job $job # this line pauses PowerShell/your script until the job returns
$output = $job | Receive-Job
You can do whatever you want with the output - it is worth noting that the exception thrown if the msbuild exit status code is non-zero will be held until you receive the job, at which point it will be raised to your code like any other exception would be. You may want to consider wrapping your call to Receive-Job in a try/catch block to deal with a failed build.
Another option if you don't want a separate window to appear:
$buildArgs = "MySolution.sln", "/t:Build", "/p:Configuration=Debug"
Start-Process -FilePath "msbuild" -ArgumentList $buildArgs -NoNewWindow -Wait
Start-Process has other flags to control redirecting output as well.