Batch File - Catching PSEXEC result - batch-file

If I run a successful PSEXEC command, it says this...
"cmd exited on workstation.domain with error code 0."
Is there any way I can prevent this and do something like
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
if %errorlevel%==0 (
echo Success!
) else (
REM display psexec error here.
)

Since my edit's were rejected...
Is the original code posted part of a larger script? If so then do you set your errcode to match the ERRORLEVEL environment variable?
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
REM display psexec error here.
)
Whenever attempting to detemine IF / THEN in batch and you use == you need to surrond the variable and the valuecheck in single " ' " marks. The above code corrects that issue for you as well as replaces errcode with ERRORLEVEL, which is the default environment variable for Windows.
Also, in practice I always use the following before any ERRORLEVEL check to drop the initial value to properly catch the error.
verify >nul
In this case I would do the following:
verify >nul
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
echo.Error is %ERRORLEVEL%; please see http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx for more details.
)
I added a weburl for checking on the error received.
Alternatively you could open the URL to the corresponding page automatically:
#ECHO OFF
verify >nul
set ERRCODE=0
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
set ERRCODE=%ERRORLEVEL%
)
IF %ERRCODE% LEQ 499 set MSERROR=681382
IF %ERRCODE% GTR 500 set MSERROR=681388
IF %ERRCODE% GTR 1000 set MSERROR=681383
IF %ERRCODE% GTR 1300 set MSERROR=681385
IF %ERRCODE% GTR 1700 set MSERROR=681386
IF %ERRCODE% GTR 4000 set MSERROR=681387
IF %ERRCODE% GTR 6000 set MSERROR=681389
IF %ERRCODE% GTR 8200 set MSERROR=681390
IF %ERRCODE% GTR 9000 set MSERROR=681391
IF %ERRCODE% GTR 12000 set MSERROR=681384
IF ERRCODE NEQ 0 start http://msdn.microsoft.com/en-us/library/ms%MSERROR%(v=vs.85).aspx
IF ERRCODE NEQ 0 echo.This failed with ERROR: %ERRCODE%
pause

For reference to psexec http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx
The first step when determining program results is to identify all of the return values and if it sets errorlevel.
#echo off
:: Method 1, Handle a single line of output. No errorlevel support
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= " ^| find /v "error code 0"`) do (
rem Display the error
echo.%%A
goto Failed
)
echo.Success
:Failed
:: Method 2, Handle multiple lines of output. No errorlevel support
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "`) do (
rem Check the status
for /f "usebackq delims=" %%X in (`echo."%%~A" ^| find /v "error code 0"`) do (
echo.%%X
)
for /f "usebackq delims=" %%X in (`echo."%%~A" ^| find "error code 0"`) do (
echo.Success
)
)
:: Method 3, Supports error level variable; only works if the called program supports it.
verify > nul
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "> nul
if %ERRORLEVEL% EQU 0 echo.Success
if %ERRORLEVEL% NEQ 0 echo.Error
:: Method 4, specific error message with error level, requires delayed expansion.
setlocal enabledelayedexpansion
verify > nul
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "`) do (
if !ERRORLEVEL! EQU 0 echo.Success
if !ERRORLEVEL! NEQ 0 echo.%%A
)
endlocal
pause

Related

.bat - ping list of IPs and reply with response time only

I'm stuck on this one, I've managed to create a batch file that imports list of IPs & hostnames but when I test for success or failure, I'd like to output how long it took. I don't know how to capture this and include it in the output. I'm trying to hide the default ping.exe output. Here's my code
#echo off
for /F "tokens=1,2 delims= " %%A in (computers.txt) do (
rem ping -n 1 %%A | findstr /i "TTL=" | find "Reply" > nul
if %errorlevel% == 0 (
echo %%B %%A successful ping in ?? Seconds
echo %%B %%A successful ping [%date%, %time%] >> log.txt
)
)
Pause
I've figured it out:
#echo off
setlocal enableDelayedExpansion
for /F "tokens=1,2 delims= " %%A in (computers.txt) do (
for /f "tokens=7 delims== " %%G in ('ping -n 1 %%A') do (
ping -n 1 %%A >nul
if errorlevel 1 (
echo %%B %%A unsuccessful ping
echo %%B %%A unsuccessful ping [!date!, !time!] >> log.txt
) else if "%%~G" NEQ "of" if "%%~G" NEQ "0" (
set ms=%%~G
set ms=!ms:ms=!
for /f %%Z in ('powershell !ms!/1000') do set second=%%~Z
echo %%B %%A successful ping in !second! seconds
echo %%B %%A successful ping [!date!, !time!] >> log.txt
)
)
)
Pause
Using FOR /F, it is possible to process command output.
As you may see, I have 2 ping -n 1 %%A. It is because FOR /F doesn't capture the ERRORLEVEL generated by the processing command. The first command gets the output, the second gets ERRORLEVEL.
if "%%~G" NEQ "of" if "%%~G" NEQ "0" filters out the unneeded results.
The powershell command converts milliseconds to second(batch file does not support decimal numbers)
I/O example
I don't have any other computers on my network, therefore I tested it with URLs.
Input -> Output
www.google.com A A www.google.com successful ping in 0.002 seconds
www.yahoo.com B B www.yahoo.com successful ping in 0.032 seconds
a.a.a C C a.a.a unsuccessful ping

