How query registry key, find a string and edit it? - batch-file

May be out of line here but I stumbled on a batch script here on Stack Overflow and it was just what I wanted to do. But it is a quit old post and I can't get it to work.
Original post: Batch to query registry key, find a string within that key, then create a new key
:start
setlocal ENABLEDELAYEDEXPANSION
set qry=reg query "HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}" /s /v DriverDesc
for /f "Tokens=*" %%p in ('%qry%') do (
set var=%%p
set var=!var:^&=!
set var=!var:^)=!
set var=!var:^(=!
call :parse
)
endlocal
goto :EOF
:parse
if /i "%var:~0,5%" NEQ "HKEY_" goto parse1
set key=%var%
set key=%key:HKEY_LOCAL_MACHINE=HKLM%
goto :EOF
:parse1
setlocal ENABLEEXTENSIONS
for /f "Tokens=*" %%f in ('#echo %var%^|findstr /i /c:"Intel(R)"') do (
if defined key reg add %key% /v PnPCapabilities /t REG_DWORD /d 56 /f&set key=
)
endlocal >nul 2>&1
I executed this batch file on Windows 10 Home Edition and it has not changed anything in Windows registry although running it as administrator.
Can someone please help me to get this script to work?
Result of reg query:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0000
DriverDesc REG_SZ Microsoft Kernel Debug Network Adapter
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001
DriverDesc REG_SZ Intel(R) Ethernet Connection I217-V
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0002
DriverDesc REG_SZ Qualcomm Atheros AR946x Wireless Network Adapter
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0003
DriverDesc REG_SZ Broadcom 802.11ac Network Adapter
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0004
DriverDesc REG_SZ Bluetooth Device (RFCOMM Protocol TDI)
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0005
DriverDesc REG_SZ Microsoft Wi-Fi Direct Virtual Adapter

The batch file written by Matt M does not work because all &, ( and ) are removed from all lines before calling the subroutine parse. For that reason Intel(R) is modified already to IntelR and FINDSTR cannot find in any modified line the string Intel(R). That's why reg add is never executed by batch file posted in question.
I decided to rewrite the batch code for the task to disable power management on all Intel ® network adapters.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "DetectionCount=0"
for /F "delims=" %%I in ('%SystemRoot%\System32\reg.exe query "HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}" /s /v DriverDesc 2^>nul') do call :ProcessLine "%%I"
if not %DetectionCount% == 0 echo/ & pause
endlocal
goto :EOF
:ProcessLine
set "RegistryLine=%~1"
if "%RegistryLine:~0,5%" == "HKEY_" set "RegistryKey=%~1" & goto :EOF
for /F "tokens=2*" %%A in ("%~1") do set "AdapterDescription=%%B"
if "%AdapterDescription:Intel(R)=%" == "%AdapterDescription%" goto :EOF
echo/
%SystemRoot%\System32\reg.exe add "%RegistryKey%" /v PnPCapabilities /t REG_DWORD /d 56 /f >nul
if errorlevel 1 (
echo Failed to add double word value "PnPCapabilities" with value 56 for
) else (
echo Added successfully double word value "PnPCapabilities" with value 56 for
)
echo network adapter "%AdapterDescription%" at registry key:
echo %RegistryKey%
set /A DetectionCount+=1
goto :EOF
How was the batch file tested?
I tested the script with the posted output of registry query
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}" /s /v DriverDesc
copied into text file RegistryOutput.txt and using the FOR loop
for /F "delims=" %%I in (RegistryOutput.txt) do call :ProcessLine "%%I"
instead of the FOR loop in posted batch code processing the output of the registry query directly. The line with reg.exe add was disabled by putting echo at beginning of this line.
The output of the batch file was:
Added successfully double word value "PnPCapabilities" with value 56 for
network adapter "Intel(R) Ethernet Connection I217-V" at registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001
How does the batch file work?
The FOR command executes console application REG in a background command process with the command line:
C:\Windows\System32\cmd.exe /c C:\Windows\System32\reg.exe query "HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}" /s /v DriverDesc 2>nul
REG could output an error message to handle STDERR if it cannot find the specified registry key. This is very unlikely because this is the registry key for network adapters. However, the error message would be redirected to device NUL to suppress it using 2>nul. Please read the Microsoft article about Using Command Redirection Operators for details about input and output redirection. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character when Windows command interpreter processes the entire FOR command line before executing internal command FOR. Otherwise 2>nul would be interpreted as misplaced redirection of command FOR resulting in a syntax error message by Windows command interpreter instead of running FOR.
The output of REG written to handle STDOUT in background command process is captured by FOR and then processed line by line.
Empty lines are skipped by FOR as well as lines starting with a semicolon which does not occur here because no line ever starts with a semicolon.
All other lines would be split up into substrings (tokens) using space and horizontal tab characters as delimiters for the strings. This split behavior is not wanted here. Therefore "delims=" is used to disable line splitting and get assigned to loop variable I each non empty line.
The line with a registry key or registry value DriverDesc is passed enclosed in double quotes to subroutine ProcessLine as first and only argument. An argument string must be enclosed in double quotes if it contains 1 or more spaces or 1 or more of following characters: &()[]{}^=;!'+,`~|<>
The subroutine ProcessLine assigns first the passed line without the double quotes to environment variable RegistryLine.
A line on which the first 5 characters are case-sensitive equal to string HKEY_ is interpreted as line with a registry key assigned to environment variable RegistryKey and the subroutine is exited with goto :EOF.
Otherwise the registry line with a DriverDesc is processed as string by one more FOR loop.
The option "tokens=2*" results in splitting up the line into the three parts:
DriverDesc
REG_SZ
The string starting with first non whitespace character REG_SZ up to end of line.
The second substring (token) REG_SZ is assigned to loop variable A. This string is of no interest for this task. For that reason loop variable A is not referenced by command line executed by FOR.
The third token being the network adapter description is assigned to next loop variable after specified loop variable A according to ASCII table which is B. That is the reason why loop variables are case-sensitive while environment variables are not.
The description of the driver of the network adapter is assigned to variable AdapterDescription for further processing.
The IF condition compares the adapter description with all occurrences of Intel(R) case-insensitive replaced by an empty string and therefore removed from the description with the unmodified network adapter description. Equal strings means the network adapter description does not contain the string Intel(R) resulting in exiting the subroutine with no further processing. In other words the registry key of this network adapter is ignored by the batch file.
But the double word value PnPCapabilities is added to the registry key containing this description value with the decimal value 56 for a network adapter with Intel(R) in description most likely at beginning of the description.
All other lines of the batch file are for informing the user of the batch file if any Intel ® network adapter was detected at all and if the registry value could be successfully added to registry or if that failed, for example on not running this batch file as administrator required for write access to any key of registry hive HKEY_LOCAL_MACHINE.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
reg /?
reg add /?
reg query /?
set /?
setlocal /?
See also the Microsoft support article Testing for a Specific Error Level in Batch Files. The answer on Single line with multiple commands using Windows batch file explains operator &.

