echoing (creating) an error log file - windows

I have the following lines commands:
if %errorlevel% equ 1 (
set/a error=1
if not exist "error.log" echo. > "error.log"
echo the procedure has got an error >> "error.log"
echo. >> "error.log
)
but like this I obtain the message that the file is being processed by another process.
There is maybe another way to create the file if not exists instead of using Echo.

You can create the file with
copy NUL error.log
However, I doubt that echo is your problem. More likely is that the file already exists and you have it opened in a text editor (or viewer) that locks the file.

Related

Batch file attribute check

I'm having a little troubles with my script in .bat. My task is to write a script that will check a file for a few things. I've already defined some of those things, but now I'm stuck. My problem is that I don't know how to define a condition that says: If the file is hidden or read-only, delete this attribute and write some info about the change to the file (some text).
And then I'm having a second problem and that is that the script has always to write something to the file, but when I try to write something to the file (while the script is running) and then I save it, there is always just the thing the script has to write in it. Would somebody please give me some advice? I'm a novice. Thanks a lot for all the responses.
here is the script itself:
#echo off
title file-checking script
set file="file.txt"
set maxbytesize=1
type NUL > file.txt
pause
:loop
if exist file.txt #echo ok> file.txt
if not exist file.txt type NUL > file.txt
FOR /F "usebackq" %%A IN ('%file%') DO set size=%%~zA
if %size% LSS %maxbytesize% (
echo.File is under %maxbytesize% byte
) ELSE (
del file.txt
)
timeout/t 2
goto loop
read HELP FOR and you will notice that checking the attributes is similar to checking the file size
set ATTRS=%%~aA
Use >> instead of > to append data to an existing file, preserving existing content. The > redirection will overwrite any existing content.
You can use the following to test if a file is hidden (after you have proven that it exists):
dir /b /ah file.txt >nul 2>nul && (
echo file is hidden
) || (
echo file is not hidden
)

BATCH- How to put a variable into the move command?

Okay, this is my first question on Stackoverflow, so I'll try to make it a good one.
I've searched all over the web and I couldn't find any information to this. I have created a little batch file that prompts you to put in the name of a file that you would like to move. After that, it asks your your usersname. The problem I'm having is cmd tells me I have incorrect syntax.
Can anyone see what I did wrong?
Below is the code I am using. I just pasted in the part that is having trouble.
Thanks guys!
echo Place the file you wish to move to the Windows Startup Folder on your desktop.
echo When you have placed it there, type in the name of your file, NOT INCLUDING the extension.
echo Example: The file's name is: myfile.bat You type in: myfile
set/p "filename=>"
echo %filename%
echo Next, type in your username.
echo Example: acly6
set/p "USERNAME=>"
echo %USERNAME%
ping 192.2.0.0 -n 1 -w 500 > nul
goto MOVE
:MOVE
echo Moving your file to your startup folder.
move C:\Users\%USERNAME%\Desktop\%filename%.bat
C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
ping 192.2.0.0 -n 1 -w 1000 > nul
echo Checking Volumes...
ping 192.2.0.0 -n 1 -w 3000 > nul
if EXIST C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\StartMenu\Programs\Startup\%filename%goto COMPLETED
goto FAILED
I editted a bit your script:
Surrounded filepaths with double quotes
Added /y parameter to move command to override automatically the file in new location (if exists)
Spotted some issues:
goto MOVE
:MOVE has no sense as it will continue anyway that path.
goto FAILED GOTO COMPLETED - there're no such labels in your script.
Please shout if you have other problems.
#echo off
echo Place the file you wish to move to the Windows Startup Folder on your desktop.
echo When you have placed it there, type in the name of your file, NOT INCLUDING the extension.
echo Example: The file's name is: myfile.bat You type in: myfile
set/p "filename=>"
echo %filename% echo Next, type in your username.
echo Example: acly6
set/p "USERNAME=>"
echo %USERNAME%
ping 192.2.0.0 -n 1 -w 500 > nul
goto MOVE
:MOVE
echo Moving your file to your startup folder.
move /Y "C:\Users\%USERNAME%\Desktop\%filename%.bat" "C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\"
ping 192.2.0.0 -n 1 -w 1000 > nul
echo Checking Volumes...
ping 192.2.0.0 -n 1 -w 3000 > nul
if EXIST "C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\%filename%" goto COMPLETED
goto FAILED
:FAILED

