71 - Grubutils - menuset, wenv, bios, grub4dos utilities and batch files - RMPrepUSB

71 - Grubutils - menuset, wenv, bios, grub4dos utilities and batch files

The GrubUtils utilites can be downloaded from Chenalls site here (this includes wenv, chkpci and other utilities). See the bottom of this page for a recent version (includes 2014 version of chkpci).

There are some interesting utilities that can be called or executed from grub4dos. The documentation is difficult to find and is usually in Chinese. Here are some notes which may be helpful.

When running an external grub4dos batch file or utility executable, you need to copy the file to your boot drive and make sure that the path is specified correctly in the menu.lst file, e.g.

/menuset 0 0 0 0 0 0 10 50 5 29 35

will run the file menuset which must exist on the root of the boot drive. menuset is contained in the grubutils package.

Note: The default command path for grub4dos is the current path (set by the root command) and the /boot/grub folder - it is recommended to place all your utilities in /boot/grub on your boot drive so that grub4dos can find them without needing to set the root or define a full path.

menuset 0 0 0 0 0 0 10 50 5 29 35

will run the file menuset which must exist in the /boot/grub folder or in the current root folder (as shown by the ls command).

The alternative is to path each command - e.g. use /bin/wenv instead of just wenv and place the wenv file at /bin.

Grub4dos Batch files

Max no lines = 2048 in a batch file, Max. no. labels in a batch file =128, file must start with !BAT on first line.

Grub4dos can execute a batch file (usually given a .g4b file extension, but sometime it has a .bat extension or no extension - whereas a grub4dos executable file has a .g4e extension or no extension). The grub4dos batch file must begin with !BAT. The syntax to use in the batch file is similar to that in a menu.lst file but not quite the same. For instance when using two variables together, you must use three % signs in a batch file because any two consecutive % signs will be treated as a single % sign in a batch file:

test.bat file contents:
set a=Fred is a
set b=GENIOUS!
echo %a%%%b%
echo Fred got 100%% in his test!

in a grub4dos commandline shell, type /test.bat
Fred is a GENIOUS!
Fred got 100% in his test!

Note that in a batch file we cannot use %a%%b% - we must add an extra % symbol and use %a%%%b%, but in a menu.lst file, echo %a%%b% will work and you don't need the extra % sign!

If want to add a SPACE before a value using set then use double-quotes:
set "C= fred"
or use double-quotes if it is possible that a variable's value (A in this case) might contain leading spaces (in batch file %%=% so we must use three % signs - %A%%%B%):
set "C=%A%%%B%"

tip: If you place all utility and batch files in the /boot/grub folder then grub4dos will find them without needing to specify a path.

tip: If you use debug 3 then you can single step a batch file (on later versions of grub4dos use debug <batchfile> <args> )

Also, if you call a grub4dos utility a lot in a batch file (for instance, in a loop or subroutine), then load it into memory first using the command insmod - e.g.
insmod /utils/wenv
wenv calc bs=%bs%-%bc2b%
will load wenv into memory so that whenever it is called later (with no path specified) it will run from memory instead of being loaded from the disk each time. Thus using insmod at the start of your batch file to load any utilities into memory will greatly improve the speed of execution! Insmod can also be called from within a menu.lst file and this will increase the speed of execution of grub4dos menus if you call a grub4dos utility within the menu.lst file, as well as any batch files you call afterwards. Use delmod <filename) to unload a file or :

::echo Checking if this batch file is loaded into memory - if not load it for faster execution
delmod -l %~nx0 || insmod %0

#Note: can only use filenames up to 11 characters (including the dot - i.e. up to 8.2 not 8.3) with insmod.

You can also call internal Function calls in a batch file using call Fn.x where x is a number and can be followed by one or more parameters - e.g.:

call Fn.0 0 "Hello" - will print Hello to the console

Here is a batch file to get lines from a text file, one at a time (redirecting bold blue lines will give a perfect copy of the file):

insmod %0 > nul
set n=0
set l=0
cat --locate=\x0d\x0a --number=1 --skip=%n% /menu.lst > nul
if "%?%"=="0x0" goto :EOF
set /a l=%?% - %n% > nul
::echo -e \nFound CR at start %n% length %l%
if %l%>=1 cat --skip=%n% --length=%l% /menu.lst
set /a n=%n% + %l% + 2 > nul
goto :LOOP

Tip: to get more lines on the console screen, type graphicsmode 179 first.

Here is a batch file to search for and list BIOS strings. Save the file to your grub4dos bootable disk as ShowBiosStrings.bat, boot to a grub4dos command prompt and then type:

ShowBiosStrings 0x680+0x180 CPU

and see what you get (tip: add insmod %0 to load the whole batch file into memory and speed it up a lot)!
This requires \grub\wenv. If a string is found the GOTSTR=1 is returned.

if "%1"=="FF" goto :FF
if "%1"=="" goto :EOF

:: Requires wenv in grub folder

:: Usage: ShowBiosStrings.bat [memorystart+memoryrange] [string]
:: where memorystart and memoryrange is in units of 512 bytes

:: e.g. ShowBiosStrings.bat 0x680+0x80 CPU
:: ShowBiosStrings.bat 0x700+0x80 "cpu\ is\ present"
:: ShowBiosStrings.bat 0x780+0x80 cpu\ is\ present

:: 0x680 = D000:0 in memory and is often use for storing DMI BIOS strings
:: 0x700 = E000:0 in memory and is used for DMI string as well a BIOS code and workspace
:: 0x780 = F000:0 in memory and is usually the BIOS code but may also contain fixed strings

:: 0x680+0x180 will search all BIOS area from D000:0 to end of BIOS area (FFFF:F)
:: 0x680+0x80 will seach the 64K segment from D000:0 only
:: 0x700+0x100 will search 128K from E000:0