Related

Processing reg query output as a single line

I want to get some details from the Windows registry in a single line (one per key) format. But what I have tried so far gives me the details I want, but split over 2/3 lines, which makes post processing harder.
This is on Windows 10.
One option is to query the registry, so I run the following:
reg query hklm\system\currentcontrolset\enum /s /f "DeviceDesc"
This gives me output in the following format (snippet):
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum\HID\VID_1A2C&PID_2124&MI_01&Col02\7&2a45f711&0&0001
DeviceDesc REG_SZ #input.inf,%hid_device_system_control%;HID-compliant system controller
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum\HID\VID_1A2C&PID_2124&MI_01&Col02\8&9a82e8&0&0001
DeviceDesc REG_SZ #input.inf,%hid_device_system_control%;HID-compliant system controller
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum\HID\VID_2149&PID_2117&MI_00\7&1e3fba77&0&0000
DeviceDesc REG_SZ #input.inf,%hid_device_touch_screen%;HID-compliant touch screen
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum\HID\VID_2149&PID_2117&MI_01\7&316fd6b5&0&0000
DeviceDesc REG_SZ #input.inf,%hid_device_vendor_defined_range%;HID-compliant vendor-defined device
HKEY_LOCAL_MACHINE\system\currentcontrolset\enum\HID\VID_24AE&PID_2003&MI_00\8&456ad84&0&0000
DeviceDesc REG_SZ #keyboard.inf,%hid.keyboarddevice%;HID Keyboard Device
The format is:
BLANK LINE
HKEY_LOCAL.....
DeviceDesc .....
What I want is the HKEY_LOCAL... and DeviceDesc to appear on the same line of output text, so that I can use FIND/FINDSTR to get the complete info for the device I am interested in.
With the output as it stands, I cannot get the two piece of information together using DOS commands.
Is there a way to make DeviceDesc appear of the same line ?
I could write a Java/C# for this, but it seems overkill.
The command REG has no options to define the output format.
A FOR loop can be used to concatenate registry key and the device description string value for output on one line. The entire output of FOR loop can next be filtered with command FINDSTR for the device description of interest:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
(for /F "tokens=1,2*" %%A in ('%SystemRoot%\System32\reg.exe query HKLM\System\CurrentControlSet\enum /s /f "DeviceDesc"') do if /I not "%%A" == "DeviceDesc" (set "RegKey=%%A") else echo !RegKey! %%C) | %SystemRoot%\System32\findstr.exe /I /L /C:"HID-compliant touch screen"
endlocal
Please note that registry keys or description values containing one or more ! are not correct processed by this batch code because of enabled delayed environment variable expansion.
There are four spaces used to separate registry key from device description. It is of course also possible to use for example a horizontal tab.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
findstr /?
reg /?
reg query /?
set /?
setlocal /?
From what I understand, you want to combine each lines Key Path & Data. The easiest way to do this (From My knowledge) Is to grab each result of the FOR loop and use an IF statement to set the strings we will later combine.
Bellow you will find the script - In my case I just outputted the results to a document. This is fine and can be called later to with a TYPE statement inside of a FOR. However if you want to do something with these variables in the loop, just simply continue your code in-place of the ECHO [!Location! !Data!] >> Output.txt.
#ECHO OFF
#setlocal EnableDelayedExpansion
Set "RUN=0"
for /F "tokens=*" %%A in ('reg query hklm\system\currentcontrolset\enum /s /f "DeviceDesc"') DO (
Rem | Grab & organize output variables to string.
If "!RUN!"=="1" (
Rem | Second Cycle
Set "Data=%%A"
ECHO !Location! !Data! >> Output.txt
Rem | Restart Cycle
Set "Data="
Set "Location="
Set "RUN=0"
) ELSE (
Rem | First Cycle
Set "Location=%%A"
Set "RUN=1"
)
)
Goto :EOF

Multiple testing in batch file - REG QUERY

