Windows batch file to connect to share and execute app - windows

I have a batch file running on Windows 7 x86. I am trying to script a connection to a share and then once that is done to execute an app.
net use \\appserver001\mycompany.ptshare\OPS /user:geek xyz!## /persistent:yes
echo %errorlevel%
if errorlevel 2 goto message
if errorlevel 1 goto message
start "" "\\appserver001\mycompany.ptshare\OPS\OPSapp.exe"
echo %errorlevel%
if errorlevel 2 goto message
if errorlevel 1 goto message
goto end
:message
cls
echo ERROR IN CONNECTING TO SERVER
:end
The NET USE connection is made as the command window says "The command completed successfully". Then when it reaches the line to execute the app I get a pop-up message "Invalid location for program!".
I swear I have done his before but cant figure out why it will not run my app.

"Invalid location for program!" sounds like an error message that could come from OPSapp.exe itself. You could verify that by opening Task Manager and checking whether OPSapp is listed in the Processes tab when the error pops. If that's not the case then you may ignore the rest of this post.
Some programs require to be launched from a drive-letter based path (e.g. X:\etc\app.exe) rather than a UNC path (e.g. \\srv\etc\app.exe). Such a program can check at startup the location where it's been started from, then pop an error message and exit if it's a UNC path, instead of the drive-letter based one it expects.
The workaround in such cases is to (temporarily) map a drive letter to the network share, then use it to launch the program. For example, in your case replace
start "" "\\appserver001\mycompany.ptshare\OPS\OPSapp.exe"
with
pushd "\\appserver001\mycompany.ptshare\OPS"
start "" "OPSapp.exe"
If this still doesn't work, then it's possible that OPSapp expects more than just a drive-letter based path, perhaps a particular directory structure someplace, or registry entries etc - in other words it may not be portable enough to be simply runnable by path.

Related

How to run a java process in the background and exit from script

I am trying to convert a bash script to batch, but I am having a trouble for this one issue. The script runs a java server in the background, waits for 5 seconds, then exit with exitcode. But in batch, I am unable...
runserver.sh
java -jar java_server.jar &
pid=$!
sleep 5
kill -0 $pid
cmdStatus=$?
if [ $cmdStatus -ne 0 ]
then
exit 1
fi
exit 0
runserver.bat
#echo off
set EXITCODE=0
start /b java -jar java_server.jar
timeout /t 5
for /f "tokens=1 delims= " %%i in ('jps -m ^| findstr java_server') do set PID=%%i
IF "%PID" == "" (
set EXITCODE=1
)
EXIT EXITCODE
but if I run the above batchscript, I am never able to disown the java process and it never exists
The first mistake in batch file code is missing % in line IF "%PID" == "" to really compare the value of the environment variable PID enclosed in double quotes with the string "". So correct would be IF "%PID%" == "". For more details on string comparisons see Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.
The second mistake is not using two times % on last command line EXIT EXITCODE around the environment variable EXITCODE to reference its value which would be correct written as EXIT %EXITCODE%.
But the batch file should be better written as follows:
#echo off
cd /D "%~dp0"
start "" /B javaw.exe -jar "%~dp0java_server.jar"
%SystemRoot%\System32\timeout.exe /T 5 /NOBREAK >nul
jps -m 2>nul | %SystemRoot%\System32\findstr.exe /L "java_server" >nul
The batch file first makes the directory of the batch file the current directory because of java_server.jar is most likely in directory of the batch file. %~dp0 expands to drive and path of argument 0 which is the batch file. The file path referenced with %~dp0 always ends with a backslash which is the directory separator on Windows which should be taken into account on concatenating this string with a file or folder name. The command CD fails only if the batch file is stored on a network resource accessed with a UNC path because of Windows prevents by default that a directory referenced with a UNC path instead of a drive letter becomes the current directory for downwards compatibility reasons because of many console applications work not correct with current directory not being on a drive with a drive letter.
The command START interprets first double quoted string as title for the console window opened on running a Windows console application in a separate command process. In this case no console window is opened because of using option /B although java.exe is a Windows console application. For that reason explicitly specifying an empty string with "" as window title like on starting a Windows GUI application is advisable to avoid that any other double quoted argument string is interpreted as optional window title.
The option /B is interpreted as background. Most people think that the started application is detached from current command process. This is true for Windows GUI applications, but not for console applications like java.exe. The handle STDIN of current command process is bind with STDIN of started console application. Also the output to the handles STDOUT and STDERR of started application are redirected to console window of the running command process which nevertheless continues immediately with execution of batch script. The option /B means just running the console application parallel to current command process without opening a new console window, but not in running the application completely detached from running command process.
The solution is quite simple in this case because there is also javaw.exe, the Windows version of Java designed for running a Java application completely in background detached from the process starting it.
A batch file for general usage works best on specifying all files with full qualified file name which means with full path, file name and file extension. Java executable can be installed everywhere and so the folder path for this executable can't be specified in the batch file. Windows command processor has to find the executable javaw in current directory or in any folder in list of folders of local environment variable PATH. But it is at least possible to specify the executable javaw with its file extension .exe as this file extension is well known.
The JAR file java_server.jar is specified with full path on assuming that this file is stored in same directory as the batch file. The batch file directory should be already the current directory and so %~dp0 would not be needed at all, but it does not matter to specify the file for safety with full path.
Next the standard Windows console application TIMEOUT is called with full qualified file name with options to wait 5 seconds unbreakable (requires Windows 7 or newer) and redirecting its output to device NUL.
I don't know anything about the file jps and have not even installed Java. For that reason I assume jps is an executable or script of which file extension listed in local environment variable PATHEXT and stored in directory of the batch file or any other directory of which path is listed in local environment variable PATH. It would be of course better to specify this file with file extension and if possible also with full path.
The standard output of jps is redirected to standard input of Windows standard console application FINDSTR and the error output to device NUL to suppress it.
FINDSTR runs a case-sensitive, literal string search for java_server on standard output of jps. The output of FINDSTR is of no interest and therefore redirected also to device NUL to suppress it.
FINDSTR exits with 0 on searched string really found and with 1 on nothing found. The batch file should exit with 1 on not successfully starting Java server and with 0 on Java server running. This matches exactly with exit code of FINDSTR and so nothing else must be done.
cmd.exe exits the execution of a batch file always with last exit code set by an application or command during batch file execution. This can be verified on commenting out second command line with rem and save it, running this batch file from within a command prompt window and running next in command prompt window if errorlevel 1 echo Java server not running! resulting in expected output Java server not running!. Then rem needs to be removed from second command line of batch file before saving the batch file which is run once again from within the command prompt window. After second batch file execution finished, running once again if errorlevel 1 echo Java server not running! results in no output while running if errorlevel 0 echo Java server is running. results in output Java server is running. as expected.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~dp0
cd /?
echo /?
findstr /?
if /?
start /?
See also:
Microsoft article about Using command redirection operators
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?

