WinSCP batch script - %ERRORLEVEL% always = 0? - batch-file

REM ---### FTP_Batch ###---
#echo off
REM Get first line record and store in %%A
setlocal enableDelayedExpansion
for /F "tokens=*" %%A in (FTP_Account_with_Password_and_EOL.txt) do (
REM Run WinSCP with %%A as open connection
"C:\Program Files (x86)\WinSCP\WinSCP.com" ^
/log="c:\temp\WinSCP.log" /loglevel=1 /ini=nul ^
/command ^
"%%A" ^
"ls" ^
"exit"
%WINSCP_RESULT% = %ERRORLEVEL%
if %ERRORLEVEL% neq 0 (
echo Error
echo %ERRORLEVEL% %%A
) else (
echo Success %ERRORLEVEL% %%A
echo Winscp Result %WINSCP_RESULT%
)
pause
)
ENDLOCAL
exit /b %WINSCP_RESULT%

Related

Batch nested loop doesn't work properly with errorlevel

I have a problem with a nested loop and usage of errorlevel. I want to delete files on multiple computers with batch files. For this I have a batch file that iterates through the computers and calls another batch files that deletes the files. On some computers I want to delete the files in a second folder.
The first part of the code works as expected, but the second part with the nested loop doesn't work. the code is:
SETLOCAL enabledelayedexpansion
REM %1 is a parameter from the calling batch file
FOR %%A IN (M:\Folder\) DO del /Q "%%A" 2>&1 1> NUL | find /V "" 1> NUL 2>&1 & IF ERRORLEVEL 1 (1> NUL ver) ELSE (2> NUL SET =)
IF !ERRORLEVEL! == 1 (
ECHO !ERRORLEVEL!
) ELSE (
ECHO OK
)
FOR %%N IN (%computers%) do (
IF %%N EQU %1 (
FOR %%A IN (M:\Folder2\) DO del /Q "%%A" 2>&1 1> NUL | find /V "" 1> NUL 2>&1 & IF ERRORLEVEL 1 (1> NUL ver) ELSE (2> NUL SET =)
IF !ERRORLEVEL! == 1 (
ECHO !ERRORLEVEL!
) ELSE (
ECHO OK
)
)
)

For Loop Ends Batch File Execution