:: This grub4dos batch file displays all BIOS strings matching the specified string
:: Case Insensitive - if one or more matches found GOTSTR=1

:: so we don't get invaild argument if no matches
errorcheck on
debug 1
set SLOC=%1
:: get location of strings from D000:0 to F000:FFFF in BIOS and DMI area
cat --locatei=%2 (md)%SLOC% | set a=
:: limit to 400 chars to reduce length of the for /f line below 512 chars!
set a=%a:~0,400%
if "%a%"=="" goto :EOF
:: parse the list and get first 17 locations into %i to %z - call this batch file again (%0) with FF as the first parameter so that it jumps to :FF
/grub/WENV for /f "delims= " %i in ( "%a%" ) do exec %0 FF %i %j %k %l %m %n %o %p %q %r %s %t %u %v %w %x %y

set a=
set A=
set z=
set SLOC=
goto :EOF

:: ============ SUBROUTINE =====


:: %2 %3 etc will have the first 17 locations
::echo @F 2=%2 3=%3 4=%4 5=%5 6=%6 7=%7 8=%8 9=%9
:: we may have an odd " in the string, turn off errorchecking otherwise it may abort
errorcheck off
set z=
if "%2"=="" goto :EOF
set z=%2
set z=%z:~0,5%
if %z:~-2,1%"=="" set z=%z:~,-2%
set /A A=0x%z%+0 > nul
if "%A%"=="0x0" goto :EOF
if "%A%"=="" goto :EOF
:: we can turn it on again now!
errorcheck on
:: now put the string at location %A% into memory
::cat --length=50 --skip=%A% (md)%SLOC%
cat --length=50 --skip=%A% (md)%SLOC% > (md)0x3000+1
:: remove line feeds, carriage returns, etc.
cat --locate=\x0a --replace=\x20 (md)0x3000+1 > nul
cat --locate=\x0d --replace=\x20 (md)0x3000+1 > nul
:: ensure end of string is marked
echo -e -n \x0 >> (md)0x3000+1
:: now display the modified string on the display
echo -n @(md)%SLOC% OFFSET=%A% ==>
cat (md)0x3000+1
:: throw a line
:: set success - found a match!
set GOTSTR=1
:: shift %3 to %2 and loop until no more left
goto :FF

Special 'command line' variables

%0 is the calling batch file name
%1 to %9 are parameters 1-9 (use shift if you have more than 9 parameters)
%* represents all parameters

call :fred mary joe
goto :eof

echo %2 is joe
goto :eof


In batch files, %0-%9 and %* will be recognised as a command line variable, therefore the following do not work as expected in a batch file:

set /a A=%B%*2 - %* means all parameters - use set /a A=%B% *2
echo %D%1 - %1 means the first parameter - use %D%%1

Another Batch file example - use checkdate.g4b to check an Expiry Date

A simple example of an expiry date test (thanks to Wonko on reboot.pro) is:

if 20131226>[email protected]:~0,[email protected]:~5,[email protected]:~8,2% pause --wait=3 THIS SOFTWARE HAS EXPIRED - XMAS 2013 IS OVER && halt

Suppose we release a bootable CD or USB drive which has software on it that should be regularly updated. We want to warn the user when it is about to expire or if it has expired. We can use a grub4dos batch file to do this and call it from a menu.lst file like this:

# Usage: /checkdate.g4b <Release Year> <Release Month> <Release DayOfMonth> <ExpiresInDays> [<SILENT>]
# Example below: Released on 2102-12-03 Expires in 30 days
/checkdate.g4b 2012 12 3 30
# Example1 without text displayed: /checkdate.g4b 2012 12 3 30 SILENT
# Example2 without text displayed: /checkdate.g4b 2012 12 3 30 > nul
if NOT "%CHECKDATE%"=="OK" reboot

This will show the following text when the grub4dos menu runs...

CheckDate: Release Date 2012-12-31 (Today is 2012-12-31)
CheckDate: This version is good for 30 days from release
CheckDate: This version expires in 29 day(s)


CheckDate: Release Date 2012-12-3 (Today is 2012-12-31)
CheckDate: This version is good for 30 days from release
CheckDate: WARNING: This is older than 30 days!

The checkdate.g4b file can be found at the bottom of this page or click here. If you add the word SILENT to the call parameters then the user will have no idea why it no longer displays a nice menu and just keeps rebooting!

Note: If you are burning this to a CD or DVD, use an 8.3 filename like chkdate.g4b as checkdate.g4b is too long a name!

If you wish to 'encrypt' your menu.lst file so that it is not just a plain text file, use 7Zip to compress the menu.lst file to GZip format (menu.lst.gz) and then rename the file to menu.lst.
grub4dos will still run the compressed menu.lst file just fine but if anyone tries to read the file using a text editor they will find it hard to understand!

Set the System Date

Using the grub4dos Function 53 we can set the Real Time Clock date. The Date.g4b grub4dos batch file can be run to set the date - this might be useful for expiry date sensitive DOS utilities that check the date of the system.

run the batchfile from your menu.lst like this

# set date of system to Jan 30th 2001
/Date.g4b 2001-01-30

# OR ...
# Prompt user to set a date

Note that this will permanently change the date of the system Real Time Clock until you set back the correct time.

grub4dos variables and setlocal/endlocal

Currently there is a maximum limit of 60 variables and each can be up to 512 bytes each.
The batch file VarsLeft.g4b will tell you how many variables remain out of the 60 allowed. It is quite easy to run out if you are not careful!
If you reset them (e.g. set A= will remove the variable A from the environment) then you will free up a 'slot for another variable'.

You can use setlocal to make a copy of the current environment (e.g. variables, root path, current filespec, etc.).
When the