Batch File Skipping If Statement - windows

It seems that whenever I run my Batch file, everything will run, and it'll go into checkfiles, but it doesn't operate the if statement. Nothing is returned, it just skips right over unto the last part of the code.
:file_check
if exist "%psychedelia%\nhc.exe" (goto file_exists) else (timeout /t 1 /nobreak > output)
goto file_check
:file_exists
copy /Y "%~dp0version.txt" "%psychedelia%"
:checkfiles
echo in checkfiles
if exist "%psychedelia%\wa.exe" if exist "%psychedelia%\readme.txt" if exist "%psychedelia%\HD.BLB" if exist "%psychedelia%\smackw32.dll" if exist "%psychedelia%\setup95.exe" if exist "%psychedelia%\WAVistaWin7.exe" (
echo MSGBOX "Thank you for installing the Neverhood. You may now go to your desktop and click on the Orpheus shortcut to play!" > %temp%\TEMPxmessage.vbs
call %temp%\TEMPxmessage.vbs
del %temp%\TEMPxmessage.vbs /f /q
rename "%psychedelia%\nhc.exe" wa.exe
timeout /t 1 /nobreak > output
taskkill.exe /F /IM setup95.exe /T
) else (
echo nonexistent
pause
timeout /t 1 /nobreak > output
goto checkfiles
)
All help is greatly appreciated.

Only the last if exist on that line has parentheses, so the else only applies to that last one. If any of the first ones evaluate to false, it will just skip the whole thing.

