43

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?

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • You double quotes aren't matched - perhaps that is an SO formatting issue. BTW if you are on PowerShell 2.0 you should use -file e.g. powershell -file c:\data\etc\run_import_script.ps1 – Keith Hill Jan 11 '10 at 16:14
  • @Keith, the three quotes are intentional, see here: http://stackoverflow.com/questions/2035193/how-to-run-a-powershell-script I am on 1.0 but considering changing over. Cheers. – Pekka Jan 11 '10 at 16:33
  • any final solution with full source code about it ? – Kiquenet Jul 31 '12 at 07:43

10 Answers10

24

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

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
Jason Swager
  • 6,421
  • 6
  • 41
  • 56
21

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

Gordon Smith
  • 311
  • 2
  • 3
  • 8
    Thanks for this, very useful. I found an alternative that works when not launching from a shell (and not in control of the streams) is to use the "-InputFormat None" argument to powershell.exe to disable the input stream. – chillitom May 05 '15 at 16:22
17

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"
aphoria
  • 19,796
  • 7
  • 64
  • 73
  • 2
    Cheers, this works great, but I can't capture Powershell's output that way - which I need to include in the console output in case there's an error. – Pekka Jan 11 '10 at 17:58
  • Not sure about the part where PS appears to be hanging. What is happening inside the PS script? Perhaps it is something subtle that only appears when called from a script. Weird I know, but I've seen it before. Also, I think %ERRORLEVEL% is going to have the results for PowerShell.exe, but the results of the script. So, as long as PowerShell.exe runs to completion, it will return 0, regardless of what happened inside the .ps1 script. – aphoria Jan 11 '10 at 19:41
  • You also can add /MIN parameter to minimize the powershell window during execution. – Monsignor Oct 06 '11 at 06:57
14

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.

Ormoz
  • 2,975
  • 10
  • 35
  • 50
Gretski
  • 461
  • 4
  • 7
  • 1
    Thank you for this answer. This solved an issue we have using bamboo agent server and powershell scripts. – Eddietec Aug 30 '16 at 10:27
  • Thank you, worked also for me, instead of having "Exit" inside the ps1 file. – Stefano Nov 29 '16 at 11:29
  • 1
    Great! I'd this issue on a server with PS2, and this has worked out. I've added it inside the .ps1, and instead of `$lastexitcode`, I can pass it whatever I need. Thanks! – curropar Jun 21 '17 at 12:48
  • I also ran into this need in the context of a legacy environment (i.e. Windows 7) running PS v2.0. – BuvinJ Dec 29 '20 at 00:35
3

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

Stephen Connolly
  • 1,639
  • 10
  • 15
1

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

Dennis Hostetler
  • 614
  • 7
  • 10
0

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!
Goyuix
  • 23,614
  • 14
  • 84
  • 128
  • 1
    Cheers Goyuix, this is very good to know. Sadly, even this way the behaviour is the same: Execution just freezes. I get no output whatsoever. I can Ctrl+C the whole thing any time, but nothing will happen. If I use `START /WAIT powershell.exe` as suggested in the other answer, it runs, but I can't catch the output. Very strange... – Pekka Jan 11 '10 at 18:00
0

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.

Deadly-Bagel
  • 1,612
  • 1
  • 9
  • 21
0

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
person
  • 154
  • 1
  • 7
0

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

Tim
  • 1