I am trying to create a Windows batch login script that collects each user's system info and username/computername and outputs it to one log file (rather than a separate file created for each user). So I need something like echo %username%-%computername% >> file.txt and systeminfo|find /i "original" >> file.txt, which I managed to do with something like this:
systeminfo|find /i "original" >> \\share\sysinfo.log
echo %username%-%computername% >>\\share\user.log
type \\share\user.log > \\share\Results\systeminfo.log
type \\share\sysinfo.log >> \\share\Results\systeminfo.log
Every time someone logs on, it output to one file, but the username and systeminfo are separated. I need them to output into separate columns, for example:
Username-ComputerName Original Install Date
Jo-PC1 17/16/2016, 09:14:34
Dan-PC2 17/03/2015, 11:00:05
Please mind that Stack Overflow is not a write-code-for-me-services. Anyways, I shamefully stole the script(and edited) by MC ND in my question
#echo off
setlocal enableextensions disabledelayedexpansion
rem Prepare padding for two column
set "Width=30"
setlocal enabledelayedexpansion
set "padding= "
for /l %%a in (1 1 %Width%) do set "padding=!padding! "
endlocal & set "padding=%padding%"
rem return "Username-ComputerName Original Install Date"
echo Username-ComputerName Original Install Date>File.ext
rem Prepate two files to store username-computerName and install date lists
for %%d in ("%temp%\username-computerName.%random%%random%%random%.tmp") do (
for %%f in ("%temp%\installName.%random%%random%%random%.tmp") do (
rem Retrieve the list of username-computerName and install date into the temp files
type user.log > "%%~fd" 2>nul
type date.log > "%%~ff" 2>nul
rem Assign each temporary file to a separate stream
rem and call the code to process them
9<"%%~fd" 8<"%%~ff" call :dumpPairs
rem Clean up temporary files
) & del /q "%%~ff"
) & del /q "%%~fd"
rem All done, leave
cls
type File.ext
pause
goto :eof
rem Read stream 9 to retrieve username-computerName - Clean var on failure
rem Read stream 8 to retrieve install date - Clean var on failure
rem If both variables are uninitialized, there is nothing more to do
rem Concatenate both information and padding
rem Echo the padded results
rem Repeat the process
:dumpPairs
<&9 set /p "username-computerName=" || set "username-computerName="
<&8 set /p "installName=" || set "installName="
if not defined username-computerName if not defined installName goto :eof
set "line=%username-computerName%%padding%"
setlocal enabledelayedexpansion
echo(!line:~0,%Width%! !installName!>>File.ext
endlocal
goto :dumpPairs
The explanation is already is inside the script, so I won't explain much.
Simply get the result into 2 files
Echo them together
The output part is
rem All done, leave
cls
type File.ext
pause
goto :eof
so you may need some adjustments.
Related
I have written a batch file that I use for file management. The batch file parses an .XML database to get a list of base filenames, then allows the user to move/copy those specific files into a new directory. The program prompts the user for a source directory and the name of the .XML file. I would like the program to default the variables to the last used entry, even if the previous CMD session has closed. My solution has been to ask the user for each variable at the beginning of the program, then write those variables to a separate batch file called param.bat at the end like this:
#echo off
set SOURCEDIR=NOT SET
set XMLFILE=NOT SET
if exist param.bat call param.bat
set /p SOURCEDIR=The current source directory is %SOURCEDIR%. Please input new directory or press [Enter] for no change.
set /p XMLFILE=The current XML database is %XMLFILE%. Please input new database or press [Enter] for no change.
REM {Rest of program goes here}
echo #echo off>param.bat
echo set SOURCEDIR=%SOURCEDIR%>>param.bat
echo set XMLFILE=%XMLFILE%>>param.bat
:END
I was hoping for a more elegant solution that does not require a separate batch file and allows me to store the variable data within the primary batch file itself. Any thoughts?
#echo off
setlocal
dir /r "%~f0" | findstr /c:" %~nx0:settings" 2>nul >nul && (
for /f "usebackq delims=" %%A in ("%~f0:settings") do set %%A
)
if defined SOURCEDIR echo The current source directory is %SOURCEDIR%.
set /p "SOURCEDIR= Please input new directory or press [Enter] for no change. "
if defined XMLFILE echo The current XML database is %XMLFILE%.
set /p "XMLFILE=Please input new database or press [Enter] for no change. "
(
echo SOURCEDIR=%SOURCEDIR%
echo XMLFILE=%XMLFILE%
) > "%~f0:settings"
This uses the Alternate Data Stream (ADS) of the batchfile to
save the settings.
NTFS file system is required. The ADS stream is lost if the
batchfile is copied to a file system other than NTFS.
The dir piped to findstr is to determine if the
stream does exist before trying to read from it.
This helps to avoid an error message from the for
loop if the ADS does not exist.
The for loop sets the variable names and values read from the ADS.
Finally, the variables are saved to the ADS.
Note:
%~f0 is full path to the batchfile.
See for /? about all modifiers available.
%~f0:settings is the batchfile with ADS named settings.
dir /r displays files and those with ADS.
Important:
Any idea involving writing to the batchfile could result
in file corruption so would certainly advise a backup of
the batchfile.
There is one way to save variables itself on the bat file, but, you need replace :END to :EOF
:EOF have a good explained in this link .:|:. see Where does GOTO :EOF return to?
Also, this work in fat32/ntfs file system!
You can write the variables in your bat file, and read when needs:
Obs.: Sorry my limited English
#echo off & setlocal enabledelayedexpansion
set "bat_file="%temp%\new_bat_with_new_var.tmp"" & type nul >!bat_file! & set "nop=ot Se"
for /f %%a in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo 0x40"') do set "delim=%%a"
type "%~f0"| findstr "!delim!"| find /v /i "echo" >nul || for %%s in (SOURCEDIR XMLFILE) do set "%%s=N!nop!t"
if defined SOURCEDIR echo/!SOURCEDIR!%delim%!XMLFILE!%delim%>>"%~f0"
for /f "delims=%delim% tokens=1,2" %%a in ('type "%~f0"^| findstr /l "!delim!"^| find /v /i "echo"') do (
set /p "SOURCEDIR=The current source directory is %%~a. Please input new directory or press [Enter] for no change: "
set /p "XMLFILE=The current XML database is %%~b. Please input new database or press [Enter] for no change: "
if /i "!old_string!" neq "!SOURCEDIR!!delim!!XMLFILE!!delim!" (
type "%~f0"| findstr /vic:"%%~a!delim!%%~b!delim!">>!bat_file!"
copy /y !bat_file! "%~f0" >nul
echo/!SOURCEDIR!!delim!!XMLFILE!!delim!>>%~f0"
goto :_continue_:
))
:_continue_:
rem :| Rest of program goes here | replace/change last command [goto :END] to [goto :EOF]
goto :EOF
rem :| Left 2 line blank above, because your variable will be save/read in next line above here |:
#ECHO OFF
CLS
REM Start Backup
TITLE Backup
SETlocal EnableDelayedExpansion
REM Capture the date/time(right down to the second) and then assign it to a variable
SET yy=%date:~-4%
SET dd=%date:~-7,2%
SET mm=%date:~-10,2%
SET newdate=%dd%%mm%%yy%_%Time:~0,8%
SET newdate=%newdate::=%
SET foldername=svetlana_backup_%newdate%
REM Variables
SET drive=R:
SET sevenZip=%USERPROFILE%\7z.exe
SET destination=R:\Backup
ECHO Running Backup Batch File
ECHO Please Plug in %drive%
PAUSE
ECHO %foldername%
MKDIR %destination%\%foldername%
FOR /F "tokens=1,2 delims=," %%i IN (backuplist.txt) DO (
SET completeSource=%%i
SET completeDestination=%destination%\%foldername%\%%j
ECHO Source: "!completeSource:"=!"
ECHO Destination:"!completeDestination:"=!"
MKDIR "!completeDestination:"=!"
XCOPY "!completeSource:"=!" "!completeDestination:"=!" /E /F
)
REM Zip the folder using the 7z command line utility
%sevenZip% a -tzip %destination%\%foldername%.zip %destination%\%foldername%
REM Remove the unzipped backup folder
RMDIR /Q /S %destination%\%foldername%
PAUSE
EXIT
This is a backup batch file that I've been using for last couple of days. It worked well up until this morning. For some reason, when it creates the variable foldername, it contains a space in the string where there was none before. It ends up like this:
svetlana_backup_22092016_ 93829
The space between the dash and the 93829 was never there before until today for some reason. How would I remove it and prevent it from happening again?
You can parse the file-/foldername like this
set foldername=%foldername: =%
This will replace all spaces with an empty string
The problem was likely caused because the test was run at a time where the hour contained just one digit. With that %Time:~0,8% will output the time including an extra space, as the time will be stored like this: 9:38:29 which are 7 characters and you read the last 8 ones.
I'm an amateur on the usage of the FOR command. I need a batch file that will run one of 5 file conversion tools based on a file's extension. I want to drop a file onto the batch file icon and have it converted.
Since my list is huge, I can't use nested IF's.
What I've tried so far:
#ECHO OFF
SET cadfile=.dwg .dxf .dwf
SET gsfile=.ps .eps .epi .epsp
SET xxxxxx=.xx .xx and goes on
FOR %%~x1 in (%cadfile%) do (
Do some action
FOR %%~x1 in (%gsfile%) do (
Do some other action
)
)
The %%~x1 variable is used for file extension of file, which dragged and dropped over the batch file.
(edited to make more clear)
FOR %%a in (%cadfile%) do (
if /i "%~x1"=="%%a" some_action "%~1"
)
... and follow the bouncing ball for the rest of the utilities/lists
I think this will work for you. It looks through all your groups of extensions in a single For loop and when the matching extension is found, calls a label where you can do the conversion and any related tasks. You'll need to finish the "groupN" variables and labels.
#echo off
SETLOCAL EnableDelayedExpansion
set file="%1"
set ext=%~x1
:: Set the 5 groups of extensions that have different converters
set group1=.dwg, .dxf, .dwf
set group2=.ps, .eps, .epi, .epsp
For %%A in (1 2 3 4 5) do (
set groupnum=group%%A
call set thisgroup=%%!groupnum!%%
:: Look for extension in this group
echo.!thisgroup!|findstr /i /C:"%ext%" >nul 2>&1
if not errorlevel 1 call :group%%A
:: else go loop next group
)
echo Extension not found in any group &pause &goto end
:group1
echo group1 file to convert is %file%
goto end
:group2
echo group2 file to convert is %file%
goto end
:end
pause
exit
The following method allows you to easily add and modify your list of extensions/applications. Please note that you just need to edit the values placed inside the first FOR command; the rest of the program is the solution you don't need to care of...
#echo off
setlocal EnableDelayedExpansion
rem Define the list of extensions per application:
rem (this is the only part that you must edit)
for %%a in ("cadfile=.dwg .dxf .dwf"
"gsfile=.ps .eps .epi .epsp"
"xxxxxx=.xx .xx1 .xx2") do (
rem The rest of the code is commented just to be clear,
rem but you may omit the reading of this part if you wish
rem Separate application from its extensions
rem and create a vector called "ext" with an element for each pair
for /F "tokens=1,2 delims==" %%b in (%%a) do (
rem For example: %%b=cadfile, %%c=.dwg .dxf .dwf
for %%d in (%%c) do set "ext[%%d]=%%b"
rem For example: set "ext[.dwg]=cadfile", set "ext[.dxf]=cadfile", set "ext[.dwf]=cadfile"
rem In the next line: set "ext[.ps]=gsfile", set "ext[.eps]=gsfile", etc...
)
)
rem Now process the extension of the file given in the parameter:
if defined ext[%~x1] goto !ext[%~x1]!
echo There is no registered conversion tool for %~x1 extension
goto :EOF
:cadfile
echo Execute cadfile on %1 file
rem cadfile %1
goto :EOF
:gsfile
echo Execute gsfile on %1 file
rem gsfile %1
goto :EOF
etc...
If each conversion tool is executed in the same way and don't require additional parameters (just the filename), then you may omit the individual sections and directly execute the conversion tools this way:
if defined ext[%~x1] !ext[%~x1]! %1
For further explanations on array concept, see this post.
I wrote myself a script based off another one that I found and I'm having trouble figuring out why it's not working.
How it is supposed to work is once a torrent has finished downloading, it runs the script and grabs the Label on the torrent. For testing, I was downloading a song with the label of Music.
When it gets to the point at :copyfile, it won't move it into the correct directory. Instead of moving into F:\Completed Torrents\Music, it just moves into F:\Completed Torrents.
Can someone please point out what I'm missing because I've looked through it thrice already and it's driving me crazy. The script is below.
#echo off
title Liam's torrent-file script
rem Parameter usage: fromdir torrent-name label kind [filename]
rem corresponds to uTorrents flags: %D %N %L %K %F
echo *********************************************
echo Run on %date% at %time%
set fromdir=%1
set name=%2
set label=%3
set kind=%4
set filename=%5
set savepartition="F:\Completed Torrents"
set winrar="C:\Program Files (x86)\WinRAR\WinRAR.exe"
set torrentlog="F:\Torrent Scripts\logs\torrentlog.txt"
set handledlog="F:\Torrent Scripts\logs\handled_torrents.txt"
set errorlog="F:\Torrent Scripts\logs\ErrorLog.txt"
set label_prefix=""
echo Input: %fromdir% %name% %label% %kind% %filename%
rem Check if the label has a sub label by searching for \
if x%label:\=%==x%label% goto skipsublabel
rem Has a sub label so split into prefix and suffix so we can process properly later
echo sub label
for /f "tokens=1,2 delims=\ " %%a in ("%label%") do set label_prefix=%%a&set label_suffix=%%b
rem add the removed quote mark
set label_prefix=%label_prefix%"
set label_suffix="%label_suffix%
echo.prefix : %label_prefix%
echo.suffix : %label_suffix%
goto:startprocess
:skipsublabel
echo Skipped Sub Label
goto:startprocess
:startprocess
echo %date% at %time%: Handling %label% torrent %name% >> %handledlog%
rem Process the label
if %label%=="Movies" goto known
if %label%=="Music" goto known
if %label_prefix%=="TV" goto TV
rem Last resort
rem Double underscores so the folders are easier to spot (listed on top in explorer)
echo Last Resort
set todir=%savepartition%\Unsorted\__%name%
if %kind%=="single" goto copyfile
if %kind%=="multi" goto copyall
GOTO:EOF
:known
echo **Known Download Type - %label%
set todir=%savepartition%\%label%\%name%
echo todir = %todir%
GOTO:process
:TV
echo **Known Download Type - %label%
set todir=%savepartition%\%label_prefix%\%label_suffix%
echo todir = %todir%
GOTO:process
:process
rem If there are rar files in the folder, extract them.
rem If there are mkvs, copy them. Check for rars first in case there is a sample.mkv, then we want the rars
if %kind%=="single" goto copyfile
if exist %fromdir%\*.rar goto extractrar
if exist %fromdir%\*.mkv goto copymkvs
if %kind%=="multi" goto copyall
echo Guess we didnt find anything
GOTO:EOF
:copyall
echo **Type unidentified so copying all
echo Copy all contents of %fromdir% to %todir%
xcopy %fromdir%\*.* %todir% /S /I /Y
GOTO:EOF
:copyfile
rem Copies single file from fromdir to todir
echo Single file so just copying
echo Copy %filename% from %fromdir% to %todir%
xcopy %fromdir%\%filename% %todir%\ /S /Y
GOTO:EOF
:copymkvs
echo Copy all mkvs from %fromdir% and subdirs to %todir%
xcopy %fromdir%\*.mkv %todir% /S /I /Y
GOTO:EOF
:extractrar
echo Extracts all rars in %fromdir% to %todir%.
rem Requires WinRar installed to c:\Program files
if not exist %todir% mkdir %todir%
IF EXIST %fromdir%\subs xcopy %fromdir%\subs %todir% /S /I /Y
IF EXIST %fromdir%\subtitles xcopy %fromdir%\subtitles %todir% /S /I /Y
call %winrar% x %fromdir%\*.rar *.* %todir% -IBCK -ilog"%todir%\RarErrors.log"
IF EXIST %fromdir%\*.nfo xcopy %fromdir%\*.nfo %todir% /S /I /Y
GOTO:EOF
EDIT
Also, for some reason, on line 39 nothing prints to the log. For those who wish to see the code with line numbers: http://hastebin.com/juqokefoxa.dos
A couple of bits for ya:
1) Likely, your script isn't moving the files. Preferences / Directories has an option to move downloads when completed. verify that these settings aren't doing the file moving.
2) uTorrent locks the files on completion so that seeding can continue. To change this behavior, go to Preferences / Advanced and set bt.read_only_on_complete to false
3) you will still be foiled because "Run this program when a torrent finishes" doesn't really do what it says. It runs the program as downloading reaches 100%, but while uTorrent is still either moving the file or seeding. See my bug report here.
A quick summary of the post, just in case that post gets deleted: you have to set the command in "Run this program when a torrent changes state:", add a %S parameter and check that %S == 11
4) Just a tip from my attempt at doing something very similar: when you set the variables from the arguments, add a tilde (%~1 instead of %1). This will strip the quotes off and let us more easily build command lines with the variables later.
You say that the log is not being written to. Try this as a test and see if it writes to the log.
If it doesn't there there is some other fundamental problem.
#echo off
title Liam's torrent-file script
rem Parameter usage: fromdir torrent-name label kind [filename]
rem corresponds to uTorrents flags: %D %N %L %K %F
echo *********************************************
echo Run on %date% at %time%
set "fromdir=%~1"
set "name=%~2"
set "label=%~3"
set "kind=%~4"
set "filename=%~5"
set "savepartition=F:\Completed Torrents"
set "winrar=C:\Program Files (x86)\WinRAR\WinRAR.exe"
set "torrentlog=F:\Torrent Scripts\logs\torrentlog.txt"
set "handledlog=F:\Torrent Scripts\logs\handled_torrents.txt"
set "errorlog=F:\Torrent Scripts\logs\ErrorLog.txt"
set "label_prefix="
set "handledlog=%userprofile%\desktop\handled_torrents.txt"
>> "%handledlog%" echo Input: "%fromdir%" "%name%" "%label%" "%kind%" "%filename%"
>> "%handledlog%" echo %date% at %time%: Handling "%label%" torrent "%name%"
I am creating an MS DOS batch script that needs to list every .bat file in the current directory, but not show autoexec.bat or other utilities or systems .bat files that shouldn't be run by the user.
I currently have DIR "*.bat" /B /P
This lists all .bat files appropriately, but it shows autoexec.bat. How would I exclude that from the list? Also slightly important, how could I chop off the file extensions and show more than the 7-characters DOS limits files to?
Constraints: I am not able to use a DOS version above WinME. That is the version I am using.
Thanks for any help.
EDIT:
There is plenty of information on the internet about doing this, but it is all in the windows command processor, not MS DOS. Please understand that DOS and the Command Prompt are not the same thing.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
echo %%~Na
)
)
EDIT: Some explanations added
Batch file processing is slow, so you should use techniques that allows a Batch file to run faster. For example:
Try to use the minimum lines/commands to achieve a certain result. Try to avoid external commands (*.exe files) like find, findstr, fc, etc. specially if they work on small amounts of data; use if command instead.
Use for %%a in (*.bat)... instead of for /F %%a in ('dir /B *.bat').... The second method requires to execute cmd.exe and store its output in a file before for command can process its lines.
Avoid pipes and use redirections instead. A pipe require the execution of two copies of cmd.exe to process the command at each side of the pipe.
A simple way to check if a variable contain a given string is trying to delete the string from the variable: if the result is different then the string exists in the variable: if "!variable:%string%=!" neq "%variable%" echo The string is in the variable.
Previous method may also be used to check if a variable have anyone of a list of values: set list=one two three, if "!list:%variable%=!" neq "%list%" echo The variable have one value from the list. If the values of the list may have spaces, they must be separated by another delimiter.
EDIT: New version added as answer to new comments
The easiest way to pause one page at a time is to use more filter this way:
theBatchFile | more
However, the program must reorder the output in order to show it in columns. The new version below achieve both things, so it does not require more filter; you just need to set the desired number of columns and rows per page.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
rem Set the first two next variables as desired:
set /A columns=5, rows=41, wide=(80-columns)/columns, col=0, row=0
rem Create filling spaces to align columns
set spaces=
for /L %%a in (1,1,%wide%) do set spaces= !spaces!
set line=
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
rem If this column is less than the limit...
set /A col+=1
if !col! lss %columns% (
rem ... add it to current line
set name=%%~Na%spaces%
set "line=!line!!name:~0,%wide%! "
) else (
rem ... show current line and reset it
set name=%%~Na
echo !line!!name:~0,%wide%!
set line=
set /a col=0, row+=1
rem If this row is equal to the limit...
if !row! equ %rows% (
rem ...do a pause and reset row
pause
set row=0
)
)
)
)
rem Show last line, if any
if defined line echo %line%
Antonio
attrib +h autoexec.bat
should hide autoexec.bat and it should thus not appear in the list
DIR "*.bat" /B /P | find /v "autoexec" | for %i in (*.bat) do #echo %~ni
Using for to process each file name individually:
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.bat" /b') do (
set system=0
if "%%i"=="autoexec.bat" set system=1
if "%%i"=="somesystem.bat" set system=1
if !system!==0 echo %%i
)
Another method without variables:
for /f %%i in ('dir "*.bat" /b') do call :test %%i
goto continue
:test
if "%1"=="autoexec.bat" goto :eof
if "%1"=="somesystem.bat" goto :eof
echo %1
goto :eof
:continue
For both, you can add new filenames to exclude from the list.