Calling print verb in windows powershell without using Start-Sleep - powershell

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.

Related

Powershell script waiting for user input and wont exit

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.'

Powershell ps1 script runs bat file but CMD screen closes after execution

This is my code:
set-location [PATH]
$A = Start-Process -FilePath .\refresh.bat -Wait
set-location C:\
When executed in powershell, the system opens a Command prompt window and executes the bat file without issue. The problem is that the window closes and I cannot see if there was an error if it succeeds.
I want to keep the CMD window open.
I also tried at the end of the bat file:
:END
cmd /k
but no luck.
First, unless you specifically need to run the batch file in a new window, do not use Start-Process - use direct invocation instead, which is implicitly synchronous and allows you to capture or redirect output:
# Invoke the batch file synchronously (wait for it to exit)
# and capture its (standard) output in variable $A
# To print the batch file's output to the console instead, just use:
# .\refresh.bat
$A = .\refresh.bat
See this answer for more information.
Also note Start-Process never allows you to capture the invoked program's output directly (you can only redirect it to files with -RedirectStandardOutput and -RedirectStandardOutput); your specific command captures nothing[1] in $A; adding -PassThru does return something, but not the program's output, but a process-information object (System.Diagnostics.Process).
If you do need to run the batch file in a new window and want to keep that window open:
Start-Process -Wait -FilePath cmd -ArgumentList '/k .\refresh.bat'
Relying on positional parameter binding, the above can be simplified to:
Start-Process -Wait cmd '/k .\refresh.bat'
[1] Strictly speaking, $A is assigned the [System.Management.Automation.Internal.AutomationNull]::Value singleton, which in most contexts behaves like $null.
Thank you mklement0 with your post gave me the solution I wanted. This is how I solved it.
set-location [PATH]
$A = Start-Process -FilePath .\refresh.bat -Wait -NoNewWindow
set-location C:\
-NoNewWindow allowed me to run my batch in the same powershell window getting the feedback of the bat file. That way I have errors if any and success status if no errors.
Thanks!

How do I get a Powershell process that was opened by another Powershell process?

I am running multiple PowerShell scripts at once. I would like to be able to wait on certain ones to finish before opening new scripts. Basically, I was thinking if I could find the command line option that ran it something like "powershell.exe -Path "<script dir>" that would do it.
I tried doing a Get-Process | gm to find any parameters that I could call to get that information and I didn't see any (doesn't mean they aren't there) I tried looking through Task Manager to see if I could view something through the gui that I could link to but that didn't help either.
I hope I can get something like
Start-Process -FilePath ".\<script>.ps1" -ArgumentList "<args>"
do
{
sleep 10
}
until ((Get-Process -ProcessName "PowerShell" | where "<paramater>" -EQ ".\<script>")
I need to wait until that process is done but I don't want to put a wait at the end of the Start-Process because after that Start-Process kicks off I need some other items to go to while my .\ is running. I just need it to wait before another section of script kicks off.
Have a look at the "Job" cmdlets https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_jobs?view=powershell-6
And the $PID automatic variable, this will give the process ID of the current PowerShell session.

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.