Powershell script gets stuck, doesn't exit when called from batch file - windows

I have a PowerShell script that connects to a web site, and parses its returned data (It's about importing a previously uploaded SQL file into the web site's data base). The PowerShell script uses wget, something I may replace by a native function later.
The import process is embedded in a script that is executed by a 3rd party program called scriptFTP.
The script runs fine when I call it from a single .bat file like so:
powershell "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%
However, when I call this .bat file from within the greater ScriptFTP context, the following happens:
The PowerShell script is executed. I confirmed this my sending myself an E-Mail each time the remote import script got called.
PowerShell doesn't seem to exit, and script execution gets stuck. I can still cancel the whole thing using Ctrl+C but the following commands never get executed.
When I change the batch file to the following:
start powershell "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%
it works, running the PowerShell script in a new console, but I can't grab the error level that PowerShell returns.
I have tried calling PowerShell from ScriptFTP directly, bypassing the batch file, but with the same result: It just gets stuck.
Any output I have the PowerShell script do using Write-Output or Write-Host is not displayed.
All programs run under the same user, me.
Does anybody have any ideas what to do?

This variant might work for you.
powershell -NoProfile -Command "C:\data\etc\run_import_script.ps1; exit $LASTEXITCODE" < NUL
Taken from http://thepowershellguy.com/blogs/posh/archive/2008/05/20/hey-powershell-guy-how-can-i-run-a-powershell-script-from-cmd-exe-and-return-an-errorlevel.aspx

From my experience, PowerShell.exe can easily run scripts from within a batch file or shell script in a predictable way using the -File switch. One does not need to use the Start command.
The important thing to do is to append
< nul
to the command line from within a batch file. My research has shown that PowerShell runs the commands in the script indicated through the -File switch and then waits for additional PowerShell commands from the standard input (my brief experimentation with the -Command switch demonstrated similar behavior). By redirecting the standard input to nul, once PowerShell finishes executing the script and "reads end-of-file" from the standard input, PowerShell exits.
When invoking PowerShell from Cygwin, use
< /dev/null
For example, I've run PowerShell scripts from Cygwin using shell variables, like this:
PowerShell.exe -ExecutionPolicy RemoteSigned -File $_powershellscriptpath $_firstscriptparameter < /dev/null
Please post a comment if your experience varied from mine.
- Gordon

Try adding the /WAIT parameter. It will keep the .bat waiting until the PowerShell script completes.
START /WAIT powershell "& "C:\data\etc\run_import_script.ps1"

We had a similar issue. We wanted to call a powershell app from a piece of software that just had a box to enter "Command" and "Parameters" but although the powershell ran successfully (I could see the affected file updated.)
Finally my coworker helped me figure it out
Command needs to be:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
And Parameters:
-ExecutionPolicy unrestricted -Command "& {C:\scripts\apps\EDI\Test.ps1; [Environment]::Exit(1)}"
In our case it was important to use [Environment]::Exit(1) rather than Exit 1. I believe Exit was simply terminating the script, not closing Powershell itself.

If you want to capture the output of the powershell.exe commands then you can also use the /B parameter to force the process to run in the same command shell.
We've just seen a very odd instance of this problem. A batch file containing the call powershell.exe -command ... ran fine locally but stalled as described above when the batch file was run in the context of an msdeploy -postSync command. After experimenting with process.Kill() to force PowerShell to quit, we lit on the use of START /WAIT /B PowerShell.exe ..
No idea why this should work, but it does ...

IF that is exactly what's in your file it's because you have mismatched quotes. Powershell is waiting for the last quote.

PowerShell has, at least what I consider, strange behavior when being invoked in this manner. In short, it doesn't treat the command line arguments being passed to powershell.exe as scripts to run. Instead, it treats them as command to run. This is because the default for powershell.exe is -command - see powershell.exe /? for additional info.
C:\>powershell "'Hello'"
Hello
What you will need to do, is construct a clever input string to "source" the script you wish to run:
C:\>powershell ". .\test.ps1"
Hello, World!
As for the output, once you get the script running correctly, it should just be a matter of capturing STDOUT or whatever ends up fitting with your script.
Full Example
test.bat
#echo off
powershell.exe ". .\test.ps1"
test.ps1
"Hello, World!"
Invoke the command:
test.bat > test.txt
And verify the output was captured:
C:\>type test.txt
Hello, World!

