Error level not changing when file is ran with psexec - windows

I have one piece of code that is behaving differently when I ran it on server and when I ran it with psexec. I'm actually trying to determent is computer offline, but that is not question here. Problem is that when I run this command directly on server errorlevel is changing to 1, because pc is online. But when I use psexec to run file with same commands on that server errorelevel is not changing it stays 0. I cant find any explanations on internet.
echo %errorlevel%
ping -n 1 machine | findstr "not" > nul
IF %errorlevel%==0 (
echo test
)
echo %errorlevel%
pause

What you show is not a command, but a batch file, say ping_machine.cmd. To call it from psexec the command line would be something like psexec \\server cmd /c ping_machine.cmd. If I guessed wrong you may stop reading the rest of this answer now (and next time post enough relevant context so that one doesn't have to guess).
Problem is that cmd /c returns the exit code of ping_machine, but the batch file does not explicitly set an exit code, so it returns 0 by default. This can be verified at the cmd prompt with the following 2 runs - note that inside the batch file you see the same/correct errorlevels, but cmd /c returns 0.
C:\etc>ping_machine
0
1
Press any key to continue . . .
C:\etc>echo %errorlevel%
1
C:\etc>cmd /c ping_machine
0
1
Press any key to continue . . .
C:\etc>echo %errorlevel%
0
To have cmd /c behave as you expect (and in turn psexec as well), add the following line at the end of the batch file to return the respective errorlevel (this works because neither echo nor pause modify the errorlevel, otherwise you'd have to save it in a temp variable for later use).
exit /b %errorlevel%

There it is. When I run this batch file locally errorlevel is changed to 9009. When I use psexec \\computername -f -c pathToFile , error code is staying 0.
#echo off
echo %errorlevel%
pin 234343
echo %errorlevel%
pause

Related

cmd /c <batch-file> exit code is sometimes 0 even on error?

I have a batch file that I run from an msysgit bash shell script via cmd /c a.bat and then I test the exit code to determine whether or not to continue. When the batch file fails, from wherever it fails, exit /b 1 is called and the batch file exits with code 1.
I recently noticed that if the batch file fails at one point where exit /b 1 is called that the exit code is not returned, and is instead 0. It only happens in an inner block. Here's an example:
#echo off
if foo EQU foo (
if bar EQU bar (
echo Exiting with code 99.
exit /b 99
)
echo this line is necessary to reproduce the issue
)
That should always exit 99, but:
X:\j\tmp>doesnotexist
'doesnotexist' is not recognized as an internal or external command,
operable program or batch file.
X:\j\tmp>echo %ERRORLEVEL%
9009
X:\j\tmp>cmd /c a.bat
Exiting with code 99.
X:\j\tmp>echo %ERRORLEVEL%
0
X:\j\tmp>cmd /c call a.bat
Exiting with code 99.
X:\j\tmp>echo %ERRORLEVEL%
99
If the last echo line is removed then cmd /c a.bat does return exit code 99. And as I mentioned in the actual batch file the exit /b <Code> does work most of the time.
I can reproduce in Windows 7 and 10. My question is why does it not return the exit code in the repro above? Is it a bug or something I did wrong? As you can see I tried CALL on a hunch and it seems to remedy this issue, but I'm not sure why. CALL is supposed to be for calling one batch from another without losing control.
You are starting a new cmd.exe instance which will produce the 99 error in the new window instead of current window.
The reason why you are getting the correct code when running it using call is purely because you are telling it to run the batch file in the current console, hence you get exit code 99
So you do not need to run cmd /c to start the file. Instead run the batch file simply as:
c:\path_to\file\a.bat
or if in the path or current directory:
a.bat
When you call cmd /c, you're creating a new cmd.exe process, and that process is calling your script. So the errorcode variable within that new process is set to 99 but then the cmd process exits successfully, setting the level back to 0 in your starting command prompt.
If you just run a.bat, the error level gets set properly. If you try cmd /k a.bat, the new cmd will be still running, and you'll be able to see that the error level is 99. Then, depending on how you exit, the error level of the original cmd will be set appropriately.

Batch to check if process exists

I'd like a batch that will check if the process firefox.exe exists (after it has been started by the start command).
If the process exists, it will go to the label :fullscreen,
else the batch will go the the label :timeout. Then, it will check again if the process firefox.exe exists and if not, it will go again to the label :fullscreen until the process exists.
Here is my batch:
#echo off
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
:timeout
timeout /t 5
:fullscreen
nircmd sendkeypress F11
exit
How can I do this check ?
You can also use QUERY PROCESS:
#Echo Off
If Not Exist "%ProgramFiles(x86)%\Mozilla Firefox\firefox.exe" Exit/B
Start "" "%ProgramFiles(x86)%\Mozilla Firefox\firefox.exe"
:Loop
Timeout 5 /NoBreak>Nul
QProcess firefox.exe>Nul 2>&1||GoTo :Loop
NirCmd SendKeyPress F11
I suggest for this task the batch file:
#echo off
start "" /max firefox.exe
if errorlevel 1 goto :EOF
set LoopCount=0
:WaitLoop
%SystemRoot%\System32\timeout.exe /T 5
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq firefox.exe" 2>nul | %SystemRoot%\System32\find.exe /I "firefox.exe" >nul
if not errorlevel 1 nircmd.exe sendkeypress F11 & goto :EOF
set /A LoopCount+=1
if not %LoopCount% == 6 goto WaitLoop
Let me explain the few command lines used here.
1. Starting Firefox
The command START being an internal command of cmd.exe interprets the first double quoted string as optional title for the console window. Therefore the command line
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
results just in opening a new console window with the window title:
C:\Program Files (x86)\Mozilla Firefox\firefox.exe
For that reason "" is specified as first START argument to define an empty title. Firefox is a GUI application. So no console window is opened which means an empty window title is really enough.
The parameter /max would not be really necessary, but the goal is to get Firefox into full screen mode after starting. So why not starting it already maximized?
32-bit version of Firefox is by default installed in directory %ProgramFiles% on 32-bit Windows and in %ProgramFiles(x86)% on 64-bit Windows. But it is possible during the installation to install Firefox into any other folder. But Firefox installer is well coded and registers firefox.exe in Windows registry under key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
This is recommended by Microsoft as written in MSDN article Application Registration.
The command START searches also in Windows registry under this key for an executable specified as argument without path as explained in answer on Where is “START” searching for executables?
This is the reason for using just firefox.exe on START command line because that starts an installed Firefox independent on installation location.
START displays an appropriate message box if firefox.exe could not be started and exits in this case with a return code greater 0 (9059 in my test on one computer).
The help output on running if /? in a command prompt window explains how to evaluate the exit code of a previous command or application without usage of immediate or delayed environment variable expansion and therefore working anywhere in a batch file from MS-DOS (really!) to currently latest Windows 10.
The command line if errorlevel 1 goto :EOF means IF start failed to start firefox.exe indicated by an exit code greater or equal 1 THEN exit execution of this batch file. For details on exiting batch file execution see answer on Where does GOTO :EOF return to?
2. Checking for running Firefox
The command TASKLIST being an external command, i.e. a console application in system directory of Windows, outputs a list of running processes. This list can be already filtered by TASKLIST itself for a specific process as done in batch file with /FI "IMAGENAME eq firefox.exe".
But TASKLIST is designed for just printing a list of processes. It is not designed for checking if a specific process is running and returning the result to the calling process via exit code. TASKLIST always exits with 0.
But an error message is output to handle STDERR on using a filter and no process can be found in process list matching this filter. For that reason 2>nul is used to suppress this error message by redirecting it to device NUL. Read the Microsoft article about Using Command Redirection Operators for more information about redirection.
A simple method to get a simple false/true respectively 0/1 result on checking for running Firefox is filtering output of TASKLIST with external command FIND which exits with 0 if the string to find was indeed found or with 1 if the searched string could not be found in the text read in this case from STDIN. The output of FIND is of no interest and therefore suppressed with redirection to device NUL using >nul.
Instead of using TASKLIST and FIND it is also possible to use QPROCESS:
%SystemRoot%\System32\qprocess.exe firefox.exe >nul 2>&1
QPROCESS exits with exit code 1 if firefox.exe could not be found in list of running processes. Otherwise the exit code is 0 on firefox.exe is running.
3. Evaluating Firefox process checking result
if not errorlevel 1 nircmd.exe sendkeypress F11 & goto :EOF
The IF command checks if exit code of FIND is NOT greater or equal 1 which means if exit code is lower than 1. Command FIND exits never with a negative value. So if this condition is true then it is time to execute nircmd.exe to send key press F11 to application in foreground hopefully being Firefox (not guaranteed by this code) and exit batch file processing.
Otherwise the batch file should wait once again 5 seconds and then do the check again. This can very easily result in an endless running batch file in case of started Firefox is immediately closed by the user before the 5 seconds wait timed out. For that reason it is counted how often the wait loop is already executed. After 6 loop runs, or 30 seconds, it is really time to no longer wait for Firefox and exit the batch file.
4. Getting more information about used commands
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.
echo /?
find /?
if /?
qprocess /?
set /?
start /?
tasklist /?
timeout /?
And Single line with multiple commands using Windows batch file should be also read explaining operator & in addition to all other web pages referenced already above.
You can show a list of opened programs like this:
tasklist
To check if firefox exists:
EDIT: Code edited to show a fully working example
#echo off
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
goto :checkloop
:checkloop
tasklist|find "firefox.exe" > NUL
if %ERRORLEVEL% == 0 (
call :fullscreen
exit
) else (
call :timeout
goto :checkloop
)
:fullscreen
nircmd sendkeypress F11
goto :EOF
:timeout
timeout /t 5
goto :EOF

How to get return/exit code of a batch file started with START command?

I am trying to run a batch file with start /high and still get the return/exit code, i.e. %ERRORLEVEL%. The problem seems to be that command START does not return the exit code that the batch file returns.
We have a simple batch file for testing named BatFileThatReturnsOne.bat.
The contents of BatFileThatReturnsOne.bat are
EXIT /B 1
We are calling this as such:
start /high /wait BatFileThatReturnsOne.bat
But no matter what the batch file returns, the execution of start never has a %ERRORLEVEL% of anything other than 0 (zero).
This is all actually called by cfn-init in CloudFormation, but that is probably not relevant because we can reproduce it from a command line window.
The actual call is:
cmd.exe /C start /high /wait BatFileThatReturnsOne.bat
How do I get start to set the %ERRORLEVEL% to something other than 0 (zero)?
directly from a cmd window or a batch file you can use
start /high /wait cmd /c BatFileThatReturnsOne.bat
but if you need to start the cmd instance to execute the start command that launchs the batch file then you can use
cmd /v /e /c" start /high /wait cmd /c launched.cmd & exit ^!errorlevel^!"
Just change EXIT /B 1 by EXIT 1.
As explained in the Table 4 given in this answer about START /WAIT bat command:
When the started Batch file ends, set ERRORLEVEL = value from 'EXIT number' commmand.

cmd.exe closes instantly when running batch file

I'm trying to make a simple batch file that will let me pick from a list of programs and run them based on my choice. For reference this is what I have so far:
#echo off
:menu
echo 1. zsnes
echo 2. Project64
echo 3. MAME
echo 4. PCSX2
echo 5. VBA
echo 6. DOSBox
set /p emu=Pick your emulator [1-6]:
if %emu%=1 goto zsnes
if %emu%=2 goto project64
if %emu%=3 goto mame
if %emu%=4 goto pcsx2
if %emu%=5 goto vba
if %emu%=6 goto dosbox
:zsnes
start /d "C:\Users\*username*\Documents\zsnes\" zsnesw.exe
I've just typed out through the zsnes program to test it. The command prompt launches and will ask for me to pick a choice. When I select 1, cmd.exe instantly closes but the program is not run. I made a script that contained only the start line and it worked fine. When I open cmd.exe manually and type that line in it also works fine. It just doesn't work in the context of my script. What could be causing this? Any advice would be greatly appreciated!
because your if is not correct .
Try with
if %emu% == 1 goto zsnes
or
if %emu% equ 1 goto zsnes
and so on.
Some syntax errors in IF and FOR commands leads force exist of the script.
probably you'll want also
:zsnes
start /d "C:\Users\*username*\Documents\zsnes\" zsnesw.exe
goto :eof
to avoid executuion of the code under the other labels.
write the following line at the end of the code or where you want to stop / pause your cmd.exe
timeout \t -1
this will pause your cmd screen and give you an option to close it by asking Yes/No ?.
Exactly like the one before me said, "if" should be:
if %emu% == 1 goto zsnes
Additionally, add "pause" after your batch, so you can read the error-messages when something fails.

%ERRORLEVEL% is not working incase multiple commands on a Single line

I am trying the below commands and want to get exit of my process(%ERRORLEVEL%). But it is returning previous(last) executed exit code result of sample.exe. I want to get exit code of current command. My requirement is to execute multiple commands in single line*(not batch script)*.
Command:
cmd /c sample.bat "test" > c:\ouput.log & echo %ERRORLEVEL% > c:\returnCode.log
I even tried using "setlocal enableDelayedExpansion" like below. Still It is not returning the exit code of current command
cmd /c setlocal enableDelayedExpansion & sample.bat "test" > c:\ouput.log & echo %ERRORLEVEL% > c:\returnCode.log
Please let me know the way to get current command's exit code.
This should work:
cmd /V:ON /c sample.exe "test" > c:\ouput.log ^& echo !ERRORLEVEL! ^> c:\returnCode.log
/V:ON switch have the same effect of setlocal EnableDelayedExpansion. For further details, type: cmd /?
EDIT: Small error fixed, the & character must be escaped with ^, otherwise, the echo !ERRORLEVEL! command is not executed in the cmd /V:ON !!!
EDIT: Escaping the echo redirection via ^> causes just that echo to be piped into the log. If you do not escape that, the entire command is piped there, i.e. including the stdout stream from "sample.exe".
cmd /c sample.exe "test" > c:\ouput.log & call echo %%ERRORLEVEL%% > c:\returnCode.log
Should work for you. See endless SO items related to delayedexpansion
Thank for your response. I am able to get the exit code of current executed command with below command, only when I run through WMI class(Win32_Process). Using WMI client, I am executing the below command on Remote machine and it is working fine i.e. able to write exit code in Retrun.txt
Command:
cmd /V:ON /c sample.bat "test" > c:\Output.txt & echo !ERRORLEVEL! > c:\Return.txt
But if I run the same command in command prompt of the same remote machine, it is printing "!ERRORLVEL!" in Return.txt instead of "sample.bat" exit code.
I am curious to know why it is not working if I run from Command prompt of the same machine locally.

Resources