How to get 2 CMD windows to 'talk' to each other?

I am probably missing the right vocabulary to talk about this problem more succinctly so excuse me if I'm a little wordy here. Under Windows 10 I have a program that runs inside a CMD command prompt It's an executable called OpenSim and it has it's own extensive command set, including 'shutdown', which initiates a graceful termination of the processes therein, closes SQL connections etc, then finally closes the CMD command window. I also have a CMD .bat file that is activated by my UPS when the power goes down that will of course open it's own window, and then does some housekeeping before closing down the hardware. One thing I want the .bat file to do is to somehow insert a 'shutdown'command into the other window's process. Is that possible? If so, how? Please assume I am a total newbie at this and you won't go far wrong. Thank you.
EDIT It looks like creating a file to flag the closedown event taking place is the only (and I guess rather primitive) way to do this. So, building on what others have said in stackoverflow, I have the following now. When I run it to test it waits - it doesn't. It runs right through to the end, running 'shutdown', even though the UPSFLAG.TXT file does not exist. What's going wrong?
echo Waiting for UPS Power Down Signal.
echo =================================
#ECHO OFF
SET LookForFile="C:\Opensim OSGrid\UPSFLAG.TXT"
:CheckForFile
IF EXIST %LookForFile% GOTO FoundIt
REM If we get here, the file is not found.
REM Wait 10 seconds and then recheck.
REM If no delay is needed, comment/remove the timeout line.
TIMEOUT /T 10 >nul
GOTO CheckForFile
:FoundIt
ECHO Found: %LookForFile%
rem Tidy up
del "C:\Opensim OSGrid\UPSFLAG.TXT"
shutdown
Adding double quote after the = will save your variable as that "C:\Opensim OSGrid\UPSFLAG.TXT" which you do not want. rather you want to store it as C:\Opensim OSGrid\UPSFLAG.TXT so move the quote to before lookforfile.
Also, you created a variable for the file, so you might as well use it in the delete.
Finally, as a safety measure, always put an exit after a goto. That will ensure the system exists should there be a problem in the script and you can make sure you do not delete files or shutdown the system when it was not planned for.
echo Waiting for UPS Power Down Signal.
echo =================================
#ECHO OFF
SET "LookForFile=C:\Opensim OSGrid\UPSFLAG.TXT"
:CheckForFile
IF EXIST "%LookForFile%" GOTO FoundIt
REM If we get here, the file is not found.
REM Wait 10 seconds and then recheck.
REM If no delay is needed, comment/remove the timeout line.
TIMEOUT /T 10 >nul
GOTO CheckForFile
exit
:FoundIt
ECHO Found: %LookForFile%
rem Tidy up
del "%LookForFile"
shutdown