My batch file is silently ending execution on the first loop (for /d "delims= eol=|" %%d in (*.*) do () and I can't tell why.
I'm not calling any other batch files
My subfolder names DO contain spaces, which I tried to handle with "delims= eol=|"
I never see !parent!!folder! echoed and it doesn't pause at the end. What am I doing wrong?
#Echo off
setlocal enabledelayedexpansion
pushd "%~dp0"
set "parent=%~dp0"
echo !parent!
set "destination=\\(test destination folder)\"
rem SET "destination=\\(prod destination folder)\"
set "FileCount=0"
for /d "delims= eol=|" %%d in (*.*) do (
set "folder=%%d"
echo !parent!!folder!
pause
for %%f in ("!parent!!folder!\(file identifying-pattern)*.DAT") do (
echo "File Type 1"
pause
if !FileCount! lss 200 (
set /a !FileCount!+=1
ECHO !FileCount!
ECHO !parent!!folder!%%f
ECHO !destination!%%f
MOVE "%%f" "!destination!"
)
(
for %%f in ("!parent!!folder!\(file identifying-pattern)*.DAT") do (
echo "File Type 2"
pause
if !FileCount! lss 200 (
set /a !FileCount!+=1
ECHO !FileCount!
ECHO !parent!!folder!%%f
ECHO !destination!%%f
MOVE "%%f" "!destination!"
)
)
)
for /d %%d in (*.*) do (
set "folder=%%d"
if not %%d==Archive (
if not %%d==Hold (
dir /b "!folder!"|find /v "">nul && ECHO "!folder! NOT EMPTY"||rmdir "!parent!!folder!"
)
)
)
pause
popd
I've took a guess at what you were doing, trying not to change the structure too much!
You'll need to add your destinations on lines 4 and 5 and your file patterns to lines 8 and 9 as necessary. (Please make sure you do not end your destination paths with back slashes):
#Echo Off
CD /D "%~dp0" 2>Nul || Exit /B
Set "Destination=\\(test destination folder)"
Rem Set "Destination=\\(prod destination folder)"
If Not Exist "%destination%\" Exit /B
Set "Pattern1=(file identifying-pattern)"
Set "Pattern2=(file identifying-pattern)"
Set /A Type1Count=Type2Count=0
SetLocal EnableDelayedExpansion
For /D %%A In (*) Do (
For %%B In ("%%A\%Pattern1%*.dat") Do (
Echo "File Type 1"
Set /A Type1Count +=1
If !Type1Count! Lss 200 (
Echo !Type1Count!. "%CD%\%%A\%%B" --^> "%Destination%\%%B"
If Not Exist "%Destination%\%%B\" MD "%Destination%\%%B"
Move /Y "%%B" "%Destination%\%%B">Nul
)
)
For %%C In ("%%A\%Pattern2%*.dat") Do (
Echo "File Type 2"
Set /A Type2Count +=1
If !Type2Count! Lss 200 (
Echo !Type2Count!. "%CD%\%%B\%%C" --^> "%Destination%\%%C"
If Not Exist "%Destination%\%%C\" MD "%Destination%\%%C"
Move /Y "%%C" "%Destination%\%%C">Nul
)
)
If /I Not "%%A"=="Archive" (
If /I Not "%%A"=="Hold" (
Set "file="
For %%D In (*) Do Set "file=1"
If Defined file (Echo %%A NOT EMPTY) Else RD "%%A" 2>Nul
)
)
)
Pause
If you're happy with it in your test you can Remark line 4 and unRemark line 5.

Keep just last 100 rows of data in text file

I have this script within a .bat file and would like to only keep the most recent 100 lines, at the end of the file.
How do I delete all other rows?
#echo off
REM *DATETIME2.BAT
REM *Copy date and time to create a new log file
echo.|date>>"\\spserver\myfolder\dt.tmp"
echo.|time>>"\\spserver\myfolder\dt.tmp"
IF NOT EXIST "\\spserver\myfolder\dt.tmp" GOTO Error1
type "\\spserver\myfolder\dt.tmp"|FIND "current">"\\spserver\myfolder\dt.log"
rem del "\\spserver\myfolder\dt.tmp"
GOTO End
:Error1
Echo.
Echo There was an error processing the command.
Echo Unable to find temporary sort file DATETIME2.TMP.
Echo.
GOTO End
:End
Here you go:
Call :Tail 100 dt.log tempout.txt
move /y tempout.txt dt.log>nul
exit /b
:Tail <numlines> <FileIn> <FileOut>
FOR /F "usebackq tokens=3,3 delims= " %%l IN (
`find /c /v "" %2`) DO (call SET find_lc=%%l)
SET /a linenumber=%find_lc%-%1
IF %linenumber% LSS 1 (
more +0 %2 >> %3
) ELSE (
more +%linenumber% %2 >> %3
)

How do I reduce the codes require to check error

We check error using
if !ERRORLEVEL! NEQ 0 (do something)
but this is littered everywhere in the batch file.
1) Is the a way to encapsulate it to log and exit program upon error?
2) how do I log the bat file line number that is causing the error?
#ECHO OFF
SETLOCAL
ECHO y|FIND "y" >NUL
CALL aberr matching y and y
pause
ECHO x|FIND "y" >NUL
CALL aberr matching x and y
pause
ECHO y|FIND "z" >NUL
CALL aberr matching y and z
pause
GOTO :EOF
The above is a testing scenario, setting errorlevel to 0, 1, 1 in succession, then CALLing then batch aberr.bat to analyse the result.
Here's aberr.bat
#ECHO OFF
IF %ERRORLEVEL%==0 GOTO :EOF
ECHO %ERRORLEVEL% found %*
EXIT
Note here that there is no SETLOCAL (which would set ERRORLEVEL to zero) and that the routine EXITs.
Consequence is that if aberr.bat is on the PATH then the message produced would show the errorlevel found plus any text that was on the CALL aberr line after CALL aberr.
You could place a PAUSE after the ECHO %ERRORLEVEL% line to show the result, or log the result to a file by using
>>logfile.txt ECHO %ERRORLEVEL% found %*
at 1) How to log and exit the batch Exit from nested batch file
at 2) How to get the current line number?
Mix them and you get it.
setlocal EnableDelayedExpansion
cd. & REM *** Set the errorlevel to 0
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
set /a n=0xGH 2> nul & REM Force the errorlevel to !=1
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
echo all OK
exit /b
:log
>error.log echo %*
call :HALT
exit /b
:HALT
call :__halt 2> nul
exit /b
:__halt
()
:::::::::::::::::::::::::::::::::::::::::::::
:GetLineNumber <resultVar> <uniqueID> [LineOffset]
:: Detects the line number of the caller, the uniqueID have to be unique in the batch file
:: The lineno is return in the variable <resultVar> add with the [LineOffset]
SETLOCAL
for /F " usebackq tokens=1 delims=:" %%L IN (`findstr /N "%~2" "%~f0"`) DO set /a lineNr=%~3 + %%L
(
ENDLOCAL
set "%~1=%LineNr%"
goto :eof
)
Use something like:
...
if !ERRORLEVEL! NEQ 0 Call :LogAndExit "some explanation"
...
GoTo :EOF
:LogAndExit
Echo %Date% %Time% - %~1>>Log.txt
Exit /B

Editing an external batch config value with batch