The problem I bet is that the Powershell process continutes to run after executing the script. This means it has not exited and therefore there is no exit code. I'm having a similar problem when trying to run a Powershell script from C# that does stuff when finished, except it never finishes...
Hacky, but the only solution I've found is to put Stop-Process -processname powershell at the end of the .ps1 script. This kills off the PowerShell process (and all PowerShell windows you have open unfortunately) but seems to work. Might work for your script as well.

I had the exact issue, we were trying to integrate power shell scripts into another system and it kept giving a timeout error. Probably because of the issue mentioned by Gordon Smith, his solution might work. But to me I prefer to have complete control of my script from within the script itself and not depend on the way in which it is called.
$pid is built in variable with the PID. The below will end the current powershell process and leave the others intact. This way anyone can call your script as normal and it will work as expected.
Stop-Process $pid

you can simply add an 'exit' command to the end of the .ps1 script (or any variant of process termination that you wish). Powershell will continue to run at the end of the script as it has not been told to terminate (when run in PS or ISE it will auto-terminate at the end of the script but not when run through the DOS shell).

Related

How can I keep powershell in repl mode with a loaded script

I'm trying to start a powershell instance, that loads a script and remains open so I can still call methods loaded by that script manually.
I'm trying to dot source a script and pipe it to powershell like below, from a cmd instance/batchfile:
echo . .\script.ps1 | powershell
The result in this case is that powershell starts, loads my script, executes it and exits. I've tried running with -noexit argument, it has no effect.
I'm thinking of another option, to start a powershell process and pipe my dot source command to its stdin - but this probably won't allow me to interact with the process anymore because its stdin is opened by the host process.
If you need to run a script file so that window stays open and variables are accessible after the execution.
Try dot sourcing the script file like this:
powershell -noexit ". .\script.ps1"
Once the script is done, you can access any internal variable the script defined. Assuming the variables are at the script level scope.

execute powershell commands with Lua

I have a program that I work with, that has an onboard lua compiler to allow for custom written actions.
Since the tool itself is very limited, especially if it goes for complex reactions over networks, I want to use Powershell over lua.
Methods like os.execute() or io.popen() use the standard command line from windows and not Powershell.
Is there a way to use Powershell with lua?
I tried to write a command line script with the Powershell editor and run this script with os.execute, but it opens it as a textfile, it would be better to write the commands directly in lua but if there is no other way, executing a Powershell script directly would also be fine. (In Windows itself you can execute the script with right mouse "click/Execute with Powershell")
-- You can generate PowerShell script at run-time
local script = [[
Write-Host "Hello, World!"
]]
-- Now create powershell process and feed your script to its stdin
local pipe = io.popen("powershell -command -", "w")
pipe:write(script)
pipe:close()
Your description of the problem makes it sound like you're using a command such as os.execute("powershellscript.ps1"), and that call invokes cmd.exe with your string as the proposed command line. Normally, Windows will open a .PS1 file for editing; this was a deliberate decision for safety. Instead, try altering the os.execute() command to explicitly call PS: os.execute("powershell.exe -file powershellscript.ps1"). If you need to pass parameters to your script, enclose them in {}. See https://msdn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help for more info on invoking PowerShell from the command line.

Exit from cmd script that calls bash

I have the following cmd script which calls a cygwin bash script:
C:\cygwin\bin\bash -l /D/Temp/testScript/cygScript.sh
echo back in cmd.
exit
The bash script is simple:
#!/bin/bash
echo Hello World!
read
The calling part works nicely - the bash shell logs in, echos as expected, reads as expected and control passes back to the cmd as expected.
But the cmd will not exit. This is fine if I run it from a command window, but I will be calling this by double clicking on the cmd file or launching it from RUN etc.
Output I see:
D:\Temp\testScript>C:\cygwin\bin\bash -l /D/Temp/testScript/shellScript.sh
Hello World!
D:\Temp\testScript>echo back in cmd.
back in cmd.
D:\Temp\testScript>exit
How do I get the cmd to exit?
Found the problem - too many bashes
I think I found the issue - probably something in my .bashrc and other files I load during cygwin login. If I change the main cmd line to remove the login flag), it works as expected - everything closes.
C:\cygwin\bin\bash /D/Temp/testScript/cygScript.sh
But then I put the flag back:
C:\cygwin\bin\bash -l /D/Temp/testScript/cygScript.sh
and run again. I see the output Hello World! which shows me that control is with bash, and I check Task Manager. Four instances of bash.exe are created. Then I press ENTER and see the output back in cmd. showing me that control is back with cmd. Now Task Manager shows me that three bash.exe instances remain.
So, something in my login scripts are creating extra bash shells. So it's not you, it's me.
Avoid creating persistent subshells in login scripts by using cygstart instead of cmd.
Previously I wrote that the problem was too many bashes. My .bash_profile was doing something to create bash sub-shells (that were persistent because the jobs they launched kept going in the background). This meant that when my cmd created a bash (via login) and the first bash exited, the sub-shells didn't exit.
I found that part of my login scripts involved launching some Autohotkey scripts like this:
cmd /c "$thePath" &
The fix was so easy... just use cygstart:
cygstart "$thePath"

