Sargon
Sargon

Reputation: 55

Batch: Comparing version numbers via GEQ when said version uses dots and varying number of digits

I've been using the following bit of CMD code to check Edge versions, but the move from 99 to 100 seems to have thrown a wrench in the code.

FOR /F "Tokens=2*" %%G IN ('REG QUERY "HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}" /V "pv" ^| FINDSTR "REG_SZ"') DO (IF %%H GEQ 100.0.1185.29 (ECHO Microsoft Edge is version %%H and does not require an update. & GOTO SomethingElse) ELSE (ECHO Microsoft Edge is version %%H and requires an update. & GOTO MSEdgeInstall))

It now thinks that, for example, 99.9.1150.30 is higher than 100.0.1185.29. Now if I were to remove the dots, it would realise that 999115030 was, in fact, smaller than 1000118529. There's something about the presence of dots and an additional digit that causes the calculation in cmd to fail.

Is there some clever way to resolve this, or do I have to essentially remove the dots from the registry query before comparing from now on?

Upvotes: 0

Views: 262

Answers (2)

Magoo
Magoo

Reputation: 80138

Depends on how far you want to go with the version-matching.

If you want to match only the major version, then

FOR /F "Tokens=3*delims=. " %%H IN ('REG QUERY "HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}" /V "pv" ^| FINDSTR "REG_SZ"') DO (IF %%H GEQ 100 (ECHO Microsoft Edge is version %%H.%%I and does not require an update. & GOTO SomethingElse) ELSE (ECHO Microsoft Edge is version %%H.%%I and requires an update. & GOTO MSEdgeInstall))

Otherwise, it's more complicated. Your code matches the detected version against the required version as a string because the two strings are not purely numeric. Even removing the dots, you'd need to compare each component individually, as version 100.1 would be less than 99.10 (1001 < 9910).

Please note that I've changed the metavariable from %%G to %%H

I'd suggest

FOR /F "Tokens=3" %%H IN ('REG QUERY "HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}" /V "pv" ^| FINDSTR "REG_SZ"') DO (call :vercmp %%H 100.0.1185.29 & if defined vergt (ECHO Microsoft Edge is version %%H and does not require an update. & GOTO SomethingElse) ELSE (ECHO Microsoft Edge is version %%H and requires an update. & GOTO MSEdgeInstall))

and the subroutine :vercmp

:vercmp
set "vergt="
for /f "delims=." %%V in ("%1") DO for /f "delims=." %%v in ("%2") do (
 if %%V lss %%v (goto :eof) else if %%V neq %%v (set "vergt=Y"&goto :eof)
 if %%W lss %%w (goto :eof) else if %%W neq %%w (set "vergt=Y"&goto :eof)
 if %%X lss %%x (goto :eof) else if %%X neq %%x (set "vergt=Y"&goto :eof)
 if %%Y geq %%y set "vergt=Y"
)
goto :eof

which should set vergt to Y if %1>%2 in the required manner.

The routine :vercmp receives two parameters : %%H being the third token in the filtered REG QUERY command output (ie. the current version number string) and the version number against which to compare.

First, set vergt to nothing (which makes vergt undefined) Then tokenise the two .-delimited strings into %%V..%%Y and %%v..%%y.

Compare the 4 fields progressively, setting vergt to Y only if the field in the first string is greater than that in the second.

AT the end of the routine, vergt will be either Y or undefined so it can be used to control actions based on this Boolean state using if defined vergt which operates on the run-time state of vergt (see Using Boolean )


Here's some general guidelines I use

@ECHO OFF
:: The above line should be used to start all batch programs. It's easy to change "OFF" to "ON" for debugging
:: It turns command-echoing off. A line starting "@" will never be echoed.

:: Next, one of these two - not both

SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION

:: SETLOCAL establishes a local environment which lasts until end-of-file or an ENDLOCAL statement is reached
:: The local environment is a copy of the current environment, but any changes made to the environment
:: will be undone and the original environment restored when the end-of-file or an ENDLOCAL statement is reached
:: qv for enabledelayedexpansion

:: Setting variables
::
:: Variables may contain alphabetical characters or numerics or some symbols, but should not start with a numeric.
:: They are case-insensitive, as is batch generally - with one major exception (qv)
:: 
:: Syntax for setting string variables
SET "sourcedir=u:\your files"

:: The following formats are NOT recommended
SET sourcedir=u:\your files
:: because trailing spaces on the line would be included in the value assigned.
SET "sourcedir = u:\your files"
:: because the spaces would be included in both the variable name and in the value assigned.
:: This would set the variable "sourcedir " to the value " u:\your files"
SET "sourcedir="u:\your files""
SET sourcedir="u:\your files"
SET "sourcedir=u:\your files\"
:: because it turns out to be easier to concatenate variable values (which is done often in batch) if those
:: values are quoteless and do not have a terminal "\" (or space)

:: Syntax for setting numeric variables
SET /a var=6
:: where the "value assigned" may be a formula like 3 + 7*(avar + 1)

:: Numerics are integers in the range -(2**32) to (2**32)-1
:: BUT they are stored as strings, and can be used as strings. 
:: BEWARE - batch interprets a string that starts with a zero as OCTAL

:: Concatenating variables
SET "filename1=%sourcedir%\recstruct.txt"
:: put a variable name between "%" signs to access the valur of that variable.

