syntax error on batch File to create a timestamp directory - scripting

I tried the script below to create a timestamp directory in one of my drives, for some reason is giving me a syntax error on the last string where it create the directory. See below.
:: Code begins....
pause
W:
pause
cd W:\VL2000_AMF\AMF_Archive
pause
for /F "tokens=1-4 delims=. " %%i in ('date /t') do (
set Day=%%i
set Month=%%j
set Year=%%k
)
pause
for /F "tokens=1-4 delims=: " %%i in ('time /t') do (
set Hour=%%i
set Minute=%%j
set Second=%%k
)
pause
md %1\%Year%-%Month%-%Day%
pause
:: Code ends....

I used the following on Windows 2000 and 2003 to get year, month, and day from the date command output. Unfortunately, I no longer have any XP systems to see if this will work there.
for /F "tokens=2-4 delims=/ " %%i in ('date /t') do (
echo "Day=%%i"
echo "Month=%%j"
echo "Year=%%k"
)
What is the format of "date /t" and "time /t" output on XP?

Are you sure your date is coming back as mm.dd.yyyy (separated by dots, and with the fields in the order you expect)? If the process's locale is not what you expect, you might be ending up with %Day% as something like 8/17/2010, which would cause md to report a syntax error as it tries to interpret /17 and /2010 as options.

Related

How to set batch variable to output of another script

I try to set a batch variable to an output of another command. In Linux/Unix you can simply use backticks, e.g. (in csh)
set MY_VAR = `tail /etc/passwd`
Is there something similar available in windows batch?
Actually I found already something but it is not fully working:
d:\>for /F "skip=1" %n in ('wmic OS Get CurrentTimeZone') do set TimeZone=%n
d:\>set TimeZone=120
:\>set TimeZone=
d:\>
The problem is the wmic commands returns several lines, otherwise it would work fine. The first I know to skip, however I did not manage to skip the second empty line. I tried with IF but no success.
yes - the output of wmic is a bit ugly to handle.
Use a trick: search for a number in the ouput (findstr "[0-9] will only return lines, that contain a number):
for /F %n in ('wmic OS Get CurrentTimeZone ^|findstr "[0-9]"') do set TimeZone=%n
echo Timezone is %TimeZone%.
(for use in a batchfile use %%n instead of %n)
Another way is:
for /F %n in ('wmic OS Get CurrentTimeZone') do if not defined TimeZone set TimeZone=%n
EDIT:
I prefer the first version, as findstr (or find) converts the wmic-line-endings, so the second for mentioned by MC ND is not neccessary.
I suggest following batch code:
#echo off
for /F "skip=1" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS Get CurrentTimeZone') do (
set "TimeZone=%%I"
goto BelowLoop
)
:BelowLoop
echo Time zone difference is: %TimeZone%
The FOR loop is exited with command GOTO after the value of interest is assigned to environment variable TimeZone.
The entire FOR loop can be optimized to a single command line:
#echo off
for /F "skip=1" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS Get CurrentTimeZone') do set "TimeZone=%%I" & goto BelowLoop
:BelowLoop
echo Time zone difference is: %TimeZone%
Exiting the FOR loop after having the value of interest avoids the problem with wrong parsing of Unicode (UTF-16 Little Endian) encoded output of WMIC by FOR which otherwise would result in deleting the environment variable TimeZone. For details on wrong parsing of Unicode output by FOR see answer on How to correct variable overwriting misbehavior when parsing output?
for /f "tokens=2 delims==" %a in ('wmic OS get CurrentTimeZone /value') do set "timeZone=%a"
(to use in a batch file, remember to double the percent signs)
The added /value in wmic changes its output to key=value format. The delims clause in for command indicates a = as a separator. The tokens clause ask to retrieve only the second token/field in the line. As the only line with two tokens is the line with the required data, only this line is processed.
BUT, wmic output includes an aditional carriage return at the end of its output, that needs to be removed from the variable. An aditional for command can be used. The resulting command will be
for /f "tokens=2 delims==" %a in ('wmic OS get CurrentTimeZone /value') do for /f %b in ("%a") do set "timeZone=%b"
Or, for a batch file
for /f "tokens=2 delims==" %%a in (
'wmic OS get CurrentTimeZone /value'
) do for /f %%b in ("%%a") do set "timeZone=%%b"
echo %timeZone%