I am working on a little project to deploy client applications in my company via GPO (Citrix Receiver and HDX Real Time Engine).
HDX Client can be installed only if Citrix Receiver has been installed beforehand. I am also testing whether HDX is already installed on the machine along with its version. See what I have done so far:
setlocal enabledelayedexpansion
REM Logs Share
set logshare=\\[path_to_logs_share]\
REM Search for Citrix Receiver Client
reg query HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\Citrix\PluginPackages\XenAppSuite\ICA_Client
REM If Client has been found - search for HDX Client starting by "Citrix HDX"
if %errorlevel% EQU 0 (
reg query HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s /v Displayname ^| findstr /c:"Citrix HDX"
REM If HDX Client has been detected set a variable containing the version of it
if !errorlevel! EQU 0 (
for /F "tokens=8" %%a in ('reg query HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s /v Displayname ^| findstr /c:"Citrix HDX"') do set HDX_Version=%%a
REM If HDX version is greater or eqaul to 2.4
if %HDX_Version% GEQ 2.4 (
echo Current version is ok >> %logshare%%ComputerName%.txt
) else (
echo Installation HDX 2.4 in progress >> %logshare%%ComputerName%.txt
)
) else (
REM In case HDX has not been detected at all - installation begins
echo Installation HDX 2.4 in progress >> %logshare%%ComputerName%.txt
)
) else (
REM In case Citrix Client is missing
echo Client Citrix missing
)
Endlocal
The issue is that testing %errorlevel% twice in a batch script is apparently awkward. I do not know how to work out that problem.
The line output by reg and findstr is for example:
DisplayName REG_SZ Citrix HDX RealTime Media Engine 2.4
The version at end of this registry string value must be processed to determine if an already installed Citrix client must be updated or nothing must be done.
In general it is better to use if not errorlevel 1 instead of if %errorlevel% EQU 0 or if !errorlevel! EQU 0 because this syntax works really everywhere. if not errorlevel 1 means IF exit code of previous command/application is NOT GREATER OR EQUAL 1 or in other words is LESS THAN 1 or is EQUAL 0 because nearly no command/application exits with a negative value according to the guidelines of Microsoft. This syntax working since MS-DOS inside and outside a command block is explained by help of command IF output on running in a command prompt window if /?.
The redirection operator | must be escaped with ^ only on being used inside set of command FOR. The usage of ^| on standard command line like on on second reg query command line results in getting the vertical bar interpreted as literal character and REG outputs an error message because of too many parameters.
But the main reason for code not working as expected is the line:
if %HDX_Version% GEQ 2.4
There is set HDX_Version=%%a inside the command block starting with ( on first IF line and ending with matching ) in last but one non-empty line which defines this environment variable with string read from Windows registry. The variable reference %HDX_Version% is replaced by Windows command processor on parsing the entire command block before running the first IF. So most likely %HDX_Version% is replaced by nothing and the IF condition executed is if GEQ 2.4 which results in an exit of batch file execution because of a syntax error. It would be necessary to use here also delayed environment variable expansion, i.e. use syntax !HDX_Version! on this IF command line.
However, the code would also not work with if !HDX_Version! GEQ 2.4 because of the comparison operators EQU, NEQ, GEQ, etc. are primary designed for comparing two 32-bit signed integer values. If one of the two arguments strings left and right the operator cannot be successfully converted to a 32-bit signed integer, cmd.exe runs a string comparison and compares the integer value returned by the string comparison function against value 0 on being equal, not equal, greater than, etc. Floating point values containing . are not supported by cmd.exe at all. For more details see answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.
I suggest the following code for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogShare=\\[path_to_logs_share]\"
if not exist "%LogShare%" set "LogShare=%TEMP%\"
set "MinimumMajorVersion=2"
set "MinimumMinorVersion=4"
set "SoftwareKey=HKEY_LOCAL_MACHINE\SOFTWARE"
if not "%ProgramFiles(x86)%" == "" if not exist %SystemRoot%\Sysnative\cmd.exe set "SoftwareKey=%SoftwareKey%\Wow6432Node"
rem Search for Citrix receiver client.
%SystemRoot%\System32\reg.exe query %SoftwareKey%\Citrix\PluginPackages\XenAppSuite\ICA_Client >nul 2>nul
if errorlevel 1 (
echo Citrix client is not installed.>>"%LogShare%%ComputerName%.txt"
goto InstallClient
)
rem Search for HDX client starting by "Citrix HDX" if receiver client was found.
for /F "tokens=8" %%I in ('%SystemRoot%\System32\reg.exe query %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall /s 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX"') do set "HDX_Version=%%I" & goto EvaluateVersion
echo HDX version not found under registry key %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall.>>"%LogShare%%ComputerName%.txt"
goto InstallClient
:EvaluateVersion
for /F delims^=.0123456789^ eol^= %%I in ("%HDX_Version%") do (
echo Determined HDX version string "%HDX_Version%" is of unknown format.>>"%LogShare%%ComputerName%_Error.txt"
goto EndCitrixCheck
)
for /F "tokens=1,2 delims=." %%I in ("%HDX_Version%") do (
if %%I LSS %MinimumMajorVersion% (
echo Determined HDX version %HDX_Version% is too low.>>"%LogShare%%ComputerName%.txt"
goto InstallClient
)
if %%I EQU %MinimumMajorVersion% (
if "%%J" == "" (
if not %MinimumMinorVersion% == 0 (
echo Determined HDX version %HDX_Version% has no minor version number.>>"%LogShare%%ComputerName%.txt"
goto InstallClient
)
) else if %%J LSS %MinimumMinorVersion% (
echo Determined HDX version %HDX_Version% is too low.>>"%LogShare%%ComputerName%.txt"
goto InstallClient
)
)
echo Determined HDX version %HDX_Version% is okay.>>"%LogShare%%ComputerName%.txt"
goto EndCitrixCheck
)
echo Determined HDX version string "%HDX_Version%" is of unknown format.>>"%LogShare%%ComputerName%_Error.txt"
goto EndCitrixCheck
:InstallClient
echo Installation of HDX in progress ...>>"%LogShare%%ComputerName%.txt"
rem Add here the command lines to install the Citrix client.
:EndCitrixCheck
if "%TEMP%\" == "%LogShare%" del "%LogShare%%ComputerName%.txt"
endlocal
The first and last IF condition in this code are just for making it possible for everyone reading this code to run it without an error message.
This batch code works even on Windows XP although this is most likely not a requirement for this task.
The Windows x86 on Windows x64 emulation must be taken into account on accessing registry keys under HKEY_LOCAL_MACHINE\SOFTWARE according to the Microsoft articles:
WOW64 Implementation Details
File System Redirector
Registry Keys Affected by WOW64
The environment variable SoftwareKey is defined first with standard registry key HKEY_LOCAL_MACHINE\SOFTWARE. This is the right key for 32-bit Windows and batch file being executed in 32-bit environment by the x86 versions of cmd.exe and reg.exe executed from %SystemRoot%\SysWOW64. But it is necessary to append \Wow6432Node to access the right key on batch file being executed by x64 version of cmd.exe starting x64 version of reg.exe stored both in %SystemRoot%\System32 on 64-bit Windows.
The rewritten code avoids definition/modification of an environment variable in a command block referenced in same command block. Therefore delayed environment variable expansion is not needed by this code which solves first main problem.
Let us look on the long command line:
for /F "tokens=8" %%I in ('%SystemRoot%\System32\reg.exe query %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall /s 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX"') do set "HDX_Version=%%I" & goto EvaluateVersion
FOR executes in a separate command process started with cmd.exe /C and the string in the round brackets between the two ' in background for example the command line:
C:\Windows\System32\reg.exe query HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s 2>nul | C:\Windows\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX"
REG outputs everything of uninstall registry key for x86 applications to handle STDOUT. An error message output to handle STDERR would be redirected with 2>nul to device NUL to suppress it. REG should not output an error message in this case. It is possible to use additionally /v DisplayName in addition to /s on Windows Vista and later Windows versions to get output by REG just all values with name DisplayName. The output of REG is redirected with | to handle STDIN of command FINDSTR.
FINDSTR searches in every line case-insensitive with a regular expression for a string starting anywhere in line with DisplayName, having 0 or more characters and the string Citrix HDX. The usage of /R /C:"DisplayName.*Citrix HDX" instead of just "DisplayName.*Citrix HDX" is necessary as otherwise FINDSTR would run a regular expression find searching for DisplayName and 0 or more characters and the string Citrix OR the string HDX anywhere in a line which is not wanted here. FINDSTR outputs hopefully always just the line with the string value of interest to handle STDOUT of separate command process.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with reg and findstr with using a separate command process started in background.
FOR captures the output written to STDOUT of started command process and processes it line by line with ignoring empty lines and by default also lines starting with a semicolon which both do not occur here. Other lines are split up into substrings (tokens) using normal space and horizontal tab as delimiters and assigns just eight space/tab delimited substring to specified loop variable I because of option tokens=8. FOR runs never the command SET if there is no line with at least eight space/tab separated strings. The string assigned to loop variable I is assigned as is to environment variable HDX_Version and the batch file execution continues on the line below label EvaluateVersion.
The second FOR validates if the string assigned to HDX_Version consists of only one or more dots/digits. FOR outputs an error message to an error file instead of standard text file in case of the string assigned to HDX_Version contains any other character than .0123456789 including a ; at beginning of the string. The execution of the batch file continues at end of batch file as this error condition cannot be handled automatically. It could be that the displayed string changed since writing this batch file which should be at least detected and reported by the batch file.
Otherwise on HDX version being most likely of format major.minor one more FOR is used to split up the version into two strings which are integers for evaluation with the integer comparators of command IF. The minor version number must not exist except the major version number is equal the minimum major version number. The missing minimum minor version number is in this case interpreted as 0 and so an installation/update of Citrix client is necessary, too.
It is very unlikely, but nevertheless possible that the string assigned to environment variable HDX_Version consist of only one or more . in which case the third FOR does not execute any command line in command block. This results also in writing an error message into the error file and a jump to end of batch file.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
goto /?
if /?
reg /?
reg query /?
rem /?
set /?
setlocal /?