I have a config file named config.conf with the content of:
[Config]
password=1234
usertries=0
allowterminate=0
I want to just edit the usertries value to 5, are there any batch script code that can help me do that
Thanks
This gets a little messy, but should work:
#echo off
set ConfigFile=config.conf
setlocal enabledelayedexpansion
(for /f "delims=" %%L in (%ConfigFile%) do (
set "LINE=%%L"
if "!LINE:~0,10!"=="usertries=" (echo usertries=5) else (echo !LINE!)
)) > %ConfigFile%.new
move /y %ConfigFile%.new %ConfigFile% > nul
Basically we're writing each line to a new file, unless it starts with usertries=. In which case we just insert our replacement line. Afterwards we move the new file on top of the old one to replace it.
#ECHO OFF
setlocal
::
:: set %1 to value %2 in config.conf
::
SET target=%2&IF NOT DEFINED target ECHO syntax is %0 keyname newvalue&GOTO :EOF
SET target=Config.conf
MOVE /y %target% %target%.old >NUL
FOR /f "tokens=1*delims==" %%i IN (%target%.old) DO (
IF /i %%i==%1 (ECHO %%i=%2) ELSE (
IF "%%j"=="" (ECHO %%i) ELSE (ECHO %%i=%%j)
)
) >>%target%
With this version, you can change an existing key to a value using
thisbatchname existingkey newvalue
I know I'm a little late to the party, but I decided to write a general purpose ini file utility batch script to address this question.
The script will let you retrieve or modify values in an ini-style file. Its searches are case-insensitive, and it preserves blank lines in the ini file. In essence, it allows you to interact with an ini file as a sort of very rudimentary database.
:: --------------------
:: ini.bat
:: ini.bat /? for usage
:: --------------------
#echo off
setlocal enabledelayedexpansion
goto begin
:usage
echo Usage: %~nx0 /i item [/v value] [/s section] inifile
echo;
echo Take the following ini file for example:
echo;
echo [Config]
echo password=1234
echo usertries=0
echo allowterminate=0
echo;
echo To read the "password" value:
echo %~nx0 /s Config /i password inifile
echo;
echo To change the "usertries" value to 5:
echo %~nx0 /s Config /i usertries /v 5 inifile
echo;
echo In the above examples, "/s Config" is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
goto :EOF
:begin
if "%~1"=="" goto usage
for %%I in (item value section found) do set %%I=
for %%I in (%*) do (
if defined next (
if !next!==/i set item=%%I
if !next!==/v set value=%%I
if !next!==/s set section=%%I
set next=
) else (
for %%x in (/i /v /s) do if "%%~I"=="%%x" set "next=%%~I"
if not defined next (
set "arg=%%~I"
if "!arg:~0,1!"=="/" (
1>&2 echo Error: Unrecognized option "%%~I"
1>&2 echo;
1>&2 call :usage
exit /b 1
) else set "inifile=%%~I"
)
)
)
for %%I in (item inifile) do if not defined %%I goto usage
if not exist "%inifile%" (
1>&2 echo Error: %inifile% not found.
exit /b 1
)
if not defined section (
if not defined value (
for /f "usebackq tokens=2 delims==" %%I in (`findstr /i "^%item%\=" "%inifile%"`) do (
echo(%%I
)
) else (
for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (
set "line=%%I" && set "line=!line:*:=!"
echo(!line! | findstr /i "^%item%\=" >NUL && (
1>>"%inifile%.1" echo(%item%=%value%
echo(%value%
) || 1>>"%inifile%.1" echo(!line!
)
)
) else (
for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (
set "line=%%I" && set "line=!line:*:=!"
if defined found (
if defined value (
echo(!line! | findstr /i "^%item%\=" >NUL && (
1>>"%inifile%.1" echo(%item%=%value%
echo(%value%
set found=
) || 1>>"%inifile%.1" echo(!line!
) else echo(!line! | findstr /i "^%item%\=" >NUL && (
for /f "tokens=2 delims==" %%x in ("!line!") do (
echo(%%x
exit /b 0
)
)
) else (
if defined value (1>>"%inifile%.1" echo(!line!)
echo(!line! | find /i "[%section%]" >NUL && set found=1
)
)
)
if exist "%inifile%.1" move /y "%inifile%.1" "%inifile%">NUL
Example:
C:\Users\me\Desktop>type config.conf
[Config]
password=1234
usertries=0
allowterminate=0
[Other]
password=foo
C:\Users\me\Desktop>ini /i usertries /v 5 config.conf
5
C:\Users\me\Desktop>ini /i usertries config.conf
5
C:\Users\me\Desktop>ini /s config /i password /v bar config.conf
bar
C:\Users\me\Desktop>ini /s other /i password /v baz config.conf
baz
C:\Users\me\Desktop>type config.conf
[Config]
password=bar
usertries=5
allowterminate=0
[Other]
password=baz

Resources