Redirecting Output from within Batch file

I am creating a batch file with some simple commands to gather information from a system. The batch file contains commands to get the time, IP information, users, etc.
I assembled all the commands in a batch file, and it runs, but I would like the batch file, when run to output the results to a text file (log). Is there a command that I can add to the batch that would do so?
Keep in mind I do not want to run the batch from cmd, then redirect output ; I want to redirect the output from inside the batch, if that is possible.
The simple naive way that is slow because it opens and positions the file pointer to End-Of-File multiple times.
#echo off
command1 >output.txt
command2 >>output.txt
...
commandN >>output.txt
A better way - easier to write, and faster because the file is opened and positioned only once.
#echo off
>output.txt (
command1
command2
...
commandN
)
Another good and fast way that only opens and positions the file once
#echo off
call :sub >output.txt
exit /b
:sub
command1
command2
...
commandN
Edit 2020-04-17
Every now and then you may want to repeatedly write to two or more files. You might also want different messages on the screen. It is still possible to to do this efficiently by redirecting to undefined handles outside a parenthesized block or subroutine, and then use the & notation to reference the already opened files.
call :sub 9>File1.txt 8>File2.txt
exit /b
:sub
echo Screen message 1
>&9 echo File 1 message 1
>&8 echo File 2 message 1
echo Screen message 2
>&9 echo File 1 message 2
>&8 echo File 2 message 2
exit /b
I chose to use handles 9 and 8 in reverse order because that way is more likely to avoid potential permanent redirection due to a Microsoft redirection implementation design flaw when performing multiple redirections on the same command. It is highly unlikely, but even that approach could expose the bug if you try hard enough. If you stage the redirection than you are guaranteed to avoid the problem.
3>File1.txt ( 4>File2.txt call :sub)
exit /b
:sub
etc.
if you want both out and err streams redirected
dir >> a.txt 2>&1
I know this is an older post, but someone will stumble across it in a Google search and it also looks like some questions the OP asked in comments weren't specifically addressed. Also, please go easy on me since this is my first answer posted on SO. :)
To redirect the output to a file using a dynamically generated file name, my go-to (read: quick & dirty) approach is the second solution offered by #dbenham. So for example, this:
#echo off
> filename_prefix-%DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log (
echo Your Name Here
echo Beginning Date/Time: %DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log
REM do some stuff here
echo Your Name Here
echo Ending Date/Time: %DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log
)
Will create a file like what you see in this screenshot of the file in the target directory
That will contain this output:
Your Name Here
Beginning Date/Time: 2016-09-16_141048.log
Your Name Here
Ending Date/Time: 2016-09-16_141048.log
Also keep in mind that this solution is locale-dependent, so be careful how/when you use it.
#echo off
>output.txt (
echo Checking your system infor, Please wating...
systeminfo | findstr /c:"Host Name"
systeminfo | findstr /c:"Domain"
ipconfig /all | find "Physical Address"
ipconfig | find "IPv4"
ipconfig | find "Default Gateway"
)
#pause
echo some output >"your logfile"
or
(
echo some output
echo more output
)>"Your logfile"
should fill the bill.
If you want to APPEND the output, use >> instead of >. > will start a new logfile.
Add these two lines near the top of your batch file, all stdout and stderr after will be redirected to log.txt:
if not "%1"=="STDOUT_TO_FILE" %0 STDOUT_TO_FILE %* >log.txt 2>&1
shift /1
There is a cool little program you can use to redirect the output to a file and the console
some_command ^| TEE.BAT [ -a ] filename
#ECHO OFF
:: Check Windows version
IF NOT "%OS%"=="Windows_NT" GOTO Syntax
:: Keep variables local
SETLOCAL
:: Check command line arguments
SET Append=0
IF /I [%1]==[-a] (
SET Append=1
SHIFT
)
IF [%1]==[] GOTO Syntax
IF NOT [%2]==[] GOTO Syntax
:: Test for invalid wildcards
SET Counter=0
FOR /F %%A IN ('DIR /A /B %1 2^>NUL') DO CALL :Count "%%~fA"
IF %Counter% GTR 1 (
SET Counter=
GOTO Syntax
)
:: A valid filename seems to have been specified
SET File=%1
:: Check if a directory with the specified name exists
DIR /AD %File% >NUL 2>NUL
IF NOT ERRORLEVEL 1 (
SET File=
GOTO Syntax
)
:: Specify /Y switch for Windows 2000 / XP COPY command
SET Y=
VER | FIND "Windows NT" > NUL
IF ERRORLEVEL 1 SET Y=/Y
:: Flush existing file or create new one if -a wasn't specified
IF %Append%==0 (COPY %Y% NUL %File% > NUL 2>&1)
:: Actual TEE
FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO (
> CON ECHO.%%B
>> %File% ECHO.%%B
)
:: Done
ENDLOCAL
GOTO:EOF
:Count
SET /A Counter += 1
SET File=%1
GOTO:EOF
:Syntax
ECHO.
ECHO Tee.bat, Version 2.11a for Windows NT 4 / 2000 / XP
ECHO Display text on screen and redirect it to a file simultaneously
ECHO.
IF NOT "%OS%"=="Windows_NT" ECHO Usage: some_command ³ TEE.BAT [ -a ] filename
IF NOT "%OS%"=="Windows_NT" GOTO Skip
ECHO Usage: some_command ^| TEE.BAT [ -a ] filename
:Skip
ECHO.
ECHO Where: "some_command" is the command whose output should be redirected
ECHO "filename" is the file the output should be redirected to
ECHO -a appends the output of the command to the file,
ECHO rather than overwriting the file
ECHO.
ECHO Written by Rob van der Woude
ECHO http://www.robvanderwoude.com
ECHO Modified by Kees Couprie
ECHO http://kees.couprie.org
ECHO and Andrew Cameron
#echo OFF
[your command] >> [Your log file name].txt
I used the command above in my batch file and it works. In the log file, it shows the results of my command.
Adding the following lines at the bottom of your batch file will grab everything just as displayed inside the CMD window and export into a text file:
powershell -c "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('^a')
powershell -c "$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys('^c')
powershell Get-Clipboard > MyLog.txt
It basically performs a select all -> copy into clipboard -> paste into text file.
This may fail in the case of "toxic" characters in the input.
Considering an input like thisIsAnIn^^^^put is a good way how to get understand what is going on.
Sure there is a rule that an input string MUST be inside double quoted marks but I have a feeling that this rule is a valid rule only if the meaning of the input is a location on a NTFS partition (maybe it is a rule for URLs I am not sure).
But it is not a rule for an arbitrary input string of course (it is "a good practice" but you cannot count with it).