remove only specific data from registry value REG_MULTI_SZ via batch file/command line

All;
I've been all around the Internet throughout the day, trying to get a batch file written/working.
Just to start off - I am looking to make this work ONLY via a batch file and/or command line.
I'm looking to remove a specific data (not case-sensitive - as in the data could be 'data' or 'Data' or 'DATA').
Most of the OS's that I've seen the actual data to be on are Win XP machines. The specific's are as follows:
I'm looking to specifically remove the data "browser" (again, it could also be "Browser" or "BROWSER) from a REG_MULTI_SZ registry value, which the subkey is found at:
HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
The actual value is:
NullSessionPipes
I've always seen multiple pieces of data within this value (with "browser" being somewhere in the mix). Whether browser is the only piece of data in the value, or multiple pieces of data, I need to be able to execute a .bat in order to remove this.
My research points me to querying the data, removing the "browser" data, then re-inserting the remaining - I'm just not able to successfully do this.
I've attempted to just create a dummy Test key/value on my machine (Win10) at the following:
HKCU\Temp\Test
which contains the data of:
Test #1
Test #2
browser
Browser
BROWSER
Test #3
Test #4
Everything I've done, I've been unable to remove only/any form of browser from this data, leaving the rest of the "Test #x" data's.
Please advise on any solution(s) that anyone can come up with.
UPDATE
Here is the code(s) that I've been able to put together throughout my research on this (I have put together several different batch files, without positive results):
(NOTE: I in no way take credit for any of this code, as the majority of it has been compiled from/across many different locations):
Test1.bat
This test kept deleting the entire value, which I could not figure out.
#echo off
for /f "tokens=*" %%a in ('
reg query "HKCU\Temp" /v "Test" /f "browser\0Browser\0BROWSER" /d /e
^| find "REG_MULTI_SZ"
') do (
setlocal enableDelayedExpansion
rem Split
set "line=%%a"
set "value=!line:*REG_MULTI_SZ=REG_MULTI_SZ!"
call set "name=%%line:!value!=%%"
rem Trim spaces
for /L %%b in (1,1,10) do if "!name:~-1!"==" " set "name=!name:~0,-1!"
echo Deleting !name!
reg delete "HKCU\Temp" /v "!name!" /f
endlocal
)
pause
Test2.bat
This was an attempt to export the data into a txt file, then remove "browser" - another failed attempt.
#echo off
reg query HKCU\Temp /v Test > c:\Temp\tmp01.txt
FOR /F "tokens=2,3*" %%a in (c:\Temp\tmp01.txt) do call :sub1 %%b
:sub1
if %1x==browser goto end
echo %1
REG ADD HKCU\Temp /f /v Test /t REG_MULTI_SZ /d %1\0\0\0
:end
goto :eof
Test3.bat
This attempt ended up replacing all data with "%b" for my 'Test' value
#echo off & setlocal ENABLEEXTENSIONS
set k="HKCU\Temp"
set v="Test"
for /f "tokens=*" %%a in ('reg query %k% /v %v%') do (
set "d=%%b"
)
set "d=%d:browser\0=%"
set "d=%d:\0\0=%"
reg add %k% /v %v% /t REG_MULTI_SZ /d "%d%" /f
I did come across some topics where users had stated that if the data was translated to HEX/binary, that this would be easier done?
I hope this helps to give some idea to someone as to what exactly I'm doing wrong here.
As long as none of the lines inside the multi string content are doublequoted, here's how I'd probably write it:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "_k=HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters"
Set "_v=NullSessionPipes"
Set "_s=Browser"
Set "_d="
For /F "EOL=H Tokens=2*" %%A In ('Reg Query "%_k%" /V "%_v%"'
) Do If "%%A"=="REG_MULTI_SZ" Set "_d=%%B"
If "%_d%"=="" Exit /B
Set "_d=%_d:\0\0=%"
Set "_m="
For %%A In ("%_d:\0=","%"
) Do Echo %%A|Find /I "%_s%">Nul||Call Set "_m=%%_m%%%%A\0"
If "%_m%"=="" Exit /B
Reg Add "%_k%" /V "%_v%" /T "REG_MULTI_SZ" /D %_m:~,-2% /F>Nul
Please note that this uses Find, (line 15), to match any line containing Browser, (case insensitive), if you're wanting to match lines containing only the string Browser, (case insensitive), then you may wish to take a look at the FindStr command instead, (enter FindStr /? at the Command Prompt for usage information)
There's one major caveat: the value data for a multi string registry entry can be very long indeed, if you're sure that the string data to be written back to the registry will not exceed maximum character length then you'll be okay. If not I'm afraid I cannot think of any other simple way to perform the task. (writing the data as hex into a registry file, *.reg and import/merging it).
Here is a commented batch file for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=2 tokens=1,2*" %%A in ('%SystemRoot%\System32\reg.exe query HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters /v NullSessionPipes 2^>nul') do if /I "%%A" == "NullSessionPipes" if "%%B" == "REG_MULTI_SZ" set "NullSessionPipes=%%C" & goto ProcessValue
echo Registry value NullSessionPipes was not found in registry.
goto EndBatch
rem The goal is to remove all ENTIRE strings BROWSER written in any case.
rem Other strings containing by chance also BROWSER at beginning or end
rem of the string should not be removed from multi-string value. For that
rem reason run case-insensitive string substitution with \0browser\0 to
rem really match entire BROWSER string. But there can be multiple BROWSER
rem strings in sequence which are not all removed with one run on using
rem \0browser\0 and so a loop is required make the string substitution
rem with \0browser\0 until this string is not removed anymore from value.
rem But BROWSER could be exist also as first string in value with no
rem preceding \0. For that reason \0 is extra added at beginning and
rem then removed after removing all entire BROWSER strings.
rem REG ADD requires that there is no \0\0 at end of multi-string value
rem to successfully add the multi-string value to Windows registry. The
rem data must end with last character of last string or with just \0.
rem For that reason the last two characters being \0 on Windows XP and
rem Windows Server 2003 are removed before even starting processing the
rem multi-string value. REG of Windows Vista and later Windows versions
rem does not output multi-string value with \0\0 at end like REG of
rem Windows XP. It outputs the multi-string with no \0 at end. So it
rem is necessary to append \0 at end in case of last string is BROWSER.
rem It is also necessary to do nothing if the NullSessionPipes value exists
rem with no string resulting on Windows Vista and later Windows version in
rem nothing assigned to NullSessionPipes and so the environment variable
rem does not exit at all. On Windows XP is assigned in this case just \0
rem which on further processing results also in an empty string and
rem therefore deletion of environment variable NullSessionPipes after
rem removing this final end of multi-string marker.
rem On Windows Vista and later Windows versions it is also necessary to
rem append \0 at end of environment variable string as otherwise with an
rem existing string ending by chance with a backslash this backslash would
rem be interpreted by REG as escape character for the double quote used to
rem enclose the data argument string on command line in double quotes on
rem adding the final multi-line string value. So without appending \0 at
rem end string like TEST\ as last string of NullSessionPipes value would
rem become TEST" which of course is not wanted avoided by using TEST\\0
rem at end of environment variable string for this use case.
rem After removing all entire BROWSER strings from value it is checked
rem if the new value is not identical to value read from registry which
rem means at least one BROWSER string was really removed and so it is
rem necessary to write new value without BROWSER back to Windows registry.
:ProcessValue
if "%NullSessionPipes%" == "" goto EndBatch
if "%NullSessionPipes:~-2%" == "\0" set "NullSessionPipes=%NullSessionPipes:~0,-2%"
if "%NullSessionPipes%" == "" goto EndBatch
if not "%NullSessionPipes:~-2%" == "\0" set "NullSessionPipes=%NullSessionPipes%\0"
set "NewSessionPipes=\0%NullSessionPipes%"
:RemoveBrowser
set "TmpSessionPipes=%NewSessionPipes:\0browser\0=\0%"
if not "%TmpSessionPipes%" == "%NewSessionPipes%" set "NewSessionPipes=%TmpSessionPipes%" & goto RemoveBrowser
set "NewSessionPipes=%TmpSessionPipes:~2%"
if "%NewSessionPipes%" == "%NullSessionPipes%" echo Current NullSessionPipes value does not contain the string BROWSER.& goto EndBatch
echo Current NullSessionPipes value is:
echo/
echo %NullSessionPipes%
echo/
echo New NullSessionPipes value is:
echo/
echo %NewSessionPipes%
echo/
%SystemRoot%\System32\reg.exe add HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters /v NullSessionPipes /t REG_MULTI_SZ /d "%NewSessionPipes%"
:EndBatch
endlocal
The output of the command line
C:\Windows\System32\reg.exe query HKLM\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters /v NullSessionPipes 2>nul
executed by FOR in a separate command process started with cmd /C in background depends on version of REG.
On Windows Vista and Windows Server 2008 and all later Windows versions the output starts with an empty line, second line is the registry key, and third line contains registry value name, value type and the value data separated by spaces.
On Windows XP and Windows Server 2003 the output starts with an empty line, next version of REG, one more empty line, fourth line contains registry key and fifth line finally contains registry value name, value type and the value data with four indent spaces and separated by a horizontal tab character.
So from different output of REG it is possible only to skip the first two lines. The next line contains the data of interest on Windows Vista/Server 2008 and all later versions of Windows. But on Windows XP and Server 2003 it is necessary to process more lines from captured REG output until fifth line is reached with the data of interest. For that reason the two additional IF conditions are used to be 100% sure that the multi-string value of registry value NullSessionPipes is really assigned to environment variable NullSessionPipes before exiting the loop and processing the value.
Output of REG on Windows XP with NullSessionPipes existing but not containing any string:
 
