I am trying to write a bat file for a network policy that will install a program if it doesn't exist as well as several other functions. I am using GOTO statements depending on whether or not certain criterion are met. However, it seems that the labels are not firing correctly as all of them do.
I have simplified my script so as to grasp some idea of what may be happening.
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
:MISSING
echo file missing
ping localhost -n 5 >NUL
Basically it checks to see that the file "test.txt" exists in folder "c:\test" which id does. So it should echo file exists to the console. However, both "file exists" and "file missing" are echoed to the console. I find that if I remove the file from the folder or simply rename it, it only echoes "file missing"
Why is it running running both labels?
Because a GOTO is just a jump in execution to a point in the script, then execution continues sequentially from that point. If you want it to stop after running 'EXISTING', then you need to do something like this. Note the extra GOTO and new label:
#ECHO OFF
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
goto :NEXTBIT
:MISSING
echo file missing
:NEXTBIT
ping localhost -n 5 >NUL
It's worth noting though that with cmd.exe (i.e., the NT-based command shells [NT, Win2k, XP, etc]), you can do IF...ELSE blocks like this:
#ECHO OFF
IF EXIST c:\test\test.txt (
ECHO File exists
) ELSE (
ECHO File missing
)
ping localhost -n 5 >nul
...so you can eliminate your GOTOs entirely.
It's because you need to skip over the "missing" bit if it exists:
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
goto :COMMON
:MISSING
echo file missing
:COMMON
ping localhost -n 5 >NUL
You may also want to keep in mind that the current cmd.exe batch language is a fair bit more powerful than that which came with MS-DOS. I would prefer this one:
#echo off
if exist c:\test\test.txt (
echo file exists
) else (
echo file missing
)
ping localhost -n 5 >nul
After you echo file exists the next command is
echo file missing
You need to do something to skip the missing case. Perhaps another goto to a :PING label?
When you're debugging it helps to keep the echo on.
Because GOTO statement moves the execution to that label. To use it in the situation like yours, you need to add another GOTO label.
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO MISSING
:EXISTING
echo file exists
GOTO END
:MISSING
echo file missing
GOTO END
:END
ping localhost -n 5 >NUL
#echo off
IF EXIST "c:\test\test.txt" ( :: warning double quotes
GOTO EXISTING
) ELSE ( :: this format best in batch
GOTO MISSING
) :: don't forget
:EXISTING
echo file exists
goto OTHER :: if file exist jump OTHER
:MISSING
echo file missing
:: label is not required
:OTHER
timeout /t 5 >nul
pause
Related
I need to create a command that allows me to insert a check of a text file for a very specific symbol (’) and I am having trouble. It is a single quotation mark and it occasionally is found on some folders that need to be zipped and when my batch zipper encounters the folder with the symbol in it's name, it just starts having a lot of problems and creates weird files. I am not going into a lot of detail, but I just need a way to (in plain terms) check if a text file contains the symbol (’) and if it does, send the script to an error line (just something to indicate the symbol was found, like "echo error found"). And if not, then just send it to the rest of the script...
Like FINDSTR "’" dirlist.txt
if found goto err else goto resume
I know that is very incorrect but you get the idea.
Here is what I have so far and I still have made no progress getting it to work:
findstr /i /c:"’" C:\ACFZ\FORZIP\dirlist.txt >2
if %errorlevel% EQU 0 (goto LABEL0) else (goto LABEL1)
:LABEL0
msg %username& "An invalid symbol has been found. Remove any single quotation marks (’) from the folder names and try again. If unsure, simply remove anything that looks like an apostrophe."
pause
goto ERROR
:LABEL1
echo No errors found, continuing
pause
goto ZIPSTART
:ERROR
echo an error was found, exiting...
pause
goto EXIT
It always ends up saying no errors, even though the file has the symbol in it.
Here is the text file I need to search (dirlist)
2082708 Amboy Bank
2082712 Cavender’s
2082736 Elizabeth Board of Education
2082763 Tri-Valley Developmental Services LLC
2082773 Vector Management
OK, so I finally got it working right... Thanks to Harvey, I used the method of outputting any results to a separate file, and then checking that file for contents. Which actually works great, because if it finds an issue, it will show you the full name of the problem folder(s) so you can easily fix it.
Here is the snippet of the working part:
findstr "'" C:\ACFZ\FORZIP\dirlist.txt > error.txt
findstr "." error.txt >nul
IF %ERRORLEVEL% EQU 0 GOTO POPUP
IF %ERRORLEVEL% EQU 1 GOTO ALLCLEAR
and here it is with a bit more detail:
CD C:\ACFZ\FORZIP
DIR /AD /B /ON >dirlist.txt
Echo Checking for errors in folder names...
ping -n 3 localhost >nul
REM that is not an apostrophe!
findstr "'" C:\ACFZ\FORZIP\dirlist.txt > error.txt
findstr "." error.txt >nul
IF %ERRORLEVEL% EQU 0 GOTO POPUP
IF %ERRORLEVEL% EQU 1 GOTO ALLCLEAR
REM Errorlevel 0= Something found, 1= nothing found
:POPUP
color cf
msg %username% "An invalid symbol has been found. Remove any single quotation marks (’) from the folder names and try again. If unsure, simply remove anything that looks like an apostrophe."
goto ERROR
:ALLCLEAR
echo No errors found, continuing...
ping -n 3 localhost >nul
ping -n 3 localhost >nul
goto ZIPSTART
:ERROR
echo An error was found in the following folder name(s) below:^
findstr "." error.txt
echo.
Echo Remove any symbols from the above folder name(s)
echo within your completed folder and try again.
Echo This program will now exit.
pause
goto EXIT
:ZIPSTART
REM Zip contents of each directory
for /f "tokens=*" %%a in (dirlist.txt) do (
CD "%%a"
wzzip "C:\ACFZ\ZIPPED\%%a.zip"
CD..
)
Glad I was able to fix this. I guess WinZip goes really crazy from that quotation mark. The reason I needed this was I wrote this batch script (there is more to it than what I have above, as this was the part I needed to work on) to automate the zipping and backup process at my work, so that the folders for the month's jobs are zipped up and then copied onto the server for archive. It was a pain to manually do it, so with this I can just do it all in one step.
Oh and yeah the errorlevel issue was I did not have it entered correctly. I did not space them over to the right.
Thanks to all who helped.
%error_level% indicates the status of the execution which always successful (0) unless you pass in wrong arguments (e.g. try run findstr without argument or with a wrong file name).
In your case, you need to examine the output (messages printed on the screen) of findstr. One approach is to rely on the fact that nothing is printed on the screen if findstr finds no string matched the search. For example:
set found=""
findstr "'" C:\ACFZ\FORZIP\dirlist.txt > findresult.txt
call:CheckEmptyFile findresult.txt found
if "%found%" EQU "FOUND" (
echo An invalid symbol has been found
) else (
echo No errors found, continuing
)
REM your execution goes here
REM Clean up
del findresult.txt
goto :eof
:CheckEmptyFile
if %~z1 == 0 (
set "%~2=NOTFOUND"
) else (
set "%~2=FOUND"
)
goto :eof
(Reference: Windows BAT : test if a specific file is empty)
As I stated above Psshutdown refuses to work in a batch file but works fine in a command prompt. The script has some light logic to determine what group of PCs and such. Here is the script:
#ECHO OFF
cd "C:\temp\remote enable rdp"
goto :SET
:SET
set /p groupPC=pc or list?:
if %groupPC% == pc goto :PC
if %groupPC% == list goto :LIST
goto :SKIP
:PC
ECHO[
set /p pcName=Which PC?:
psshutdown -c -k \\%pcName% -r
PAUSE
goto :DONE
:LIST
ECHO[
set /p input=Which list?:
set list=%input%.txt
psshutdown #C:\Temp\Lists\%list% -r -f else goto :SKIP
PAUSE
goto :DONE
:SKIP
ECHO[
ECHO You probably typed something wrong. Starting from the top.
PAUSE
ECHO[
goto :SET
:DONE
ECHO Mischief Managed
TIMEOUT /t 10
EXIT /B
Every time I run either the PC logic or the List logic the prompt merely shows me the psshutdown syntax uses. I have tried every configuration of syntax I can find on the internet. Any thoughts?
Edit:It's worth noting that the #file syntax I'm using works almost verbatim with psexec.
Two things stand out to me. If your filename has a space in it, that would produce the results you mentioned. Try putting quotes around the file path.
I also can't make sense of the "else" statement at the end of your line. Was that a mistake? It should work with the below line instead.
psshutdown #"C:\Temp\Lists\%list%" -r -f
So basically I want to create a batch script that can run any notepad file which the user specifies. I tried this...
#Echo Off
SET /P ANSWER=What is the name of the file to open?
IF /i (%ANSWER%)==('FIND /i "*.txt" %ANSWER%) (goto :Filename)
goto :exit
:Filename
Start *.txt
EXIT
:exit
ECHO FAILLLLLLLL
PAUSE
EXIT
The issue here is the first IF statement. I know its wrong. But, I don't know how to specify the entry of any filename. A different way to do this task is also appreciated.
Thanks for help :)
If your goal is simply to open a file that the user specifies in Notepad, the following works for me in Windows 7:
#echo off
set /P answer=What is the file name?
if exist %answer% (
start notepad.exe %answer%
) else (
echo Unable to locate %answer%
)
I'd like to write a batch file that logs data. Each time it runs, it should log data in a new, sequentially numbered directory.
If I were doing this in BASH I would simply do:
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-1
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-2
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-3
What would be the equivalent of this in Windows (XP or more recent) batch programming?
[EDIT]
This is what I implemented, and it doesn't do what I'd hoped:
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST "C:\Thermo-Cal\NUL" "md C:\Thermo-Cal"
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\NUL" "md C:\Thermo-Cal\%UNIT_ID%"
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL" (
"md C:\Thermo-Cal\%UNIT_ID%\log-%%F"
set "LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F"
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo "Stuff will get saved in: %LOG_DIR%"
Running on Windows 7 (cmd) gives:
c:\batch\log-dir.bat
Check Thermo-Cal
The filename, directory name, or volume label syntax is incorrect.
Check Thermo-Cal\00534
The filename, directory name, or volume label syntax is incorrect.
The filename, directory name, or volume label syntax is incorrect.
"Stuff will get saved in: C:\Thermo-Cal\00534\log-1"
The first time the batch file runs, the log-1 is created.
Running the command a second time produces the exact same results, I would hope it create log-2.
Turning off the #echo off shows that the loop never breaks out early and runs (in this case) 99 times.
FOR /L %%F IN (1,1,25) DO (
IF "condition" "md C:\some\folder\log-%%F"
ECHO log-%%F
PAUSE
)
Inserted pause so you can see each output before it moves onto the next sequential number. Remove PAUSE when you finalize your script.
EDIT: Adding an IF NOT EXIST condition
FOR /L %%F IN (1,1,25) DO (
IF NOT EXIST "C:\some\folder\log-%%F\NUL" "md C:\some\folder\log-%%F"
ECHO log-%%F
PAUSE
)
When using IF [NOT] EXIST statements on directories, you must specify .\NUL as a file, as Windows normally only passes the condition on files and not folders. And in Windows, the NUL file ALWAYS exists in an existing directory.
EDIT2: Making log-%%F accessible outside of the loop
FOR /L %%F IN (1,1,25) DO (
IF NOT EXIST "C:\some\folder\log-%%F\NUL" ("md C:\some\folder\log-%%F" && SET dir%%F=C:\some\folder\log-%%F)
)
ECHO %dir1%
ECHO %dir2%
ECHO %dir3%
Plug that into a batch file and try it.
This worked on Windows 7:
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST C:\Thermo-Cal\NUL md C:\Thermo-Cal
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST C:\Thermo-Cal\%UNIT_ID%\NUL md C:\Thermo-Cal\%UNIT_ID%
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL (
md C:\Thermo-Cal\%UNIT_ID%\log-%%F
set "LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F"
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo "Stuff will get saved in: %LOG_DIR%"
You have to be careful where you use quotes, as in batch scripting, quoted content can be seen as literal strings instead of code.
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST "C:\Thermo-Cal\NUL" (md C:\Thermo-Cal)
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\NUL" (md C:\Thermo-Cal\%UNIT_ID%)
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL" (
md C:\Thermo-Cal\%UNIT_ID%\log-%%F
set LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo Stuff will get saved in: %LOG_DIR%
So, how I have it done right now, is that it that it calls another bat file to update it, and then that batch file updates, and sets %ERRORLEVEL% to 1. At the start of the original program, it checks if errorlevel is 1, if yes, it goes to the main menu, but right now, it doesn't call the update file, it just goes to the menu. This is my code
Main program
IF %errorlevel% EQU 1 goto begin
call updater.bat
:begin
echo MENU
Updater
set=errorlevel 1
wget (updatelink here)
call mainprogram.bat
Right now, sometimes it works, sometimes it doesn't, which leads me to believe that some command is somehow increasing the errorlevel, but the only code before the errorlevel check is
#echo off
color 0f
cls
set currentver=v0.5.6
(check code)IF %errorlevel% EQU 1 goto begin
https://code.google.com/p/flashcart-helper/source/browse/trunk/0.6/FlashcartHelperRobocopy.bat
Here is what I have right now.
Don't play around with errorlevel. It's an internal variable. At the start of a batch, errorlevel will be 0 because all you've done is set a local variable. This will almost always ( never say never ) succeed. Also, if errorlevel is 1, and I'm reading this correctly you also seem to have an infinite loop? From what I understand of what you've said your batches are like this:
Main
#echo off
color 0f
cls
set currentver=v0.5.6
IF %errorlevel% EQU 1 goto begin
call updater.bat
:begin
echo MENU
Updater
set=errorlevel 1
wget (updatelink here)
call mainprogram.bat
As errorlevel get's overwritten each time you do anything you're asking for trouble. Change %errorlevel% to %error% and it should solve your problems. As it's a local environment variable it should also be passed between batch files. Just be careful not to use error elsewhere.
Here is a solution using Dropbox Public Folders and no wget. It uses PowerShell that in on Win7+ machines.
Update the below https://dl.dropboxusercontent.com/u/12345678/ url with your own.
It auto creates a .conf file for configuration.
Set __deploy_mode to 1 for the file on dropbox so the version file can be updated but the script not accidentally executed.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET time_start=%time%
SET time_choice_wait=20
SET script_ver=1.00
SET script_name=%~n0
SET server_url=https://dl.dropboxusercontent.com/u/12345678/
SET script_name_bat=%~dp0%script_name%.bat
SET script_name_cfg=%~dp0%script_name%.conf
SET script_name_latest_ver=%~dp0%script_name%.latest.ver
ECHO %script_name% v%script_ver%
ECHO %script_ver% > %script_name%.current.ver
IF NOT EXIST "%script_name_cfg%" CALL :SCRIPT_MISSING_CFG
FOR /f "delims=" %%x IN (%script_name%.conf) DO (SET "%%x")
IF %__deploy_mode% EQU 1 GOTO :EOF
IF %auto_update_compare% EQU 1 CALL :SCRIPT_COMPARE_VER
:SCRIPT_MAIN
REM =======================================
REM === EDIT BELOW THIS LINE ==
REM TODO Add main content
ECHO.
ECHO Waiting for content...
REM === EDIT ABOVE THIS LINE ==
REM =======================================
GOTO END
:SCRIPT_MISSING_CFG
ECHO Creating new %script_name%.conf file...
ECHO __deploy_mode=0 > "%script_name_cfg%"
ECHO repository_base_url=%server_url% >> "%script_name_cfg%"
ECHO auto_update_compare=1 >> "%script_name_cfg%"
ECHO auto_update_download=1 >> "%script_name_cfg%"
ECHO Update %script_name%.conf as needed, then save and close to continue.
ECHO Waiting for notepad to close...
NOTEPAD "%script_name_cfg%"
GOTO :EOF
:SCRIPT_COMPARE_VER
ECHO Please wait while script versions are compared...
Powershell -command "& { (New-Object Net.WebClient).DownloadFile('%server_url%%script_name%.current.ver', '%script_name_latest_ver%') }"
IF NOT EXIST "%script_name_latest_ver%" GOTO END
SET /p script_latest_ver= < "%script_name_latest_ver%"
IF %script_ver% EQU %script_latest_ver% CALL :SCRIPT_COMPARE_VER_SAME
IF %script_ver% NEQ %script_latest_ver% CALL :SCRIPT_COMPARE_VER_DIFF
GOTO :EOF
:SCRIPT_COMPARE_VER_SAME
ECHO Versions are both %script_name% v%script_ver%
GOTO :EOF
:SCRIPT_COMPARE_VER_DIFF
ECHO Current Version:%script_ver% ^| Server Version:%script_latest_ver%
IF %auto_update_download% EQU 1 GOTO SCRIPT_DOWNLOAD_SCRIPT
ECHO.
ECHO Would you like to download the latest %script_name% v%script_latest_ver%?
ECHO Defaulting to N in %time_choice_wait% seconds...
CHOICE /C YN /T %time_choice_wait% /D N
IF ERRORLEVEL 2 GOTO SCRIPT_DOWNLOAD_NOTHING
IF ERRORLEVEL 1 GOTO SCRIPT_DOWNLOAD_SCRIPT
IF ERRORLEVEL 0 GOTO SCRIPT_DOWNLOAD_NOTHING
:SCRIPT_DOWNLOAD_SCRIPT
ECHO Please wait while script downloads...
Powershell -command "& { (New-Object Net.WebClient).DownloadFile('%server_url%%script_name%.bat', '%script_name_bat%') }"
ECHO Script Updated to v%script_latest_ver%^^!
REM User must exit script. Current batch is stale.
GOTO :END
:SCRIPT_DOWNLOAD_NOTHING
GOTO :EOF
:END
SET time_end=%time%
ECHO.
ECHO Script started:%time_start%
ECHO Script ended :%time_end%
:END_AGAIN
pause
ECHO.
ECHO Please close this window
ECHO.
GOTO END_AGAIN
You can do that through these steps:
1.put two files in server,a config file, a higher version bat file which need to update; set last version num. in config file.
2.client bat should be checked update at every startup time. you can read the news version in server config file, then compared to local bat file version. if not equal, so do update, else other wise.
Do you have any problems?