execute user inputed Windows (or bash) commands from batch (or bash) file?

Ok, so I have this batch script and what I want to happen is that when you run the script it does some standard stuff like change the path and access files etc... but after it's done that it goes back to being a normal cmd prompt/terminal where I can type in commands at free will.
Can this be done (in either dos or bash)? Is there like an execute command that I can put in an internal while loop or is there a command where when the scirpt ends it can go back to the normal cmd/terminal?
Do you need a full bash prompt?
Or would something like this be enough?
#!/bin/bash
echo -n "Enter cmd: "
read COMMAND
echo ${COMMAND} | bash
Also, in a script, you can just execute bash and get a full prompt in the current environment.
In Dos / windows command prompt if you run the batch file from command line you will get the prompt back always by default. Just like running any other command in command prompt.
Also in windows when the batch file execution is complete you can just put Cmd.exe when everything has finished running I.e at the end of the batch file.
Hope this helps!
E.g
#echo off
Echo running
.
.
.
Cmd.exe
Or even at the end
Echo %command% | Cmd.exe
Never mind, I got a good solution using this code: (for windows)
set /p command=CMD:
%command%

Does PSCP work with PowerShell?

I have a PowerShell script that produces a text file. At the end, I would like to copy this file to a Linux server.
From CMD.EXE, I can use PSCP (from Putty), it works and copies the file.
But from PowerShell, either interactively or from a PowerShell batch, PSCP has no visible effect: no error messages and the file is not copied.
Even if I run simply .\PSCP.EXE without arguments, on the CMD command line it displays the options, but from PowerShell it does nothing.
Can PSCP be used from inside PowerShell?
Executing a program from within PowerShell should work identically to CMD, but depending upon how that program produces its output (does it write to STDOUT, STDERR, other?) that may behave differently.
I've been using Rebex's components for FTPS & SFTP within .NET apps & PowerShell scripts; the SFTP package includes an SCP class. Yes, it costs money, but depending upon your usage it may be worthwhile.
Just attempted to automate PSCP from PowerShell. Remember to use pscp's -batch parameter so that, should you do something like enter the wrong password, you won't get asked for input.
$Cmd = "pscp -l username -pw password -batch c:\folder\file.txt server:/home/user1"
Invoke-Expression "& $( $Cmd )"
Otherwise your script will just grind to a halt.
Yes - most any executable can be called from PowerShell. There isn't anything peculiar about pscp.exe in this regard. You may need to preface it with the call operator - the ampersand - &:
PS C:\>& "C:\Program Files (x86)\Putty\pscp.exe" -V
pscp: Release 0.62
The above is direct output from my PowerShell prompt. The call operator is particularly helpful if the path to your executable contains spaces - the call operator is used to tell PowerShell to treat what would be considered a string as something it should try to execute instead.
Please include the full command your are trying to execute as it will help in providing a better answer. You may have a problem with your PATH variable or something else weird if you don't get any output.
If using pscsp from inside a script, e.g. perl
no ampersand
quote like this "my password"
e.g.
"C:\Program Files\Putty\pscp.exe" -C -p -pw "password" /local_dir/file_to_copy user#hostname:/remote_directory
in perl (beware that \ is an escape char in a "string" )
$cmd = q("C:\Program Files\Putty\pscp.exe" -C -p -pw "password" /local_dir/file_to_copy user#hostname:/remote_directory);
system($cmd);

Resources