:: Substringing variables
SET "substring=%filename1:m,n%"
:: (where m and n are integers)
:: sets the variable SUBSTRING to the n characters starting at character m
:: m is counted from 0 as the first character of the string
:: ,n is optional. If missing, returns the string except the first m characters
:: If m or n is negative, it is the number of characters from the end of the string

:: For loops
FOR %%X IN (one two three) DO ECHO %%X
:: The metavariable X must be a single LETTER and is CASE-SENSITIVE.

:: Two colons is an unreachable label and is often used for comments
REM is the documented remark statement but takes longer to type and is more visually intrusive

FOR %%X IN (one two three) DO (
 ECHO %%X...once
 REM comments within a code block must be of the REM form, not ::
 ECHO %%X...twice
 ECHO %%X...thrice
)
:: Parenthesising lines of code - typically in a "FOR" statement forms a "code block"
:: Such blocks are first evaluated, then executed so if you are varying a variable
:: within the block, you need DELAYEDEXPANSION and use !var! to access the new value
:: See Stephan's DELAYEDEXPANSION link: https://stackoverflow.com/a/30284028/2128947
:: for details

CALL xsubroutine optionalparameters
:: Executes the commands in the executable "xsubroutine", typically "xsubroutine.bat" 

CALL :isubroutine optionalparameters
:: Executes the commands in the internal routine :isubroutine. The label :isubroutine must
:: be in this file (the ":" indicates "internal")

:: This command jumps to the end of this batch file. 
:: CMD understands ":EOF" to be end-of-file, and it should not be added as a user label.
GOTO :EOF

:: Were it not for the GOTO :EOF. batch would simply careen through here to the next instruction
                                                 
:: Here's the subroutine isubroutine
:isubroutine
ECHO IN subroutine
:: then go to end-of-file to exit the subroutine and return to the command following the CALL

GOTO :EOF

:: Here are other internal subroutines
:: Each internal subroutine should follow a "goto :eof" statement. 
:: It doesn't really matter where that "goto :eof" is in the code. 
:isubroutine2
ECHO IN subroutine2

GOTO :EOF

Upvotes: 1

Sargon
Sargon

Reputation: 55

While Magoo's code errored out for me somewhere, or I'm just not clever enough to understand it, it did give me a good advice on comparing each number individually, so thank you for that Magoo. I'd upvote you but my rank's too low apparently.

What I came up with instead is the following:

@ECHO Off

SET "DesiredVersionColumn01=100"
SET "DesiredVersionColumn02=0"
SET "DesiredVersionColumn03=1185"
SET "DesiredVersionColumn04=29"

FOR /F "Tokens=3*" %%G IN ('REG QUERY "HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}" /V "pv" ^| FINDSTR "REG_SZ"') DO (SET "CurrentVersionFull=%%G")
FOR /F "Tokens=1* Delims=. " %%G IN ('ECHO %CurrentVersionFull%') DO (SET "CurrentVersionColumn01=%%G" & SET "CurrentVersionColumnRemaining=%%H")
FOR /F "Tokens=1* Delims=. " %%G IN ('ECHO %CurrentVersionColumnRemaining%') DO (SET "CurrentVersionColumn02=%%G" & SET "CurrentVersionColumnRemaining=%%H")
FOR /F "Tokens=1* Delims=. " %%G IN ('ECHO %CurrentVersionColumnRemaining%') DO (SET "CurrentVersionColumn03=%%G" & SET "CurrentVersionColumn04=%%H")

REM These are just for show, not really needed:
ECHO Edge Full Version: %CurrentVersionFull%

ECHO Edge Version Without Dots: %CurrentVersionColumn01% %CurrentVersionColumn02% %CurrentVersionColumn03% %CurrentVersionColumn04%

REM Version Checking
ECHO Ensuring that Microsoft Edge is version %DesiredVersionColumn01%.%DesiredVersionColumn02%.%DesiredVersionColumn03%.%DesiredVersionColumn04% or above.
IF %CurrentVersionColumn01% GTR %DesiredVersionColumn01% (ECHO Microsoft Edge is version %CurrentVersionFull% and does not require an update. C1 & GOTO NoInstall)
IF %CurrentVersionColumn01% EQU %DesiredVersionColumn01% IF %CurrentVersionColumn02% GTR %DesiredVersionColumn02% (ECHO Microsoft Edge is version %CurrentVersionFull% and does not require an update. C2 & GOTO NoInstall)
IF %CurrentVersionColumn02% EQU %DesiredVersionColumn02% IF %CurrentVersionColumn03% GTR %DesiredVersionColumn03% (ECHO Microsoft Edge is version %CurrentVersionFull% and does not require an update. C3 & GOTO NoInstall)
IF %CurrentVersionColumn03% EQU %DesiredVersionColumn03% IF %CurrentVersionColumn04% GEQ %DesiredVersionColumn04% (ECHO Microsoft Edge is version %CurrentVersionFull% and does not require an update. C4 & GOTO NoInstall)
ECHO ECHO Microsoft Edge is version %CurrentVersionFull% and requires an update. C Full & GOTO Install


:Install
ECHO Installing
PAUSE
EXIT

:NoInstall
ECHO Not Installing
PAUSE
EXIT

I think this is now error-proof. If it isn't then I missed it lol.

I'll still try to find out why Magoo's code is erroring out for me, as it seems more efficient than mine.

Upvotes: 0

Related Questions