Start a Windows service from a batch script and take appropriate action based on result

I have a .bat script that attempts to start a Windows service at the end.
:start_wildfly
echo.
set /p wildfly_service_name="Enter Wildfly service name: "
echo INFO: Starting %wildfly_service_name%...
echo.
call net start "%wildfly_service_name%"
I want to be able to interpret the result of the net start attempt so that I can have my script take the appropriate action if it fails (e.g. if the service is already running, restart it. If the service name is invalid, re-prompt for the name again, if the user doesn't have sufficient privileges, exit).
The problem is that the NET command does not return the documented Win32_Service class codes.
It does echo errors on the console, however:
The requested service has already been started.
More help is available by typing NET HELPMSG 2182.
See http://ss64.com/nt/net_service.html for a list of the errors.
Unforunately, the errorlevel variable is always 2 in these error cases, so I can't rely on that.
What I'm now trying to do is run a FIND on the output of the NET command, searching for specific error codes and act upon them.
net start Wildfly 2>&1 | FIND "2182"
if %errorlevel% equ 0 goto service_already_running
So, the result of the FIND is stored in errorlevel and I can check to see if the FIND succeeded by checking if errorlevel is 0. This works.
Now, the problem comes when I want to check for more than one error code. I don't know how to expand the code above to check for "2185" as well, for example, and goto a different label in that case.
I'm now attempting to store the entire result of the NET command into a variable, and then run a FINDSTR on that variable.
setlocal EnableDelayedExpansion
set "output_cnt=0"
for /F "delims=" %%f in ('dir /b') do (
set /a output_cnt+=1
set "output[!output_cnt!]=%%f"
)
for /L %%n in (1 1 !output_cnt!) DO echo !output[%%n]!
This should store and echo each line of the output, however the last line doesn't seem to do anything.
And then I've also found some code that should search within a variable and return whether or not that string was found:
echo.%output%|findstr /C:"2182" >nul 2>&1 && echo Found || echo Not found.
I've had no luck putting it all together though. I just want to be able to interpret the result of the NET START <SERVICE> and jump to certain labels based on the result.
I want to be able to interpret the result of the net start attempt
so that I can have my script take the appropriate action if it fails (e.g. if the service is already running, restart it. If the service name is invalid, re-prompt for the name again, if the user doesn't have sufficient privileges, exit).
Start the service as you are already doing:
net start "%wildfly_service_name%"
Now check the status of the service.
There are two ways to do this.
Use net start again to see if the service is running:
net start | find "%wildfly_service_name%" > nul
if errorlevel 1 echo The service is not running
Use sc (Service Control) to check the service status:
SC query %wildfly_service_name% | find "STATE" | find "STOPPED"
Or
sc query %wildfly_service_name% | find "STATE" | find "RUNNING"
The two statements above will return %errorlevel% = 1 if the text is not found.
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
net - The NET Command is used to manage network resources.
sc - Service Control - Create, Start, Stop, Query or Delete any Windows SERVICE.
Taking DavidPostill's answer of using net start to check the status of the service, here is my new solution:
echo.
echo INFO: Starting %wildfly_service_name%...
echo.
:verify_not_running
net start | find "%wildfly_service_name%" > nul
if %errorlevel% equ 0 goto restart_wildfly
:start_wildfly
net start "%wildfly_service_name%"
goto verify_running
:restart_wildfly
echo The %wildfly_service_name% service is already running. Will now restart...
net stop "%wildfly_service_name%"
net start "%wildfly_service_name%"
:verify_running
net start | find "%wildfly_service_name%" > nul
if errorlevel 1 goto start_wildfly
This script will first verify the service is not running.
If the service is already running, it will restart the service.
In either case, I check at the end to make sure the service is now started. If not, repeat the process over again.
Note that I no longer have a requirement to check that the service name was valid. The service name is now hardcoded earlier in the script so it is assumed to be correct.
And to handle the case of insufficient privileges, I added this snippet at the beginning of the script:
:check_permissions
net session >nul 2>&1
if errorlevel 1 (
echo.
echo ERROR: This script must be run as an Administrator. Please re-run the script from an elevated command prompt.
echo.
echo Right-click "cmd.exe" from the Start menu and select "Run As Administrator".
exit /b %error_level%
)
You're right; the net command apparently always returns 2 for any kind of error. However, you can use the sc start command as a drop-in replacement for net start, and that one does indicate different errors through distinct exit statuses, in particular 1056 for An instance of the service is already running. So, you can use use
sc start "%wildfly_service_name%"
And then check %errorlevel% afterwards.

Read variable from external file not working on running as scheduled task

I would like to run a batch file after resuming from sleep state in Windows.
If I start the batch file on command line everything works as expected.
But the batch script does not run properly as scheduled task.
What I have done:
External config file AutoMountConf.bat contains set Pass = Test
Local script file scheduleTask.bat contains
rem AutoMountConf.bat is in my intranet.
call X:\AutoMountConf.bat
start "" "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
On command line the TrueCrypt container is mounted.
If I run the script from scheduled task I get the login screen to type the password manually.
There are two or perhaps even three issues.
The first one is set Pass = Test instead of set "Pass=Test" as Stephan reported already. For more details on how to assign a value right to an environment variable see my answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The second issue is caused by the fact that network drives once mapped by a user to a drive letter and remembered in registry by Windows are automatically disconnected by Windows on user logs off and are only reconnected if the same user logs on again.
For a scheduled task it is therefore very often necessary to use UNC paths for files and folders on a shared folder in network or connect the network drive and disconnect it in the batch file itself executed as scheduled task.
It is not possible to call a batch file with UNC path. Windows does not allow that. Therefore it is necessary to connect and disconnect to network share manually in the batch file. I offer 2 solutions for this problem.
The first one is using command net use:
%SystemRoot%\System32\net.exe use X: \\ComputerName\ShareName password /user:Domain\UserName /persistent:no
if not errorlevel 1 (
call X:\AutoMountConf.bat
%SystemRoot%\System32\net.exe use X: /delete
start "" /wait "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
)
password and /user:Domain\UserName is necessary only if the scheduled task is not executed with a user account which has the permissions to access the batch file on the remote machine. In general it is much more secure to define the scheduled task with the right user account and safe the password also for this account together with the task. Windows stores the password for the task encrypted like it does it also for the user account itself.
Run in a command prompt windows net use /? for details on the required and optional options. /persistent:no is what avoids remembering the network share in Windows registry for automatic reconnect after login by same user.
The second one is using commands pushd and popd:
pushd \\ComputerName\ShareName
if not errorlevel 1 (
call AutoMountConf.bat
popd
start "" /wait "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
)
Please execute in a command prompt window pushd /? and read the output help to understand why this works.
But this solution requires that the user account used for the scheduled task with correct password is one which has appropriate permissions on the share on the remote computer. Password and user name can't be specified with this solution in the batch file itself.
if not errorlevel 1 means if previous command exited NOT with a value greater or equal 1 meaning if exit code of previous command is 0 and therefore command execution was successful. It can always happen that the remote machine is currently not available on network and therefore it is always good to check success on connecting to share on remote machine.
There is perhaps one more reason why Pass is not defined after running AutoMountConf.bat.
AutoMountConf.bat contains setlocal and the variable Pass is defined after this command was executed and before endlocal is executed in same batch file or implicitly called by command processor on exiting AutoMountConf.bat.
setlocal results in creating always a copy of existing environment variables and all modifications on environment variables are done on this local copy. The previous environment variables are restored on execution of (matching) endlocal or when end of a batch file is reached in which case the command processor automatically restores previous environment.
Please execute in a command prompt window setlocal /? and read the output help.
For examples to understand environment management by commands setlocal and endlocal perhaps even better see answers on Echoing a URL in Batch and Why is my cd %myVar% being ignored?
set Pass = Test
sets a variable pass<space> with the Content <space>Test. So %pass% keeps empty.
use this Syntax:
set "Pass=Test"
to avoid any unintended spaces.

MS-DOS FTP command in a batch file: raise error

In MS-DOS (Windows 2003 R2 Server), I have a batchfile which has the FTP command in it, eg:-
FTP.CMD
-------
cd d:\extracts\scripts
ftp -i -s:ftp_getfile.ftp
exit
I would like the batch file to raise and return an error level 1 for failure instead of 0,
so that the calling batchfile can deal with it.
The error could be caused by the FTP server being down. Right now, nothing is returned to indicate
an error condition occured.
Please can someone advise?
Thanks! :)
Maybe too late, but it is possible. I'm running the following script to check for errors in the text that's returned by the FTP script. If you know the error text that's returned by FTP, then that's what you look for with the 'find' command.
The ftp commands are in a file called ftp.inp, just check out the help of FTP on how to use '-s'.
ftp -s:ftp.inp > ftp.log
find /I /C "not connected" ftp.log
IF NOT ERRORLEVEL 1 GOTO FTPERROR
find /I /C "not found" ftp.log
IF NOT ERRORLEVEL 1 GOTO FTPERROR
find /I /C "failed" ftp.log
IF NOT ERRORLEVEL 1 GOTO FTPERROR
REM --- no errors found
GOTO :END
:FTPERROR
REM --- error found
:END
As per this question:
How to capture the ftp error code in batch scripts?
The windows FTP command doesn't support this behaviour (or PASV mode) and is basically next to useless.
You might want to try NcFtp instead. It's free, small, portable, and has decent error codes.

Resources