Try:
...
echo in checkfiles
for %%f in (wa.exe
readme.txt
HD.BLB
smackw32.dll
setup95.exe
WAVistaWin7.exe
) do if not exist "%psychedelia%\%%f" (
echo %%f nonexistent
pause
timeout /t 1 /nobreak > output
goto checkfiles
)
:: all required files found
echo MSGBOX "Thank you for installing the Neverhood. You may now go to your desktop and click on the Orpheus shortcut to play!" > %temp%\TEMPxmessage.vbs
call %temp%\TEMPxmessage.vbs
del %temp%\TEMPxmessage.vbs /f /q
rename "%psychedelia%\nhc.exe" wa.exe
timeout /t 1 /nobreak > output
taskkill.exe /F /IM setup95.exe /T
It might be easier to maintain.
In fact, you could even write
set requiredfiles=wa.exe readme.txt HD.BLB smackw32.dll setup95.exe WAVistaWin7.exe
for %%f in (%requiredfiles%) do if not exist "%psychedelia%\%%f" (
...
which would be even easier.

Related

How to stop a cmd file from showing Network error messages

Error Message I want to remove:
I get this error when I run a code that runs a shortcut that's shared over network.
How can I stop cmd script from showing Network Errors like these, even if I know there is an error?
#echo off
echo.
echo 1. Add
echo 2. Remove
echo.
set /p var= Type option number here -
if %var%==1 (goto :add)
if %var%==2 (goto :remove)
if else (goto :EOF)
:add
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\ /v RestoreConnection /d 0
echo.
echo SUCESSFULLY ADDED!
timeout /t 2 /nobreak >nul &exit
:remove
reg delete HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\ /v RestoreConnection
echo.
echo SUCESSFULLY REMOVED!
timeout /t 2 /nobreak >nul &exit
This .bat script could come handy btw. Atleast it's easier than changing the registry manually. You can add and delete the value any time you want, so its convenient. Save this as a (.bat) file and use it...
Thanks #FiddlingAway for giving reference for the script : )

Get out of loop if more than one minute Windows Batch file

I am trying to delete a folder on Windows server if a certain condition is met. If it is not met, then a wait for 10 seconds and loop around, check for the condition again. I also need to make sure that I am not in the loop forever. (Check if I am in the loop for more than 60 seconds, then get out of the loop). The batch file looks something like this:
C:\postgresql\uninstall-postgresql.exe --mode unattended
set TIMESTAMP1=%TIME%
:deleteFolder
tasklist /V |findstr /i "_uninstall*" >nul
if %errorlevel% == 0 (timeout /T /10 >nul
set TIMESTAMP2=%TIME%
**REM I want to make sure that we get out of this loop if the diff b/w TIMESTAMP2
AND TIMESTAMP1 IS MORE THEN 60 SECONDS**
goto deleteFolder
) ELSE (
if exists C:\postgresql RD /Q /S C:\postgresql)
Command 1
Command 2
Command 3
So, I am trying to uninstall Postgresql from a windows server, making sure that the uninstall is complete by checking the tasklist and then delete the basedir (C:\postgresql). If the uninstall process is still running, then wait for 10 seconds and check the tasklist again. I just want to make sure that I am not stuck in the loop forever.
Thanks in advance
Using timestamps and calculating time difference:
#echo off
setlocal EnableDelayedExpansion
C:\postgresql\uninstall-postgresql.exe --mode unattended
set "startTime=%time: =0%"
set "endTime="
:deleteFolder
tasklist /V |findstr /i "_uninstall*" >nul
if %errorlevel% == 0 (
goto waitAndDeleteFolder
) else (
goto cleanup
)
:waitAndDeleteFolder
timeout /T 10
set "endTime=%time: =0%"
set "end=!endTime:%time:~8,1%=%%100)*100+1!" & set "start=!startTime:%time:~8,1%=%%100)*100+1!"
set /A "elap=((((10!end:%time:~2,1%=%%100)*60+1!%%100)-((((10!start:%time:~2,1%=%%100)*60+1!%%100), elap-=(elap>>31)*24*60*60*100"
if !elap! gtr 6000 goto done
goto deleteFolder
:cleanup
if exist "C:\postgresql" RD /Q /S "C:\postgresql"
goto done
:done
The simpler method would be to utitlise a count to break the loop
#Echo off & Set Count=0
C:\postgresql\uninstall-postgresql.exe --mode unattended
:deleteFolder
If "%Count%"=="6" Goto :Failed
tasklist /V |%__AppDir_%findstr.exe /lic:"_uninstall" >nul 2> Nul && (Timeout /T 10 /Nobreak > Nul & <Nul Set /P "=." & Set /A "count+=1" & Goto :deleteFolder) || Goto :Post
:Post
if exist C:\postgresql (
RD /Q /S C:\postgresql && Echo/Task Completed
) Else Echo/C:\postgresql Absent
Goto :Eof
:Failed
Echo/Task failed to complete in the allocated time
Goto :Eof
I would however suggest a more robust approach on your part to identifying the task

Batch file that deletes itself and folder that contains it

I'm trying to do the following but deleting the downloaded folder which contains the batch file fails:
NOTE: All exe's, apps, batch file etc. are contained in file.zip.
User downloads file.zip to any directory and unzips.
User runs an exe which is located in the unzipped folder.
This in turn runs two portable apps and some other things.
Once duties are performed, I remote in and run the same exe but this time I select an option that runs a batch file (located in unzipped folder) that starts a 30 second timer then is supposed to stop the apps and delete file.zip and the unzipped folder including the batch file itself.
Below is the batch file:
#echo off
mode con: cols=32 lines=7
color 4f
title
echo 30 Second Delay
echo Close window to abort
echo/
echo/
echo 0%% 100%%
SET /P var= <NUL
set count=0
:loop
PING -n 2 127.0.0.1 >NUL 2>&1
call :printline _
set /a count=count+1
if %count%==30 goto finish
goto loop
:printline
REM Print text passed to sub without a carriage return.
REM Sets line variable in case %1 intereferes with redirect
set line=%1
set /p var=%line%<NUL
exit /b
:finish
cls
color 0f
title Finished
mode con: cols=80 lines=25
echo Do NOT close this window!
echo/
echo Killing processes...
echo/
echo/
echo/
taskkill /t /f /im app1mainprocess.exe >nul
timeout /t 5 >nul
taskkill /t /f /im app2mainprocess.exe >nul
timeout /t 5 >nul
echo Do NOT close this window!
echo/
rem echo Restarting Windows Explorer...
rem timeout /t 10 >nul
rem taskkill /f /im explorer.exe >nul
rem start explorer.exe
echo Do NOT close this window!
echo/
echo Deleteing files and folders...
echo/
rem timeout /t 10 >nul
Set "Folder2Del=%~dp0"
cd ..
IF EXIST "file.zip" DEL "file.zip" /s /q >nul
rem echo %scrptDir%
echo Do NOT close this window!
echo/
echo Still working...
timeout /t 10 >nul
rd %Folder2Del% /s /q
(goto) 2>Nul & RD /S /Q "%Folder2Del%" & exit
The problem I encounter is that the folder never gets deleted. I realize my code is not correct but another reason is because one of the dll files in the unzipped folder is sometimes still in use by the dllhost.exe process.
I'm not sure if it is safe to add a line that kills the dllhost.exe process or not but my code still won't work because I have something wrong with how it deletes the batch file itself and the folder that contains it.
What lines do I need to edit and is it safe to kill dllhost.exe?
According to a link from dbenham
This does the trick:
#Echo off
Echo Ref: "http://www.dostips.com/forum/viewtopic.php?f=3&t=6491"
Set "Folder2Del=%~dp0"
cd "%~d0"
pause
(goto) 2>Nul & RD /S /Q "%Folder2Del%"
Take care the folder containing the batch is deleted
including any other files/folders without any further question!
Ok... I THINK I figured out how to do what I want by trying to delete the dll file, first, before trying to delete the entire directory. The code below looks for the problem dll and tries to delete it. If it still exists, it will try to delete the file every 30 seconds for up to 15 minutes. As soon as the dll gets deleted, the entire folder will also be deleted. If after 15 minutes the dll cannot be deleted, the remaining files in the folder will be deleted.
I still have a small issue. If I add code that kill/restarts Windows Explorer, the folder does not get deleted. Why and is there a workaround?
Below is the latest code:
#echo off
mode con: cols=32 lines=7
color 4f
title
echo 30 Second Delay
echo Close window to abort
echo/
echo/
echo 0%% 100%%
SET /P var= <NUL
set count=0
:loop
PING -n 2 127.0.0.1 >NUL 2>&1
call :printline _
set /a count=count+1
if %count%==30 goto finish
goto loop
:printline
REM Print text passed to sub without a carriage return.
REM Sets line variable in case %1 intereferes with redirect
set line=%1
set /p var=%line%<NUL
exit /b
:finish
cls
color 0f
title Uninstall
mode con: cols=80 lines=25
echo Do NOT close this window!
echo/
echo Killing processes...
tasklist /fi "imagename eq app1mainprocess.exe" |find ":" > nul
if errorlevel 1 taskkill /t /f /im "app1mainprocess.exe" > nul
tasklist /fi "imagename eq app2mainprocess.exe" |find ":" > nul
if errorlevel 1 taskkill /t /f /im "app2mainprocess.exe" > nul
timeout /t 5 >nul
rem echo Do NOT close this window!
rem echo/
rem echo Restarting Windows Explorer...
rem timeout /t 10 >nul
rem taskkill /f /im explorer.exe >nul
rem start explorer.exe
echo/
echo Deleteing file.zip if it exists...
timeout /t 5 >nul
Set "Folder2Del=%~dp0"
cd ..
IF EXIST "file.zip" DEL "file.zip" /s /q >nul
rem echo %Folder2Del%
rem Loops for 30 times in 30 second intervals (Total 15 minutes) to confirm deletion. Loop will exit after 30 loops and move on if dll cannot be deleted.
for /l %%i in (1,1,30) do (
del "%Folder2Del%name*.dll"
if not exist "%Folder2Del%name*.dll" goto Folder2Del
echo/
echo File locked! May take up to 15 minutes to delete.
echo Will stop trying 15 minutes after first attempt.
timeout /t 30 >nul
)
:Folder2Del
echo/
echo Attempting to delete the Connector folder and it's contents...
timeout /t 5 >nul
rd "%~dp0" /s /q & exit

Workaround for failing DEL not setting errorlevel [duplicate]

The batch has to remove files and directories from specific locations and output success or stdout/stderr messages to a new .txt file. I have created the most of the script and it performs exactly as it should, except when the deletion is successful it moves forward to the next line rather than echo a 'successful' message on the log.
echo Basic Deletion Batch Script > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 0 echo succesful
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
For some reason I can't find the syntax for if del succeeds echo 'successful'. In the above example if I remove the line
if errorlevel 0 echo successful
Everything works fine, but no success message. With this line left in it echoes success for every line.
del and ErrorLevel?
The del command does not set the ErrorLevel as long as the given arguments are valid, it even resets the ErrorLevel to 0 in such cases (at least for Windows 7).
del modifies the ErrorLevel only in case an invalid switch is provided (del /X sets ErrorLevel to 1), no arguments are specified at all (del sets ErrorLevel to 1 too), or an incorrect file path is given (del : sets ErrorLevel to 123), at least for Windows 7.
Possible Work-Around
A possible work-around is to capture the STDERR output of del, because in case of deletion errors, the related messages (Could Not Find [...], Access is denied., The process cannot access the file because it is being used by another process.) are written there. Such might look like:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
To use the code in command prompt directly rather than in a batch file, write %# instead of %%#.
If you do not want to delete read-only files, remove /F from the del command line;
if you do want prompts (in case wildcards ? and/or * are present in the file path), remove /Q.
Explanation of Code
This executes the command line del /F /Q "\path\to\the\file_s.txt". By the part 2>&1 1> nul, the command output at STDOUT will be dismissed, and its STDERR output will be redirected so that for /F receives it.
If the deletion was successful, del does not generate a STDERR output, hence the for /F loop does not iterate, because there is nothing to parse. Notice that ErrorLevel will not be reset in that case, its value remains unchanged.
If for /F recieves any STDERR output from the del command line, the command in the loop body is executed, which is set =; this is an invalid syntax, therefore set sets the ErrorLevel to 1. The 2> nul portion avoids the message The syntax of the command is incorrect. to be displayed.
To set the ErrorLevel explicitly you could also use cmd /C exit /B 1. Perhaps this line is more legible. For sure it is more flexible because you can state any (signed 32-bit) number, including 0 to clear it (omitting the number clears it as well). It might be a bit worse in terms of performance though.
Application Example
The following batch file demonstrates how the above described work-around could be applied:
:DELETE
echo Deleting "%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F "tokens=*" %%# in ('del /F /Q "C:\Users\newuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted "%~1" succesfully.
goto :EOF
Presetting ErrorLevel
Besides the above mentioned command cmd /C exit /B, you can also use > nul ver to reset the ErrorLevel. This can be combined with the for /F loop work-around like this:
> nul ver & for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Alternative Method Without for /F
Instead of using for /F to capture the STDERR output of del, the find command could also be used like find /V "", which returns an ErrorLevel of 1 if an empty string comes in and 0 otherwise:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
However, this would return an ErrorLevel of 1 in case the deletion has been successful and 0 if not. To reverse that behaviour, an if/else clause could be appended like this:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)
Different Approach: Checking File for Existence After del
A completely different approach is to check the file for existence after having tried to delete it (thanks to user Sasha for the hint!), like this, for example:
del /F /Q "\path\to\the\file_s.txt" 1> nul 2>&1
if exist "\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)
When using this syntax, instead of this
if errorlevel 0 echo successful
you can use this - because errorlevel 0 is always true.
if not errorlevel 1 echo successful
Just use rm from UnxUtils (or gow or cygwin). It sets the errorlevel correctly in case of a nonexistent file, or any errors deleting the file.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
I found out how to do it... one way anyway.
echo Startup > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1 >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1
dir c:\users\newuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1 echo "successful" )
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
IF ERRORLEVEL 0 [cmd] will execute every time because IF ERRORLEVEL # checks to see if the value of ERRORLEVEL is greater than or equal to #. Therefore, every error code will cause execution of [cmd].
A great reference for this is: http://www.robvanderwoude.com/errorlevel.php
>IF /?
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
I would recommend modifying your code to something like the following:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 1 (
rem This block executes if ERRORLEVEL is a non-zero
echo failed
) else (
echo succesful
)
GOTO :EOF
If you need something that processes more than one ERRORLEVEL, you could do something like this:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done
GOTO :EOF
OR
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER
:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done
GOTO :EOF
The answer of aschipfl is great (thanks, helped me a lot!) using the code under Presetting ErrorLevel you get a nice standard function:
Take care to use %~1 instead of %1 in the del statement, or you will get errors if you use a quoted filename.
::######################################################################
::call :DELETE "file.txt"
::call :DELETE "file.txt" "error message"
:DELETE
>nul ver && for /F "tokens=*" %%# in ('del /F /Q "%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
if NOT .%2==. echo %~2
)
goto :EOF
BTW 1: You can give a nifty error message as a second parameter
BTW 2: Using :: instead of REM for comments makes the code even more readable.
Code:
Error Code: (What you did)
if errorlevel 0 echo succesful
The problem here is that you aren't calling errorlevel as a variable and plus you didn't add in the operator to the statement as well.
Correct Code: (Here is what it should actually be.)
if %ERRORLEVEL% EQU 0 echo succesful
Definitions:
EQU: The EQU stands for Equal. This kind of operator is also called a relational operator. Here is the documentation link to operators if you wanna know more, there are other ones but this helped me.
ERRORLEVEL: is declared as a variable and usually get the error level of the last command run usually. Variables are usually called when they are between percent signs like this
%foo%
For some more help on variables, go to cmd (Which you can go to by searching it on windows 10) and type in "set /?", without the quotes. the set command is the command you use to set variables