Batch file - date variables and moving files with variable date file name from one folder to another

I need some assistance, please. I'm trying to create a batch file to move files from one folder to another. The file name will have variable yyyy-mm format plus additional data before or after the date. The batch will need to move the file to a server directory with the same mmmm-yy folder name.
I've come up with the code below, but it doesn't quite work.
A "Missing Operand" error is returned.
The new directory is created but the files are not moving from the old folder to the new one.
My code:
#echo off
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
SET /A MONTH=%%D
SET /A YEAR=%%F
)
:: Set month to last month
set /a MONTH=%MONTH%-1
:: If month equals zero, reset to 12
if %MONTH%==0 set MONTH=12
:: If month < 10, fill with zero
if %MONTH% LSS 10 set MONTH=0%MONTH%
:: If month = 12, subtract one year
if %MONTH%==12 set /a YEAR=%YEAR%-1
SET FILEDATE=%YEAR%-%MONTH%
SET FOLDER2=E:\ARCHIVE\%FILEDATE%
MKDIR %FOLDER2%
:: trying to recreate the format MOVE C:\FOLDER1\\*2013-07*.* E:\FOLDER2\2013-07 which does work
MOVE C:\FOLDER1\\*%FILEDATE%*.* %FOLDER2%
:END
EXIT
EDIT: Both responders below really helped. I tried to vote them up, but I guess my reputation is not good. Mother was right - guard your repuation! It will get you far. :)
You should better use %date%, not wmic, but you can try:
for /f "skip=1 delims=" %%a in ('WMIC Path Win32_LocalTime Get Month^,Year /Format:table') do for /f "tokens=1,2" %%b in ("%%a") DO SET "month=%%b" &SET "year=%%c"
Just a minor edit - it looks like it should work - as your explanation says the folder is being created just fine.
MOVE "C:\FOLDER1\*%FILEDATE%*" "%FOLDER2%"

OS Name Variable

