I have a batch script which is run from an AT command, and may get run more than once. When it starts, I need it to detect if it already running, and if so, exit (the second one) immediately.
- It must be robust, and handle if the scripts exits unexpectedly (i.e. so I can't set a flag on entry and clear it on exit)
- It must run in a Remote Desktop session
- I'm stuck on XP with Powershell v2, but don't mind writing a little exe if I can't do it in batch/powershell or vbs
- The script must run minimised, so I start it with Start "NAME" /MIN %COMSPEC% /C "MyScript.bat"
- Other cmd windows may be open so I need to check the running script
- The batch script runs as SYSTEM user, but I can't use any WMI
I was using PowerShell Get-Process to look at MainWindowTitle, but this didn't work when remote connecting to the computer as the script may be running, but not displayed in this remote connection instance. I this case, the cmd process is seen by Get-Process, but the MainWindowTitle is blank.
I've tried Get-Process and looked at the expanded StartInfo.EnvironmentVariables property, but can't see how to create an env var so that it appears in the property.
I thought about using /WAIT in the start command, then the AT will remain open until it finishes, but the script containing the AT is not minimised
Any ideas?
Answer
I believe a lock file is the simplest reliable solution. The trick is to make sure your running batch process maintains an exclusive write lock on the file until it terminates. The beauty of this system is that Windows will release the lock no matter what reason the batch terminates.
Once you have a lock file, you need a way to detect if the file is currently locked. I describe how to do this at How to check in command-line if a given file or directory is locked (used by any process)?
I've used this primitive, yet effective, technique to accomplish some fairly sophisticated tasks with Windows batch:
You are not clear where the batch file resides - on the remote machine, or the local machine, or if you might be running the script on multiple machines simultaneously, but only one active process per machine.
If the batch script is on the remote machine, and your process has write access to the script, then you can use the batch file itself as the lock file! You simply need to call a :subroutine while redirecting an unused file handle to the batch script using append mode. The CALL will fail if another process already has a lock. The lock will be released automatically when the script terminates (regardless of how it terminates).
myscript.bat
@echo off
:: Note - this extra call is to avoid a bug with %~f0 when the script
:: is executed with quotes around the script name.
call :getLock
exit /b
:getLock
:: The CALL will fail if another process already has a write lock on the script
call :main 9>>"%~f0"
exit /b
:main
:: Body of your script goes here. Only one process can ever get here
:: at a time. The lock will be released upon return from this routine,
:: or when the script terminates for any reason
exit /b
If your script is on a different machine than the process, but you only have the process running on one machine at a time, then I think the above will still work.
Perhaps a better alternative is to establish a dedicated lock file on each remote machine, separate from the batch script. Then you can run the process on as many remote machines as you want.
No comments:
Post a Comment