Batch file read from largest registry sub-key? - scripting

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" "."

Related

I need a batch program to find the folder name inside another folder [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
For example
consider:
H:\reports\test\12345\dailynews.pdf
I want to send this PDF through mail by using MSSQL job (sql server 2008 R2).
But every time when another job creates the pdf file the location changes.
like
H:\reports\test\48596\dailynews.pdf
I need a batch program to find the folder name which is present after the test folder.
A recursive check may report same named files existing elsewhere in the tree and may take longer. My suggestion is to use this instead:
#Echo Off
Set "MyFile="
For /D %%A In ("H:\reports\test\*"
) Do If Exist "%%A\dailynews.pdf" Set "MyFile=%%~fA\dailynews.pdf"
If Not Defined MyFile Exit/B
Echo %%MyFile%% = %MyFile%
Regarding the given info, I would suggest to
split the string at the backslashes and extract the 4th element like this:
set p=H:\reports\test\12345\dailynews.pdf
for /F "delims=\ tokens=4" %%a in ("%p%") do echo %%a
Note the double quotes ("%p%"), so it gets interpreted as string (and not as a filename or command).
If you want to make sure, that the 3rd element is the test folder, then I would suggest:
set p=H:\reports\test\12345\dailynews.pdf
set o=H:\reports\live\55555\dailynews.pdf
for /F "delims=\ tokens=3,4" %%a in ("%p%") do if "%%a"=="test" echo %%b
for /F "delims=\ tokens=3,4" %%a in ("%o%") do if "%%a"=="test" echo %%b
Outputs 12345 but not 55555, which is in the live folder.
Edit:
I realized that my answer left out completely, how one can detect the newest dailynews.pdf, which is what the OP probably looking for.
Like the dailynews routine runs at 21.00, and you want to mail that report at 22.00. (Again, yet another assumption.)
IMO, the tricky part is to parse and compare the date/time info of the files.
A simple dir dailynews.txt /S /O:-D does not work with subdirs.
So...
#echo off
cls
set base=H:\reports\test
set filename=dailynews.pdf
set current_date=19000101
set current_time=0000
set current_file=
::debug output
dir "%filename%" /S /O:-D
:: inspect each entry
for /F "usebackq" %%a in (`dir "%filename%" /S /B /O:-D`) do call :inspect "%%a"
:: all done, quit
goto :quit
:: subroutine for comparing current with actual newest entry
:inspect
echo %1
set _date=
set _time=
:: get comparable date time info
:: change to your regional date/time settings/locale! (german here)
:: maybe check SO for other locales
for /F "usebackq tokens=1,2,3,4,5 delims=.: " %%a in (`dir %1^|findstr "%filename%"`) do echo %%a %%b %%c %%d %%e&set _date=%%c%%b%%a&set _time=%%d%%e
:: we have to split in two components, otherwise it seems too big for comparing
if /I %_date% LSS %current_date% goto :eof
if /I %_time% LSS %current_time% goto :eof
:: this one is newer! set new values
set current_date=%_date%
set current_time=%_time%
set current_file=%1
goto :eof
:quit
set current_
Performance may get worse if you dont clean up the basedir at some time.

batch script for file system: use of for-loop variable in another nested for-loop

the last 4-5 hours I spent trying to get my script fixed, and tried several things, but it still doesn't work as supposed. Here is the working part:
#echo off
rem automatically sort MP3s into an existing structure or add folders if needed
rem example of MP3-file pattern: Wu-Tang Clan - Gravel Pit (LP Version Clean).mp3
SETLOCAL
rem set variables
SET "source=g:\music\folder"
SET "str=Wu-Tang Clan - Gravel Pit (LP Version Clean).mp3"
SET "test=%source%\%str%"
rem split the filename from the remaining path. Take the left part
rem and assign it to %band% while the right part gets assigned to %song%
FOR /f "delims=" %%i IN ("%test%") DO SET "result=%%~nxi"
SET "band=%result: - =" & SET "song=%"
rem If there is no such folder (%band%), create it
IF not exist "%source%\%band%" MD "%source%\%band%"
rem As soon as there definetely is a fitting folder
rem move the file over there.
MOVE /-Y "%source%\%result%" "%source%\%band%"
The next step would be to enhance the code by a for-loop so I don't have to edit the script for every single one of my 3k+ files ;)
I tried really hard to get this code going, but failed:
#echo off
SETLOCAL
SET "source=g:\music\folder"
FOR %%f IN (%source%\*.mp3) DO (
echo %%f
FOR /f "delims=" %%i IN ("%%f") DO SET "result=%%~nxi"
SET "band=!result: - =" & SET "song=%"
IF not exist "%source%\%band%" MD "%source%\%band%"
MOVE /-Y "%source%\%result%" "%source%\%band%"
)
pause
So I added a for-loop and %%f was correctly filled at first and wasn't in the next for-loop.
FOR %%f IN (%source%\*.mp3) DO (
echo %%f
That resulted in: "g:\music\folder\Wu-Tang Clan - Gravel Pit (LP Version Clean).mp3"
Like it was supposed to. But after that
FOR /f "delims=" %%i IN ("%%f") DO SET "result=%%~nxi"
result and every following variable was empty, always.
I tried to fix it with a second variable as a 'helper':
FOR %%f IN (%source%\*.mp3) DO (
SET "helper=%%f"
FOR /f "delims=" %%i IN ("%helper%") DO SET "result=%%~nxi"
Even added 'enabledelayedexpansion' after I read about that and went for
FOR /f "delims=" %%i IN ("!helper!") DO SET "result=%%~nxi"
still doesn't work.
Now I could really need some help and would really appreciate it :)
regards Phoenix
Next code snippet could work. Note that the SET "band=%result: - =" & SET "song=%" trick can't be performed using ! delayed expansion unlike %-expansion. Therefore, that command is moved to the :myset subroutine and executed via call command.
#echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
SET "source=g:\music\folder"
FOR %%f IN (%source%\*.mp3) DO (
echo %%f
FOR /f "delims=" %%i IN ("%%f") DO SET "result=%%~nxi"
call :myset
IF not exist "%source%\!band!" MD "%source%\!band!"
MOVE /-Y "%source%\!result!" "%source%\!band!"
)
goto :skipMyset
:myset
SET "band=%result: - =" & SET "song=%"
goto :eof
:skipMyset
pause
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(special page) EnableDelayedExpansion

batch: storing folderpaths in variables

Win7/64bit/batch/beginner
To sum this up, I'm trying to
search an/all external drive/s for a certain folder and
copy it to another location.
I looked up for-loops and the xcopy stuff but I'm completely new to batch scripting so this is what I got so far:
#echo off
::I found this to be useful for variables in for-loops
Setlocal EnableDelayedExpansion
set odrive=%odrive:~0,2%
set backupcmd=xcopy /S /C /G /D /E /I /R /Y
::this part is meant to find all available drives
for %%i in (D E F G H I J) do if exist %%i: (
::and store the drive name
set target=!target!%%i:\
echo "!target!"
::now I want to find a certain folder and use its filepath
for /d /r "!target!" %%a in (*) do if /i "%%~nxa"=="foldername"
set folderpath=!folderpath!%%a ::I want to use this just like I did earlier
echo "!folderpath!" ::but it turns out to be empty
::the last step is to use the folderpath for the backupcmd
%backupcmd% "!folderpath!" "%drive%\backedUpFiles"
::reset variables
set "target="
set "folderpath="
)
No idea if any of this is actually "good" batch scripting but so far I can follow and understand it. I'm expecting the error to be somewhere between the lines (literally) and maybe it has just to do with how I'm using variables.
The error is something about "invalid drive name".
I hope someone can help me since I'm really done searching code after some days.
Try this:
#echo off
Setlocal EnableDelayedExpansion
set searchitem=level 3
set target=%drive%\backedUpFiles
set backupcmd=xcopy /S /C /G /D /E /I /R /Y
set backupcmd=echo
for %%X in (C D E F G H I J) do if exist %%X:\ (
if exist "%%X:\%searchitem%\" %backupcmd% "%%X:\%searchitem%\" "%target%"
for /f "delims=" %%D in ('dir /b/s/ad "%%X:\%searchitem%" 2^>nul') do %backupcmd% "%%D" "%target%"
)
As examples I've set the foldername to search for to "level 3" to demonstrate foldernames with embedded spaces. In the loop we've got to handle firstlevel subfolders separately (a quirk of dir, not listing the foldername but it's content). I found dir to be much faster than a for /R loop, which I didn't get to run without errors anyway.

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%

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.