Why cmd doesnt keep shell script processes alive? - powershell

I have a powershell script, that starts x number of Jobs. If I start it from powershell, the processes stays alive, but if start from cmd, after the script finishes every process stops.
The only way I can keep the processes alive, is to put Sleep in the script. Why is that?
This is how I start the script from cmd:
Powershell.exe .\scripts\cpu_load.ps1 -UtilizeCorePercent 50

The PowerShell.exe has 2 main modes of operations.
A terminal mode where you can run multiple scripts or individual commands.
An execution mode where PowerShell.exe starts running, it then executes a script that was passed to it as a parameter, continues to run until the script exits, and then the PowerShell.exe exits or closes.
In terminal mode, variables you assign, jobs you start, and more, will stay active and available until you exit the PowerShell.exe terminal. Similarly, in execution mode, everything remains available until the script exits - which exits the PowerShell.exe.
The CMD terminal allows you to execute exe programs such as Notepad.exe and PowerShell.exe, but you have to understand that CMD.EXE is, itself, an executable program ran typically by a shortcut placed somewhere in your Windows Desktop.
The fact that CMD is its own exe program means that it has no "awareness" of any type of other exe programs, and, as such, it will not preserve anything from those other exe programs after they close.
The only solutions is something similar to iRon's comment on using "Wait-Job and/or Receive-Job", where, in some fashion, PowerShell.exe remains running until the job(s) are done.

Related

Automatically execute .cmd file requiring user input

We have a .cmd file we want to be able to execute automatically using Powershell (from TFS Release).
The issue with using start-process in Powershell is that execution gets stuck waiting for user input (Press any key to continue...).
Is there any way that we can pass variables to this call or call it in a different way where we no longer require user input for this .cmd?
Don't use Start-Process.
"`n" | & 'C:\path\to\your.cmd'
Powershell isn't getting stuck, Start-Process is working correctly - it's running the process (assume cmd.exe) and waiting for that process to terminate before continuing.
cmd.exe is prompting for interactive user input (PAUSE) before continuing, again working as you have instructed it to.
The issue is you're running non-interactively, and aren't providing the input required to continue.
You can update the cmd file and add an optional parameter so you can 'skip' the PAUSE when running unattended:
if "%1"=="unattended" goto skippause
pause
:skippause
then run it using unattended:
CMD /c c:\folder\file.cmd unattended

Are external commands started by powershell scripts run synchrously or asynchrously as background processes?

If I were to start an exteral program from a powershell script and then start another one, does the first program started wait to exit before running the next command?
For example:
# Assume pagent loaded our key...
& {
& pscp -sftp "<some-path>\text*.json" nonroot#somehost:/home/nonroot/json ;
Write-Output $LASTEXITCODE;
& plink nonroot#somehost "/bin/processJSON.sh /home/nonroot/json";
Write-Output $LASTEXITCODE;
}
On Windows, PowerShell will always wait synchronously for a console application to complete. For Win32 applications, if the output of the command is not redirected, then the command will run asynchronously. If it is redirected, then PowerShell will wait for the command to complete. For example, running notepad from the command line will start notepad running asynchronously with PowerShell but if you ran notepad | out-null then PowerShell would wait until the notepad process exited before proceeding. On Linux or MacOS, there is no OS distinction between "windows" and "non-windows" applications so PowerShell always waits for the child process to complete. So unless the application puts itself in to the background (which a lot of GUI tools do), on these platforms you have to explicitly run the process as a background job using & e.g. xedit &.

Powershell config to force a batch file to run within the powershell window?