I would like to run a script where I can get the windows Name and version of the system of all computers running in the company, put it in a text fil. Then make a system variable out of my windows name . I know what to run but where I am running into an issue is a place holder. so here is my code:
:OS_NAME
Set OS_NAME= systeminfo | find "OS Name"
:OS_Ver
Set OS_Version= systeminfo | findstr /B /C:"OS Version"
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /c:"BIOS Version" | >> G:\Directory\%Computername%
:OS_Arch
IF exist "%programfiles(x86)% (SET OS_ARCH=X64)
Else (SET OS_ARCH=X86)
:Win_7
systeminfo | find "Microsoft Windows 7" > nul
if %ERRORLEVEL% == 0 (
goto ver_7)
:Ver_7
Set Win7= systeminfo | find "Microsoft Windows 7"
Echo %computername% is running %WIN7% in %OS_ARCH% Environment >> G:\Directory\Win7Comps.txt
So basically I would like a place holder for the results of Systeminfo which i can refer to and parse it my SET command when I am making my system variables.
Thanks, any help would be appreaciated.
Not exactly sure what you're looking for, but the biggest problem I see is that systeminfo takes forever to run and returns much more information than you're looking for. You'd be better off capturing wmi queries using wmic. This is basically a rewrite of your example script, just using wmic rather than systeminfo. It should be much, much faster.
#echo off
setlocal
set prefix=G:\Directory
for /f "usebackq tokens=1,2 delims==|" %%I in (`wmic os get name^,version /format:list`) do 2>NUL set "%%I=%%J"
for /f "tokens=2 delims==" %%I in ('wmic bios get version /format:list') do set "bios=%%I"
for /f "tokens=2 delims==" %%I in ('wmic computersystem get model /format:list') do set "model=%%I"
>>"%prefix%\%COMPUTERNAME%" echo OS Name: %name%
>>"%prefix%\%COMPUTERNAME%" echo OS Version: %version%
>>"%prefix%\%COMPUTERNAME%" echo PC Model: %model%
>>"%prefix%\%COMPUTERNAME%" echo BIOS Version: %bios%
if defined PROGRAMFILES(x86) (set arch=X64) else set arch=X86
if "%name%" neq "%name:Windows 8=%" (
set out=%prefix%\Win8Comps.txt
) else if "%name%" neq "%name:Windows 7=%" (
set out=%prefix%\Win7Comps.txt
) else if "%name%" neq "%name:Windows Vista=%" (
set out=%prefix%\WinVistaComps.txt
) else if "%name%" neq "%name:Windows XP=%" (
set out=%prefix%\WinXPComps.txt
)
>>"%out%" echo %COMPUTERNAME% is running %name% in %arch% environment
Type wmic /? for more info, and try wmic computersystem get /? or similar to see a list of items that can be queried under each class.
wmic is the Swiss Army knife of Windows. Fun fact: you can even use wmic to generate a web page table of installed software on a remote system.
You are giving batch a little too much credit. If you ran echo %OS_NAME% it would literally echo systeminfo | find "OS Name". Variables in batch will always just expand, it won't process any further. This will also more than likely try to run find "OS Name" when you try to set the variable as the | is not escaped nor enclosed in double quotes.
If you want to set the output of a command to a value you have to capture it in a for statement like this:
for /f "tokens=2 delims=:" %%a in ('systeminfo ^| find "OS Name"') do set OS_Name=%%a
Then remove the leading spaces like this: (there is probably a better way to do this)
for /f "tokens=* delims= " %%a in ("%OS_Name%") do set OS_Name=%%a
A few things to note here. 1.) "tokens=2 delims=:" is setting the delimiter to : and it is selecting the second section only, which will pull only the part you want. 2.) the | is escaped with a ^, this needs to be done in for loops or anything after that will attempt to execute as seperate commands. 3.) "tokens=* delims= " The token here is * which is all tokens.
A few other problems I found.
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /c:"BIOS Version" | >> G:\Directory\%Computername%
This has an extra | character at the end.
IF exist "%programfiles(x86)% (SET OS_ARCH=X64)
Else (SET OS_ARCH=X86)
Two problems here, you didn't finish the double quote around the path, and else has to be on the same line as the ending parentheses of the if statement, like this:
IF exist "%programfiles(x86)% (SET OS_ARCH=X64
) Else (SET OS_ARCH=X86)
Otherwise it tries to process else as it's own command

Batch file read from largest registry sub-key?

I am trying to modify my batch script to get the install path for a piece of software, however it needs to be version independent and the install path is stored in a version sub-key, so basically what I am looking to do is detect the greatest version sub-key and get the install path from there.
Here is what the code for getting the registry value looks like now:
FOR /F "skip=2 tokens=2,*" %%A IN ('REG.exe query "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node......\6.30" /v "InstallLocation"') DO set "InstallPath=%%B"
Basically I want to not be dependent on the "6.30" part on the end of the key address, how can I do this?
Since I do not know which exact software you are looking at, I will reference Adobe Reader on Winodws 7 x64.
Answer:
The following example will output all of the sub keys within the parent.
for /f "delims=" %%A in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Adobe\Acrobat Reader"') do if not "%%~A"=="" echo.%%~nxA
Output:
9.5
10.0
11.0
Sample:
From there it would just be a matter of remembering the largest and using it in the next query for the value data.
#echo off
setlocal EnableDelayedExpansion
set "xVersion="
set "xPath="
:: Retrieve Greatest Version
for /f "delims=" %%A in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Adobe\Acrobat Reader"') do (
if not "%%~A"=="" if "%%~nxA" GTR "!xVersion!" set "xVersion=%%~nxA"
)
:: Validate Version
if "%xVersion%"=="" goto :eof
:: Retrieve Install Path
for /f "tokens=1,2,*" %%A in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Adobe\Acrobat Reader\%xVersion%\Installer" /v Path') do (
set "xPath=%%~C"
)
:: Show Results
echo.%xPath%
endlocal
Output:
C:\Program Files (x86)\Adobe\Reader 10.0\
Bonus:
If you want to validate that the %%~nxA is a number, here is a batch routine of mine.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:IsNumber <xReturn> <xInput> [xDelims]
:: Return true if the input is a base 10 number, else return false.
:::: Does not allow any seperators unless specified by xDelims. ,.[tab][space]
setlocal
if not "%~2"=="" set "xResult=true"
for /f "tokens=1 delims=1234567890%~3" %%n in ("%~2") do set xResult=false
endlocal & if not "%~1"=="" set "%~1=%xResult%"
goto :eof
:: Usage Example.
:: The variable xResult will be set to true if %%~nxA is a decimal number.
call :IsNumber xResult "%%~nxA" "."