! REG.EXE VERSION 3.0
 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
····NullSessionPipes» REG_MULTI_SZ» \0
· in output example above and all others below represents an indenting/separating space character. » represents a separating horizontal tab character.
Output of REG on Windows XP with NullSessionPipes existing but not containing any string:
 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
····NullSessionPipes····REG_MULTI_SZ····
Example output of REG on Windows XP with NullSessionPipes containing strings:
 
! REG.EXE VERSION 3.0
 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
····NullSessionPipes» REG_MULTI_SZ» browser\0test #1\0BROWSER\0Browser\0Test\#2\0TEST\\0browser\0\0
Example output of REG on Windows 7 with NullSessionPipes containing strings:
 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
····NullSessionPipes····REG_MULTI_SZ····browser\0test #1\0BROWSER\0Browser\0Test\#2\0TEST\\0browser
For the example with multiple strings the data string to add on command line is: "test #1\0Test\#2\0TEST\\0"
The command line with REG to add modified value to registry does not contain option /f to force an overwrite. That gives you the possibility to check new value before really writing it to registry. Insert parameter /f left to /d if there should be no prompt to overwrite existing value once you verified that the batch file works as expected by you.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
goto /?
if /?
reg /?
reg add /?
reg query /?
set /?
setlocal /?
See also Single line with multiple commands using Windows batch file for an explanation of operator &.