I've got a powershell script that eventually passes a stack of arguments into a batch file via invoke-expression command.
However, on one server, when the powershell scripts executes that batch file, that batch file opens in a new window, but on the other server, the batch file executes within the powershell window.
What that means, is that I've got a sleep interval that is starting once the batch file begins executing in the new window, and thus screwing up my timings, unlike the other server, where the sleep interval doesn't begin until after the batch file has finished executing.
So my question is... does anybody know why the behaviours are different between the two servers, and how to get the batch file to execute in the powershell window? I'm thinking it's a configuration thing, but can't actually find anything that tells me how to make it do what I want it to do.....
Thanks!
--edit--
I'm currently just piping the line straight through like this:
E:\Software\ibm\WebSphere\AppServer\bin\wsadmin -lang jython -username $($username) -password $($password) -f "F:\Custom\dumpAllThreads.py" $($servers)
Previously, it was
$invokeString = 'E:\Software\ibm\WebSphere\AppServer\bin\wsadmin -lang jython -username $($username) -password $($password) -f "F:\Custom\dumpAllThreads.py" $($servers)'
$output = invoke-expression $invokeString
Both had the same behaviour.
So my question is... does anybody know why the behaviours are different between the two servers
Most often I've seen this sort of thing related to how a scripts is called. If the same user is logged on multiple times on the same server (i.e., console and RDP) then the window might appear in a different session. Similarly, if the script runs as a scheduled task and the user that runs the task isn't the user logged on, the window will never be visible. If the same user is logged on, it might be visible.
how to get the batch file to execute in the powershell window?
You could try Start-Process with -NoNewWindow, as #Paul mentions.
However....
What that means, is that I've got a sleep interval that is starting once the batch file begins executing in the new window, and thus screwing up my timings, unlike the other server, where the sleep interval doesn't begin until after the batch file has finished executing.
It sounds like your actual problem is that your code has a race condition. You should fix the actual problem. Use Start-Process with the -Wait parameter, or use the jobs system in PowerShell.

Is there a way to start commandline processes in a new commandline window from a powershell script?

I am using
Start-Process "<PathToFile>.bat"
For .bat files from a lengthy script in Powershell (v3). However, the commandline window pops up for a moment and is immediately closed and the process that normally runs on the commandline, runs in the background with no indication wether it's finished or if any errors occured.
Is there a way to force the command window to stay open until the user exits the window (after the .bat ran)? I suppose even if there is a way that the command window stays open, the PS script will continue to run in the background?
As said by Alex K CMD /K opens a CMD window and then keeps it open.
If you use CMD /C it will call the file, run the commands/process and then exit.
Sadly, it never worked for me with cmd /c. Since I also needed parameters to be handed over to the programm called from the commandline, I opted to write a temporary proxy bat that held the call to the program and the parameters.
Pseudocode here:
"ProgramName /Parameters" | Out-File DirOfTempBatFile -Encoding ascii
$output = Start-Process DirOfTempBatFile -wait
This calls the program (sqlplus with parameters) with keeping the command window open. Additionally, you can access the output of the sqlplus debug messages via $output.

how to run a powershell script and a batch script in a batch script?

i have controller batch file named oneclick.bat, code as below:
rem batch controller
rem wait for email input for ssh key generation...
rem call copyEnv.bat
call generateSshKey.bat %1
call gitClone.bat
in generateSshKey.bat, i start a powershell script like this:
rem make sure powershell is able to run
powershell.exe set-executionpolicy remotesigned
rem start powershell and add ssh key to the server by ui aotumation
powershell.exe -noe -file SetSSHKeytoServer.ps1
and then gitClone.bat did not run in the command window
how can i get the gitClone.bat run?
When you want to return to a calling script you shouldn't run PowerShell with an option that prevents it from returning. Remove -noe from the last line of generateSshKey.bat.
-NoExit
Does not exit after running startup commands.
As Ansgar Wiechers pointed out, the -noe (short for -NoExit) is keeps the PowerShell session open, so generateSshKey.bat doesn't exit, and oneclick.bat doesn't get past the line that called it.
If you specifically want the powershell session that runs SetSSHKeytoServer.ps1 to remain active (since you used the -noe switch the second time but not the first time, I'm inferring that this was deliberate), you could change
call generateSshKey.bat %1
to
start generateSshKey.bat %1
Note that this means that oneclick.bat won't wait for generateSshKey.bat to finish before calling gitClone.bat, so if you need to run them in sequence, this won't work. It will work as long as it's okay for gitClone.bat to start while generateSshKey.bat is still running.