How to force exit command line bat file when occur download error

Dears
Here is my .bat command line
I use bitsadmin /transfer command download from url.
but got error(like disconnect network...etc) I need continue execute remain command.
But now I can't get achievement... what should I do
#echo off
:: Filter updater for HCK and HLK
:::::::::::::::::::::::::: Settings :::::::::::::::::::::::::::::::::
:: Notice: As of July 2015, the HCK and the HLK filter updates are the exact same file, downloaded from the same location!
SET "source=https://sysdev.microsoft.com/member/SubmissionWizard/LegalExemptions/HCKFilterUpdates.cab"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SET "destination=C:\FilterUpdates.cab"
if not exist "%DTMBIN%\" (
echo ERROR: folder "%DTMBIN%"
echo does not exist! Please verify that you have the controller installed.
pause
exit /B 1
)
echo Please make sure that all instances of the Studio are turned OFF!
echo Downloading Filters...
bitsadmin /transfer "Downloading Filters" "%source%" "%destination%"
if errorlevel 1 goto end
echo Extracting...
expand -i "%destination%" -f:UpdateFilters.sql "%DTMBIN%\"
if not errorlevel 0 echo ERROR & exit /B 1
echo Installing...
pushd "%DTMBIN%\"
if not errorlevel 0 echo ERROR & exit /B 1
"%DTMBIN%\updatefilters.exe " /s
if not errorlevel 0 echo ERROR & exit /B 1
popd
:end
exit
Your problem could be caused by the errorlevels generated by bitsadmin: some of them are negative values and the test if errorlevel 1 will be evaluated as false (if errorlevel n is true for values greater than or equal to n)
You will need to read and test the value of the errorlevel variable
if not %errorlevel%==0 exit /b 1
But sometimes, bitsadmin will have errors and will generate a errorlevel 0, so, you need to manualy check the status
#echo off
setlocal enableextensions disabledelayedexpansion
:: Filter updater for HCK and HLK
:::::::::::::::::::::::::: Settings :::::::::::::::::::::::::::::::::
:: Notice: As of July 2015, the HCK and the HLK filter updates
:: are the exact same file, downloaded from the same location!
SET "source=https://sysdev.microsoft.com/member/SubmissionWizard/LegalExemptions/HCKFilterUpdates.cab"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
if not exist "%DTMBIN%\" (
echo ERROR: folder "%DTMBIN%"
echo does not exist! Please verify that you have the controller installed.
pause
exit /B 1
)
SET "destination=C:\FilterUpdates.cab"
if exist "%destination%" del /q "%destination%"
echo Please make sure that all instances of the Studio are turned OFF!
echo Creating download task...
set "taskName=[HCK_FilterUpdater]"
>nul (
rem remove task if already present
bitsadmin /list | find "%taskName%" && bitsadmin /cancel "%taskName%"
rem create the task
bitsadmin /create "%taskName%"
rem include our file in the task
bitsadmin /addfile "%taskName%" "%source%" "%destination%"
rem start the download
bitsadmin /resume "%taskName%"
)
echo Downloading...
set "exitCode="
for /l %%a in (1 1 500) do if not defined exitCode for /f "delims=" %%a in ('
bitsadmin /info "%taskName%"
^| findstr /b /l /c:"{"
') do for /f "tokens=3,*" %%b in ("%%a") do (
if "%%~b"=="TRANSFERRED" (
set "exitCode=0"
>nul bitsadmin /complete "%taskName%"
echo ... done
)
if "%%~b"=="ERROR" (
set "exitCode=1"
bitsadmin /geterror "%taskName%" | findstr /b /c:"ERROR"
>nul bitsadmin /cancel "%taskName%"
)
if not defined exitCode (
echo(%%b %%c
timeout /t 2 >nul
)
)
if not defined exitCode ( echo TIMEOUT & exit /b 1 )
if not exist "%destination%" ( echo ERROR & exit /b 1 )
echo Expanding...
>nul expand -i "%destination%" -f:UpdateFilters.sql "%DTMBIN%"
if errorlevel 1 ( echo ERROR & exit /b 1 )
echo Installing...
pushd "%DTMBIN%" || ( echo ERROR & exit /b 1 )
".\updatefilters.exe " /s || ( echo ERROR & exit /b 1 )
popd
It seems like once command shell is in bitsadmin mode you can't take it out of it. My solution unfortunately is two seperate .bats.

Batch - "for /F loop" inside "for /L loop"

I have following problem:
I want to create a batch file looping through an amount of ip addresses to stop a certain service on remote pc's.
Cause the stopping process takes some time I need to have a second loop to query the state of the service and waiting until the service reached the state STOPPED.
Set /p StartIP="Start IP (101): "
Set /p EndIP="End IP (199): "
for /L %%n IN (%StartIP%, 1, %EndeIP%) DO (
psservice -u username -p password \\192.168.8.&&n stop 'ServiceName'
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in ('psservice -u username -p password \\192.168.8.%%n query 'ServiceName' ^| findstr " STATE"') do (
if NOT %%H==STOPPED (
echo.
echo state: %%H
goto CHECK
)
echo.
echo state: %%H
)
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
Now the point I stuck to:
My range of numbers '%%n' from the /L loop is getting destroyed after passing the /F loop the first time.
With an example it looks like this:
Set /p StartIP="Start IP (101): 101"
Set /p EndIP="End IP (199): 105"
for /L %%n IN (101, 1, 105) DO (
psservice -u username -p password \\192.168.8.101 stop 'ServiceName'
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in ('psservice -u username -p password \\192.168.8.101 query 'ServiceName' ^| findstr " STATE"') do (
if NOT %%H==STOPPED (
echo.
echo state: %%H
goto CHECK
)
echo.
echo state: %%H
)
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
In this example I have the ip range 192.168.8.101 to 192.168.8.105.
The batch is running well until the /F loop is run trough the first time.
After this moment the %%n parameter from my /L loop is gone. The service can't start again, cause the %%n parameter already missing and my /L loop can't continue too -.-
Someone an idea what I can do to solve this problem?
Thank you already for reading this post.
As MC ND said in his comment, issuing a GOTO within a FOR loop will break the loop. Actually, the issue is more general than that - issuing a GOTO within any block of code (paranthesized, or concatenated via &) will terminate the remainder of the block.
The simple solution is to extract the code that needs GOTO and put it in its own subroutine, and then CALL the routine from within your loop.
Set /p StartIP="Start IP (101):"
Set /p EndIP="End IP (199):"
for /L %%n IN (%StartIP%, 1, %EndIP%) DO (
psservice -u username -p password \\192.168.8.%%n stop 'ServiceName'
call :check %%n
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
exit /b
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in (
'psservice -u username -p password \\192.168.8.%1 query 'ServiceName' ^| findstr " STATE"'
) do (
echo.
echo state: %%H
if not %%H==STOPPED goto CHECK
)
exit /b

Batch Script ErrorLevel Output

I need help - I am trying to output any ErrorLevel that is 1 or greater into a log file. When I issue the command the log file never get's generated. Any help would be greatly appreciated.
Script:
for /f "delims=" %%i in (C:\_\Restart\Computer.txt) do (
start "%%i" \_\PStools\psexec \\%%i -u Administrator -p Password -i c:\restart.cmd
if not %errorlevel%==0 echo %errorlevel% > error.log
)
This script allows me to use PSEXEC and issue a restart command to all the computer at once. However several of them fail and I'd like to know which ones fail.
Thanks!
Is this the format I should use?
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\_\Restart\Computer.txt) do (
start "%%i" \_\PStools\psexec \\%%i -u Administrator -p Password -i c:\restart.cmd
if errorlevel 1 echo !errorlevel! > error.log
)
Script V3:
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\temp\list.txt) do (
start "" "shutdown" /m \\%%i -r -f -t 900
echo !errorlevel! && echo %%i
if errorlevel 1 echo !errorlevel! >> c:\temp\log.txt && echo %%i >> c:\temp\log.txt
)
-m = use remote computer
-r = reboot
-f = Force reboot
-t = delay of time before rebooting
you can use shutdown -? for more help on argument that can be passed to the reboot command.
Script v4 without the start command:
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\temp\list.txt) do (
shutdown /m \\%%i -r -f -t 900
echo !errorlevel! && echo %%i
if errorlevel 1 echo !errorlevel! >> c:\temp\log.txt && echo %%i >> c:\temp\log.txt
)

Batch script that get hostname from list then pings hostname, if result then do stuff

From: Batch ERRORLEVEL ping response
I found this pice of code
for /f %%i in ('ping racer ^| find /c "(0%% loss)"') do SET MATCHES=%%i
echo %MATCHES%
I am trying to replace "racer" with an variable I get from a textfile:
for /f %%x in (computers.txt)
trying to nest 2 for loops gives me erros
After this I want to do something like this (not tried this code yet):
IF "%MATCHES%"=="0" (
shutdown /h /m \\%%x
) ELSE (
IF (
"%MATCHES%"!=="0"
)
echo "ping failed to %%x" >> failed01.txt
)
Try this:
#echo off
setlocal
for /f %%a in (computers.txt) do (
Call :IsPingable %%a && shutdown /h /m \\%%a || echo Ping failed to %%a >> failed01.txt
)
exit /b
:IsPingable comp
ping -n 1 -w 3000 -4 -l 8 "%~1" | Find "TTL=">nul
exit /b

Resources