Versioning up existing files using batch

#echo off
:prep
cls
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)
:for /l %A in (1,1,100) do copy "C:\some folder\file.ext" "C:\some folder\file-%%A.ext"
set choice=
:: test to see if directory exists
if EXIST "../delivery_%mydate%.txt" (
goto overwrite
) else (
goto start
)
:overwrite
echo.
echo delivery note already exists - continue?
set /p choice='y / n ?'
if '%choice%'=='' ECHO "%choice%" is not valid please try again
if '%choice%'=='y' goto start
if '%choice%'=='n' goto end
echo.
:start
echo.
for /l %A in (1,1,100) do copy "C:\some folder\delivery_%mydate%.ext" "C:\some folder\delivery_%mydate%.ext"
echo Choose the following:
echo 1. Directories
echo 2. Files
echo 3. quit
echo.
set /p choice=
if '%choice%'=='1' goto directory
if '%choice%'=='2' goto file
if '%choice%'=='3' goto end
cls
ECHO "%choice%" is not valid please try again
goto start
:directory
dir /ad /on /b > ../delivery_%mydate%.txt
echo.
goto checksuccess
:file
dir /a-d /on /b > ../delivery_%mydate%.txt
echo.
goto checksuccess
:checksuccess
I need to add a line of code to this batch file I have created above. I need this code to save an existing file to a higher version without deleting the previous one. This will also need to be embedded into the code I created. For example it will start saving them like: filev001, filev002, etc.
1. Some general advice for writing batch files
A list of commands is output on executing in a command prompt window help. It is advisable to use in batch files for environment variables and labels not a string which is also a command. It is possible, but not advisable.
start is a command to start an application in a separate process. So it is better to use for example Begin instead of start as label.
choice is a command for a choice which is better for single character choices than using set /P. So it is better to use for example UserChoice instead of just choice as environment variable name.
It is better to use echo/ instead echo. to output an empty line. The reason is explained by DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/.
Environment variable names and labels are easier to read on using CamelCase and can be more easily searched case-sensitive and if necessary replaced in a batch file than a name/label which can exist as word also in comments and in strings output with echo.
The answer on question Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains in detail why the usage of the syntax set "Variable=string value" is recommended in batch files on assigning a string to an environment variable.
The directory separator on Windows is the backslash character \. The slash character / is the directory separator on Unix/Linux/Mac. On Windows / is used for options/parameters. The Windows kernel functions support also directory and file paths with / as directory separator by automatically correcting them to \ internally in path. But it is nevertheless recommended to use in a batch file \ in paths.
rem is the command for a comment in a batch file. :: is an invalid label and not really a comment. Lines with a label at begin are ignored for command execution. But a label cannot be used in a command block. For that reason it is recommended to use command rem because :: in a command block results often in unexpected behavior on execution of the batch file.
2. Get current date in a specific format
Let us look on the command line:
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)
date /t is a command which for executes in a background command process with the command line cmd.exe /C date /t for capturing the output of this command process written to standard output handle STDOUT and process the captured output line by line.
Can this be optimized?
Yes, because on running in a command prompt window set /? and reading the output help from first to last page it can be read that there is the environment variable DATE which expands to current date. So there is no need to run the command date to get current date as string.
The command date with option /t outputs the current date in the format defined for the used user account in Windows Region and Language settings. In your case it looks like the region dependent date format is MM/dd/yyyy with the weekday abbreviation at beginning (with no comma) before the date. The date format on my computer is just dd.MM.yyyy without weekday. The environment variable DATE is in same region dependent format as output of command date /t.
So the region dependent date in format ddd, MM/dd/yyyy could be also modified to yyyy-MM-dd using the command line:
for /F "tokens=2-4 delims=/, " %%a in ("%DATE%") do set "MyDate=%%c-%%a-%%b"
It is also possible to use string substitution:
set "MyDate=%DATE:~-4%-%DATE:~-10,2%-%DATE:~-7,2%"
String substitution is also explained by help output on running set /? and read the answer on
What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean?
But if yyyy-MM-dd is the wanted date format for current date independent on region settings of the used user account is advisable to use the command lines
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "MyDate=%%I"
set "MyDate=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%"
This region independent solution is really much slower than the above command lines. It is explained in detail by the answer on Why does %date% produce a different result in batch file executed as scheduled task? But it has the big advantage of being region independent.
3. Prompting user for a single character choice
The usage of set /P variable=prompt is not recommended for a single character choice because
the user can just hit RETURN or ENTER without entering anything at all resulting in variable keeping its current value or still not being defined if not defined before set /P command line;
the user can make a typing mistake and presses for example Shift+2 instead of just 2 resulting (on German keyboard) to enter " as string which most batch files using set /P breaks because of a syntax error on next command line evaluating the user input;
the user can enter anything instead of one of the characters asked for including strings which on next command line results in deletion of files and folders.
The solution is using the command choice if that is possible (depends on Windows version). choice waits for the key press of a character specified in the command options and immediately continues after one of these keys is pressed. And choice exits with the index of the pressed character in list as specified in batch file. This exit code is assigned to ERRORLEVEL which can be evaluated next also within a command block without using delayed expansion or used directly in a single goto instruction.
4. Rewritten batch file
Here is the rewritten batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem set "Folder=C:\some folder"
set "Folder=F:\Temp\Test"
:Prepare
cls
rem Get current date region independent in format yyyy-MM-dd.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "MyDate=%%I"
set "MyDate=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%"
set "FileNumber=0"
for %%I in ("%Folder%\file-*.ext") do call :GetFileNumber "%%~nI"
goto IncrementNumber
rem Subroutine to find out highest file number without using delayed
rem environment variable expansion for number range 0 to 2147483647.
rem Numbers starting with 0 are interpreted as octal number in number
rem comparison which makes it necessary to remove leading 0 from the
rem number string get from file name starting with 5 characters.
:GetFileNumber
set "Number=%~1"
set "Number=%Number:~5%
:RemoveLeadingZero
if "%Number%" == "" goto :EOF
if "%Number:~0,1%" == "0" set "Number=%Number:~1%" & goto RemoveLeadingZero
if %Number% GTR %FileNumber% set "FileNumber=%Number%"
goto :EOF
rem Make sure the file number has at least 3 digits.
:IncrementNumber
set /A FileNumber+=1
if %FileNumber% GEQ 100 goto ExistDelivery
set "FileNumber=00%FileNumber%"
set "FileNumber=%FileNumber:~-3%"
rem Test to see if file exists already.
:ExistDelivery
if not exist "..\delivery_%MyDate%.txt" goto Begin
echo/
%SystemRoot%\System32\choice.exe /C YN /N /M "Delivery note already exists, continue (Y/N)? "
if errorlevel 2 goto :EOF
:Begin
set "FileName=file-%FileNumber%.ext"
copy "%Folder%\file.ext" "%Folder%\%FileName%" >nul
echo/
echo Choose the following:
echo/
echo 1. Directories
echo 2. Files
echo 3. Quit
echo/
%SystemRoot%\System32\choice.exe /C 123 /N /M "Your choice? "
if errorlevel 3 goto :EOF
if errorlevel 2 goto GetFileList
dir * /AD /ON /B >"..\delivery_%MyDate%.txt"
echo/
goto CheckSuccess
:GetFileList
dir * /A-D /ON /B >"..\delivery_%MyDate%.txt"
echo/
:CheckSuccess
rem More commands.
endlocal
It was not really clear for me what the entire batch code is for at all.
It would have been also easier to write the determination of highest number in a file name on knowing the possible number range like 001 to 100. So I wrote a general solution for 001, 002, ..., 099, 100, 101, ..., 1000, ..., 2147483647.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
cls /?
copy /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
See also answer on Single line with multiple commands using Windows batch file for an explanation of & operator and read the Microsoft article about Using command redirection operators.