find string in text file and then renaming my log file

im working on a basic .bat file.
It checks if various files exists and if they dont, it will write "ERROR" in the log file.
I then test this log file for the string "ERROR" and if it does I want to rename my log file, but i seem to be getting an error on my if statement. Heres my code..
set "filename=C:\Temp\%COMPUTERNAME%.txt"
echo Creating .txt file...
echo Getting the Computer name...
echo %COMPUTERNAME% >> filename
echo ArcGIS Desktop 10 File checker
pause
echo Looking for files.....
call:checkFileExists C:\support\msi_local\Oracle10g\marker.txt
pause
FIND "ERROR" filename
echo error level is %ERRORLEVEL%
pause
if %ERRORLEVEL% 1 (
set "newfileName=C:\Temp\%COMPUTERNAME%%_ERROR.txt"
rename fileName newfileName
)
pause
:checkFileExists
if exist %~1 (
echo Success %~1 does exist >> C:\Temp\%COMPUTERNAME%.txt
) else (
echo ERROR "C:\support\msi_local\Oracle10g\marker.txt"%~1 does not exist >> C:\Temp\%COMPUTERNAME%.txt
)
I get a error -
The syntax of teh command is incorrect.
C:\Windows>if ERRORLEVEL 1(
Where am i going wrong?
Thanks
try this:
#echo off &SETLOCAL
set "filename=C:\Temp\%COMPUTERNAME%.txt"
echo Creating .txt file...
echo Getting the Computer name...
>>"%filename%" echo %COMPUTERNAME%
echo ArcGIS Desktop 10 File checker
pause
echo Looking for files.....
call:checkFileExists "C:\support\msi_local\Oracle10g\marker.txt"
pause
FIND "ERROR" "%filename%"
echo error level is %ERRORLEVEL%
pause
if %ERRORLEVEL% equ 1 (
set "newfileName=C:\Temp\%COMPUTERNAME%_ERROR.txt"
move "%fileName%" "%newfileName%"
)
pause
:checkFileExists
if exist "%~1" (
echo Success %~1 does exist >> C:\Temp\%COMPUTERNAME%.txt
) else (
echo ERROR "C:\support\msi_local\Oracle10g\marker.txt"%~1 does not exist >> C:\Temp\%COMPUTERNAME%.txt
)
if %ERRORLEVEL% 1 (
should be
if ERRORLEVEL 1 (
And, since you're retyping the error rather than copy-pasting, note that there must be a space between the 1 and the (
The error appears that way because batch replaces any %var% with its value at that time (when it is 'parsed') and then executes the line, so batch substitutes whatever has been reported as %errorlevel% from your debug statement :) (eg 1) and then tries valiantly to work out what if 1 1 ( means.
(btw, it would be a good idea to replace if exist %~1 ( with if exist "%~1" (
This may seem redundant, removing and then replacing the quotes, BUT if you later decide to change the statement to if exist %file% ( it's only later you'll find out you'll get a crash when %file% contains a space. Best to be ever-mindful of the spaces-in-filenames problem; if you make quoting a habit, you'll be caught out less often.
)
The two syntaxes are subtly different:
Old style syntax (MS-DOS era) - check if the error level was 1 or more:
IF ERRORLEVEL 1
New style syntax - check if the %errorlevel% variable was not equal to 0:
IF %errorlevel% NEQ 0
Note that the new style syntax uses % to indicate a variable, while with the old style syntax, ERRORLEVEL is a special keyword.
The new style syntax should be preferred, because it will handle programs that return -1 on error. If the program can return negative error codes on success, you could handle errors with IF %errorlevel GEQ 1. Either way, using the %errorlevel% variable allows a lot more flexibility.
For clarity I've used upper case for keywords and lower case for variables, but it should be case sensitive either way.

Batch Print - Batch Script - findstr condition in for loop

My problem at hand is to download pdf files and send all of them to the printer.
I download via ftp correctly and all the files go into my local directory:
File Name = FtpScript.ftp
open ftp.domain.com
username
password
!:--- FTP commands below here ---
lcd local/Directory
cd /remote/Directory
binary
mget "*.pdf"
prompt
disconnect
quit
This batch file then calls the ftp script.
File Name = retrieve_print.bat
#ftp -i -s:"C:\Scripts\FtpScript.ftp"
set mm=%date:~4,2%
set dd=%date:~7,2%
set yy=%date:~-4%
IF NOT EXIST {C:\Users\print_test2\print_%mm%_%yy%}( mkdir C:\Users\print_test2\print_%mm%_%yy% )
IF NOT EXIST C:\Users\print_test2\print_%mm%_%yy%\uploaded_%mm%_%dd%_%yy%.txt (
#echo Uploaded Text -- Date: %date% Time : %time% >> C:\Users\print_test2\print_%mm%_%yy%\uploaded_%mm%_%dd%_%yy%.txt
)
IF NOT EXIST C:\Users\print_test2\print_%mm%_%yy%\printed_%mm%_%dd%_%yy%.txt (
#echo Printed Text -- Date: %date% Time : %time% >> C:\Users\print_test2\print_%mm%_%yy%\printed_%mm%_%dd%_%yy%.txt
)
REM LOOP THROUGH PDFs THAT WERE UPLOADED AND INSERT THE NAMES INTO THE UPLOADED_*_*.txt TEXT FILE
FOR %%x in ( C:\Users\print_test2\print_%mm%_%yy%\*.pdf ) DO (
findstr "%%~nxx" C:\Users\print_test2\print_%mm%_%yy%\uploaded_%mm%_%dd%_%yy%.txt
#ECHO Error level = %errorlevel%
#ECHO %%~nxx
#pause
IF NOT %errorlevel% == 0 (
#echo %%~nxx >> C:\Users\print_test2\print_%mm%_%yy%\uploaded_%mm%_%dd%_%yy%.txt
)
)
REM LOOP THROUGH PDFs THAT WERE UPLOADED AND PRINT THEM, THEN INSERT THEM INTO THE PRINTED_*_*.txt TEXT FILE TO SUPPRESS DUPLICATE PRINTS
FOR %%x in ( C:\Users\print_test2\print_%mm%_%yy%\*.pdf ) DO (
findstr "%%~nxx" C:\Users\print_test2\print_%mm%_%yy%\printed_%mm%_%dd%_%yy%.txt
#ECHO Error level = %errorlevel%
#ECHO %%~nxx
IF NOT %errorlevel% == 0 (
rem PRINT FUNCTION
#echo %%~nxx >> C:\Users\print_test2\print_%mm%_%yy%\printed_%mm%_%dd%_%yy%.txt
)
)
The text files generate incorrectly. My thought is that I could loop through the files available in the print_test2/print_%mm%_%yy% directory for all the files that I received via ftp and log it into a text file.
The problem becomes apparent when I try to run the script a second time when the text files have file names in them. I expect the findstr function to give back an %errorlevel% of 0 , but it does not detect the string that is in the text file and appends all the file names again in both my uploaded and printed text files.
Is there a better way of logging the files received and printing the pdfs only once?
Thanks
Your problem is that the %errorlevel% value is taken inside a for, so it is replaced by the value errorlevel had before enter the for loop. To take the current value that errorlevel have in each for iteration you must use Delayed Variable Expansion, that is, enclose the value in exclamation points instead percents: !errorlevel! AND insert this line at begining of your program:
setlocal EnableDelayedExpansion
To make this problem clearer, try this:
set name=Value before FOR
for %%f in (*.pdf) do (
set name=%%f
echo %name%
)
and then try again changing echo %name% by echo !name!.
A few ideas to consider:
I'm not sure that the errorlevel after your FINDSTR command is going to be non-zero just because the string wasn't found.
Even if errorlevel is non-zero, I think that the moment you execute the next command, the new errorlevel from that command gets set.
In your IF statement, you might need to wrap the two sides of your equality check in delimiters, e.g. IF NOT "%errorlevel%" == "0"
You might consider just making your list distinct after you echo all file names into it. It'll save you some logic on the way in. Some code for making a list distinct in DOS is described here: http://www.dullsharpness.com/2010/10/01/create-a-distinct-ordered-list-from-an-unordered-duplicate-list-using-ms-dos/
If you use techniques from #4, you can then just do a directory listing into your file (as follows) and then make unique using techniques in #4.
dir/b C:\Users\print_test2\print_%mm%_%yy%\*.pdf >> C:\Users\print_test2\print_%mm%_%yy%\printed_%mm%_%dd%_%yy%.txt

Resources