Variables in loops Dont Work, Batch

This is the new Script and it Still Doesn't Work
I Get The syntax of the command is incorrect.
on FOR /F "USEBACKQ tokens=*" %%A IN (TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command") DO (
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "C:\Windows\System32\tasks\at%num%" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command"`) DO (
set var=%%A
ECHO %var%
SET /a num=%num%+1
PAUSE
)
GOTO:START
To understand your code, I'm going to break it down into logic first then try to solve it. Let me know if I miss a detail...
Set num var to 0
Begin :Loop
set num var to its current value ::NOT NEEDED - You've specified this prior to the GOTO
increment num var by +1
if myfolder\at* file exists then read at%num% and find a string then output that line to %tmp%\1.txt ::Need quotations on file location.
set F var to the line stored in %tmp%\1.txt
set F="%%F: =%%" ::Please explain what you are trying to do with this command.
set F to start on 10th character and remove the last 11 characters from the line.
echo the variable
If it doesn't exist, exit, but if it does return to :Loop
You should tell us what you are attempting. If it is as simple as saving a variable from a text file output, set F=<file.txt will work. If it didn't, then something happened prior to that command. Still... what is set F="%%F: =%%"?
Unless you are using a FOR loop variable, there is no need to use %% on each end of the variable.
If this were a FOR loop, it would look like this:
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "myFolder\at%num%.txt" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "myFolder\at%num%.txt" ^| FIND /i "string"`) DO (
PAUSE
SET var=%%A
ECHO !var!
PAUSE
SET var=!var: =!
ECHO !var!
PAUSE
SET var=!var:~10,-11!
ECHO !var!
PAUSE
SET /a num=!num!+1
ECHO !num!
PAUSE
)
GOTO:START
One good practice to check if commands are working, such as SET, insert an ECHO on the variable and a PAUSE right after each time you believe the variable should be changed. This will track what has changed on the variable so you can see if your command was correct and the changes were made.
I'd suggest using Batch's inbuilt function for loops, see here.
Conditionally perform a command for a range of numbers
Syntax
FOR /L %%parameter IN (start,step,end) DO command
Or maybe iterating over files in a folder would be better for what you are trying to do?
Loop through files (Recurse subfolders)
Syntax
FOR /R [[drive:]path] %%parameter IN (set) DO command
Or iterating over file contents?
Loop command: against a set of files - conditionally perform
a command against each item.
Syntax
FOR /F ["options"] %%parameter IN (filenameset) DO command
FOR /F ["options"] %%parameter IN ("Text string to process") DO command
This site has plenty of examples here which should point you in the right direction.
There are a few issues with your code, I've amended as follows to get the variable populated with the contents of the temp file.
set num=0
:Loop
set /a num=%num%+1
if exist "myFolder\at*" (
TYPE "myFolder\at%num%" | FINDSTR "\<Command\>" > "%temp%\1.txt"
set /P F=<"%TEMP%\1.txt"
Echo %F%
Pause
)
I don't know if this is the problem, but have you tried enabling:
setlocal enabledelayedexpansion
Then, inside the loop (or the IF(...)), you use !foo! to signify environment variables instead of %foo%.
See setlocal /? and set /? for more information.