Batch file log function for printing command output to both log file and screen

I found there are some topics similar to this problem but not exactly what I want, so I raise this topic.
I want to create a log function for printing message to both formatted log file and console output. The function is as below:
:LOGDEBUG
#echo DEBUG: %~1
if NOT EXIST %LOG_FILE% exit /b 1
#echo [%date - %time%] DEBUG: %~1 >> %LOG_FILE% 2>&1
exit /b 0
And I try to use it for printing the command execution output and if the output contains special character like "<" and ">", this function doesn't work well and prompt "The system cannot find the file specified". My code for executing a command is below:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
CALL :LOGDEBUG "%%a"
)
However, when I use "echo" command directly instead of the log function, the output can be printed correctly on the console. Like the following code:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
echo %%a
)
May I know what is the problem, and how can I print the output correctly by using the log function? Thanks
You have answered your question by own: when I use "echo" command directly...
#ECHO OFF
SETLOCAL EnableExtensions
set "LOG_FILE=D:\tempx\program.log" my testing value
rem type NUL>"%LOG_FILE%"
for /f "usebackq delims=" %%a in (`dir d:\temp 2^>NUL`) do (
CALL :LOGDEBUG "%%a"
)
rem type "%LOG_FILE%"
ENDLOCAL
exit /b
:LOGDEBUG
FOR %%A in ("%~1") do (
#echo DEBUG: %%~A
if NOT EXIST "%LOG_FILE%" exit /b 1
#echo [%date% - %time%] DEBUG: %%~A >> "%LOG_FILE%" 2>&1
)
exit /b 0
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~A etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
Here is the batch code which should work.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do call :LOGDEBUG "%%a"
endlocal
goto :EOF
:LOGDEBUG
set "StringToOutput=%~1"
echo DEBUG: !StringToOutput!
echo [%DATE% - %TIME%] DEBUG: !StringToOutput!>>"%LOG_FILE%"
goto :EOF
First delayed environment variable expansion is enabled and a copy of existing environment table is made. It is explained below why this is done.
Next the name of the log file with full path is assigned to an environment variable in local variable table. This path can be with or without 1 or more spaces in path. The log file is deleted in case of existing already from a previous run. This code can be removed if you want to append new lines to already existing file. But you should add in this case code to avoid that the log file permanently increases until no free storage space anymore.
The FOR command executes the command DIR and processes each line of the output of DIR written to stdout. Blank lines are skipped. The default delimiters are space, tab and newline characters. As wanted here are the entire lines of DIR, the default delimiter list is replaced by nothing which means only newline characters remain and loop variable %a gets assigned always an entire non blank line.
The output of command DIR contains < and > which are interpreted as redirection operators if found by command processor within a line not quoted. Therefore the line for DIR output is passed quoted to subroutine LOGDEBUG. Which characters must be usually quoted are listed on last help page printed into a command prompt window when executing cmd /? in a command prompt window.
When the loop has finished, the local environment table is deleted which means LOG_FILE and StringToOutput are also removed, and previous environment is restored which usually means the delayed expansion is turned off again before batch execution exits with a jump to predefined label to end of file.
The subroutine LOGDEBUG first assigns the passed string to an environment variable without surrounding quotes just needed because of special characters in line like < and >.
Next the line is written to console window without quotes using delayed expansion as otherwise < and > would be interpreted as redirecting operators and not literally.
The same line is written also to the log file with the difference of date and time inserted at beginning of line. You missed the percent sign after date in your code. Again delayed expansion is used to get the line with the characters < and > written to file without being interpreted as redirection operators.
Important is also that there is no space before >> as otherwise each line in log file would have a trailing space. 2>&1 is useless here as command echo does not write something to stderr.
The subroutine is exited with a jump to end of file resulting in command FOR processes next line.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
dir /?
for /?
goto /?
set /?
It would be of course possible to do all the output directly in body of command FOR without using a subroutine.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do (
echo DEBUG: %%a
echo [!DATE! - !TIME!] DEBUG: %%a>>"%LOG_FILE%"
)
endlocal
Delayed variable expansion is nevertheless required here as otherwise %DATE% and %TIME% would be expanded by command processor like %LOG_FILE% already on parsing entire block defined by ( and ) before command FOR is executed at all which would result in same date and time written for all lines to the log file.

Resources