Batch File to check Folder continuously for new CSV files , renaming them one after another and start Firefox with current File

the Batch File should scan a certain folder continuously for new csv files and whenever a new csv-file is placed in the folder, the csv-file should be renamed to a specific filename, because a firefox extension shall read that file.
I have already written a batch file for this but I think the solution is not perfect.
This is my attempt:
I start with the batch-file InitRun.bat:
#echo off
for /L %%i in (1,1,86400) do (
call FFRun1.bat
timeout /T 1
)
FFRun1.bat looks like this:
#echo off
FOR %%f in (*Data.csv) do (
echo %%f
set FILE=%%f
call :copy
)
goto end
:copy
copy /y %FILE% merged.csv
del %FILE%
call :RunFF
:RunFF
type merged.csv
pushd "C:\Program Files (x86)\Mozilla Firefox\"
start /wait firefox.exe
popd
:end
exit /b
If I place two or more csv-files at the same in the Folder, my solution can only process one csv and merged.csv only contains the last processed csv. In addition Firefox opens several windows, but also only works with the last csv which was copied to merged.csv.
Each new csv-File has the filename *Data.csv and should be renamed to merged.csv and for each new csv-file, firefox should start in a new tab and process the current merged.csv.
The csv-Files should not be renamed all at once, but one after another. Also Firefox should not start multiple windows/instances at a time.
I hope you can help me.
Regards,
Kepler
It should do what you indicate iterating over the directory in date order and converting the *data.csv into merge csv for later process (firefox changed with notepad for testing, adapt as neede). Also it will check if .csv files are in use, and wait for file to become available. If a file can not be processed (in use) no later file will be accesible until locked file become available (process files in generation order)
#echo off
setlocal enableextensions
set "folder=d:\temp"
set "files=*data.csv"
pushd "%folder%"
for /l %%a in (0 0 1) do (
if exist "%files%" (
echo files found
set "done="
for /f "tokens=*" %%d in ('dir /b /od "%files%"') do if not defined done (
call :replace "merged.csv" "%%d"
if not errorlevel 1 (
start "" /wait notepad "merged.csv"
) else (
set "done=1"
)
)
) else (
echo no files to process
)
timeout.exe /t 2 >nul
)
endlocal
exit /b
:replace target source
if exist "%~1" del /f /q "%~1" >nul 2>nul
if errorlevel 1 (
echo file "%~1" is in use
exit /b 1
)
ren "%~2" "%~1" >nul 2>nul
if errorlevel 1 (
echo file "%~2" is in use
exit /b 1
)
exit /b 0

Resources