I want to execute a simple command (to delete a directory) when PowerShell exits.
So far I have this:
Register-EngineEvent PowerShell.Exiting -SourceIdentifier –Action { cmd.exe /c "D:\removedir.bat" }
Off course the .bat file works, but not when PS closes. I have tried several things inside the ScriptBlock like: Start-Process, Invoke-Item, etc. to execute the .bat file after PS exits, but I am running out of ideas.
As mentioned in the comments, the conceptual event you want to react to is not "PowerShell is exiting", but rather "My code is done executing".
For this, you'll want a try/finally statement:
try {
# Start by placing your existing code in the `try` block as-is
& GenericScript.ps1 #paramArgs
}
finally {
# ... and then perform your cleanup tasks once the `try` block is done executing.
Perform-Cleanup
}
The finally block will execute immediately before exiting the try block - in other words, if all the code in the try block executed successfully, the finally code will execute right after as usual (as if the try/finally statements weren't there at all) - but if any terminating errors are thrown by the code in the try block, the finally block will still execute before control is returned to the caller - which sounds like exactly the kind of guarantee you're looking for :)
Related
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.
For example I can directly call myscript.cmd or in other script I can put a line to myscript.
The reason is that if a script is run on it's own it dissapears as soon as it stop executing, so I can't see the result, so at the end I must add #pause but when I run it from another shell this causes annoyance since console window wouldn't exit that way.
So I look for some kind of 'if' condition to address this issue.
To get your script paused when double-clicked (or by dropping files on it), but terminating the usual way when invoked from console:
#echo off
echo Hello World!
:: ...your ScriptCode...
(((echo.%CMDCMDLINE%)|find /I "%~0")>NUL)&&pause
Unless you create an environment variable like Stu suggested, you're not going to find any that do what you want. You're going to need to write a small program that queries the parent process programmatically and returns a value your script can check. If you're being run from Start->run your parent will be explorer.exe. Otherwise it will be cmd.exe or some other exe.
Sample code to find the parent process can be found here.
Why not set it yourself?
SET RUNNINGFROMOTHERSHELL=YES
CALL MYSCRIPT.CMD
SET RUNNINGFROMOTHERSHELL=
In MyScript.Cmd:
IF "%RUNNINGFROMOTHERSHELL%"=="" GOTO NOPAUSE
PAUSE
:NOPAUSE
I'm trying to run a script, which internally invokes other script
but, the main script should exit after invoking and the invoked script should run independently on the background.
How can i achieve this in shell scripting? or is there any other alternative way to do this?
Regrads,
senny
nohup otherscript &
The nohup will ensure that the process keeps running even if the current terminal goes away (for example if you close the window).
(Just to make it clear: the "&" puts the other script in the background, which means the first will keep running, and the second script won't exit when the first one does.)
If your script is in Perl, use exec() command to start the second script.
exec() returns immediately after executing the command, and the calling script can exit, while the second script keeps running.
http://perl.about.com/od/programmingperl/qt/perlexecsystem.htm
I have a batch file that is located on one machine that I am invoking remotely from another machine. That batch file is pretty simple; all it does is set some environment variables and then executes an application - the application creates a command window and executes inside of it. The application it executes will run forever unless someone types in the command window in which it is executing "quit", at which point it will do some final processing and will exit cleanly. If I just close the command window, the exit is not clean and that is bad for a number of different reasons related to the data that this application produces. Is there a way for me to perhaps write another batch script that will insert the "quit" command into the first command window and then exit?
I'd write a little script using the subprocess module in python, like so:
from subprocess import Popen, PIPE
import os
import os.path
import time
app = Popen(['c:/path/to/app.exe', 'arg1', 'arg2'], stdin=PIPE, env = {
'YOUR_ENV_VAR_1': 'value1',
'YOUR_ENV_VAR_2': 'value2',
# etc as needed to fill environment
})
while not os.path.exists('c:/temp/quit-app.tmp'):
time.sleep(60)
app.communicate('quit\n')
print "app return code is %s" % app.returncode
Then, you remotely invoke a batch script that creates c:/temp/quit-app.tmp when you want to shut down, wait a couple of minutes, and then deletes the file.
Naturally, you need Python installed on the Windows machine for this to work.
It sounds like the type of job for which I'd use expect, though I've never used it under Windows.
You could use the < to take the "quit" from a text file instead of the console... but that would quit your process as soon as it loads. Would that work?
Otherwise you could write a program to send keystrokes to the console... but I don't think this is a production quality trick.
Do you have access to the actual code of the application? if so you can check for a batch file. Else you can do something like the following using powershell.
$Process = Get-Process | Where-Object {$_.ProcessName -eq "notepad"}If (!($Process))
{ "Process isn't running, do stuff"
}Else
{ $myshell.AppActivate("notepad")
$myshell.sendkeys("Exit")
}
I am only suggesting powershell as its easy for you to call the code. you could also put in a loop and wait for it to run.
RE
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).