<http://www.netikka.net/tsneti/info/tscmd300.php>
Copyright © 2003- by Prof. Timo Salmi  
Last modified Fri 11-Aug-2017 14:20:15
Welcoming the user from 54.224.13.210
On Tue 17-Oct-2017 01:07:26 server time

 
Assorted NT/2000/XP/.. CMD.EXE Script Tricks
From the html version of the tscmd.zip 1cmdfaq.txt file
To the Description and the Index
 

This page is edited from the 1cmdfaq.txt faq-file contained in my tscmd.zip command line interface (CLI) collection. That zipped file has much additional material, including a number of detached .cmd script files. It is recommended that you also get the zipped version as a companion.

Please see "The Description and the Index page" for the conditions of usage and other such information.



300} A Miscellaneous Collection of Reusable Command-line Programming Modules

This one is a somewhat different item. It does not address a single question but its theme is routine reusability for command-line programming. The item also differs from the rest of the items in this FAQ collection in the sense that all the modules are for Windows 7, (and probably also beyond), even if they mostly are backwards compatible. Many of the modules have been covered elsewhere on this FAQ collection in connection with specific questions.

The modules in this item:
AddLeadingZeros  AskQuestionWithNdefault  AskQuestionWithYdefault  AssignTemp  CheckDriveExistence  CheckExifExistence  CheckExistence  CheckExistenceAtPath  CheckLock  CommonHelpText  ConvertFoldToM  CopyFoldToM  CurrentScript  DetabFile  FilesCount  FinMonth  FinWeekday  FuncRightJustify  GetDateModifiedInUnxtouchFormat  GetDateThen  GetLatest  GetRidOfThumbs  IbmStr2Latin1  Ibm2Latin1  IsFolderFn  IsSwitch  IsWild  Latin1ToIbm  ProgramHelp  ProgramTitle  PurgeOneSet  RemoveLeadingZeros  RemoveTrailingSpaces  ShowOneExif  ShowVarValue  SmallDelay  StrToLower  TestForInteger  ThunderbirdWarning  TimeDiff  Trim  WeekdayNumberNow 

In some of the modules third party UNIX-like PC tools are assumed to be available:
  (unx)gawk.exe   A pattern scanning and processing language
  (unx)less.exe   A pager like MORE but with better controls
  (unx)sed.exe   Stream editor for filtering and transforming text
  (unx)touch.exe   Change file timestamps
  (unx)tr.exe   Translate, squeeze, and/or delete characters

:ProgramTitle
echo +---------------------------------------------------------+
echo ^ MYCMD.CMD Timo's command-line commands collection       ^
echo ^ Prof. (emer.) Timo Salmi, Last modified Tue 10-Mar-2015 ^
echo +---------------------------------------------------------+
goto :EOF

:ProgramHelp
echo The help is not ready yet
goto :EOF

An example of a frame and calling:
@echo off & setlocal enableextensions
rem enabledelayedexpansion
:
if "%~1"=="/?" (call :ProgramTitle & echo. & call :ProgramHelp & goto _out)
:
rem My special ending (See #Item002)
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

:AskQuestionWithNdefault
  setlocal enableextensions
  :_askthenquestionagain
  set return_=
  set ask_=
  set /p ask_="%~1"
  if "%ask_%"=="" set return_=n
  if /i "%ask_%"=="n" set return_=n
  if /i "%ask_%"=="y" set return_=y
  if not defined return_ goto _askthenquestionagain
endlocal & set "%2=%return_%" & goto :EOF

:AskQuestionWithYdefault
  setlocal enableextensions
  :_asktheyquestionagain
  set return_=
  set ask_=
  set /p ask_="%~1"
  if "%ask_%"=="" set return_=y
  if /i "%ask_%"=="y" set return_=y
  if /i "%ask_%"=="n" set return_=n
  if not defined return_ goto _asktheyquestionagain
endlocal & set "%2=%return_%" & goto :EOF

An example of calling:
:
call :AskQuestionWithYdefault "Doit [Y,n]?" reply_
if /i not "%reply_%"=="y" (... whatever ...)
:

rem If defined assign my own temporary folder for the script
:AssignTemp
setlocal
set return_=%temp%
if defined mytemp if exist "%mytemp%\" set return_=%mytemp%
endlocal & set "%1=%return_%" & goto :EOF

:: Assign a value for the temporary folder variable temp_
call :AssignTemp temp_

:: Check the existence of a file
:CheckExistence
setlocal enableextensions
set file_=%~2
if exist "%file_%" (endlocal & set "%3=true" & goto :EOF)
echo %~1 "%file_%" not found^G
endlocal & set "%3=" & goto :EOF

set wzzip_=C:\Program Files\WinZip\WZZIP.EXE
set wzunzip_=C:\Program Files\WinZip\WZUNZIP.EXE
if defined ProgramW6432 set wzzip_=C:\Program Files (x86)\WinZip\WZZIP.EXE
if defined ProgramW6432 set wzunzip_=C:\Program Files (x86)\WinZip\WZUNZIP.EXE
call :CheckExistence "Program" "%wzzip_%" found_
if not defined found_ goto _out
call :CheckExistence "Program" "%wzunzip_%" found_
if not defined found_ goto _out

:CheckExistenceAtPath
setlocal enableextensions
set file_=%2
set found_=""
for %%f in (%file_%) do set found_="%%~$PATH:f"
if exist %file_% set found_=%file_%
if /i not %found_%=="" (endlocal & set "%3=true" & goto :EOF)
echo.
echo %~1 %file_% not found at path or in the current folder^G
endlocal & set "%3=" & goto :EOF

:: Is the UnxUtils GnuWin32 Gawk for Windows program available by default
set unxsed_=unxsed.exe
call :CheckExistenceAtPath Program "%unxsed_%" found_
if not defined found_ goto _out

:CheckDriveExistence
setlocal
set ready=true
dir "%~1" 2>&1 | find "The device is not ready" > nul
if %errorlevel% EQU 0 set ready=
dir "%~1" 2>&1 | find "Invalid drive specification" > nul
if %errorlevel% EQU 0 set ready=
dir "%~1" 2>&1 | find "The system cannot find the" > nul
if %errorlevel% EQU 0 set ready=
endlocal & set "%2=%ready%" & goto :EOF

call :CheckDriveExistence "F:" DriveExist
if not defined DriveExist (echo Drive F: is not available&goto :EOF)

:IsFolderFn
setlocal
set return_=
:: First the potential case of the root requires special treatment
if /i "%~d1"=="%~1" if exist "%~d1\" (
  set return_=true& goto _ExitIsFolderFn)
if /i "%~d1\"=="%~1" if exist "%~d1" (
  set return_=true& goto _ExitIsFolderFn)
dir /a:d "%~1" 2>&1|find "<DIR>">nul
if %errorlevel% EQU 0 set return_=true
:_ExitIsFolderFn
endlocal & set "%2=%return_%" & goto :EOF

call :IsFolderFn "%sourcefile_%" isfolder_
if defined isfolder_ (
  echo Note: "%~1" is a folder, not a file
  goto :EOF)

:: For debugging, show verbally the value of an environment variable
:ShowVarValue [TheNameOfTheVariable]
setlocal
set par1_=%~1
call set value_=%%%par1_%%%
echo The value of %~1 is %value_%
endlocal & goto :EOF

call :ShowVarValue temp
Might produce e.g.
The value of temp is C:\Users\ts\AppData\Local\Temp

:CommonHelpText
setlocal
set less_=C:\_F\FTOOLS\unxless.exe
if not exist "%less_%" (
  echo Exiting: Pager %less_% not found^G
  goto _eofCommonHelpText)
set helptext_=%~1
if not exist "%helptext_%" (
  echo Exiting: File %helptext_% not found^G
  goto _eofCommonHelpText)
"%less_%" -i -S "%helptext_%"
:_eofCommonHelpText
endlocal & goto :EOF

call :AskQuestionWithNdefault "Display related programs' common help [y/N]?" reply_
if "%reply_%"=="y" (call :CommonHelpText "C:\_F\XTOOLS\TODAYZIP.TXT" & goto _out)

:CheckLock
setlocal
if exist "%~1" (
  call :ProgramTitle
  echo.
  echo An instance of the current script already is running^G
  echo If this is in error delete the lockfile
  echo "%~1"
  if not defined cmdbox if defined PauseIfFromDesktop pause
  endlocal & set "%2=true" & goto :EOF)
echo Lockfile "%~1">"%~1"
endlocal & set "%2=" & goto :EOF

:
call :AssignTemp temp_
set lockfile_=%temp_%\%~nx0_lockfile.tmp
:: Do not allow running simultaneous instances of this script
call :CheckLock "%lockfile_%" locked_
if defined locked_ (
  if not defined cmdbox if defined PauseIfFromDesktop pause
  goto :EOF)
:
... whatever ...
:
:_out
for %%f in ("%lockfile_%") do if exist %%f del %%f
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

Getting the current date and time, which is the top FAQ #Item001 with many alternative solutions. Here the following will suffice, where DATET.CMD is a ready-made Visual Basic aided script from tscmd.zip.
call C:\_F\XTOOLS\DATET.CMD /Q
echo ,,%DatetDD%.%DatetMM%.%DatetYYYY% %DatetHH%:%DatetMI%:%DatetSS%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
call C:\_F\XTOOLS\DATET.CMD /C /Q
Might produce e.g. (a date entry for an address book)
,,10.03.2015 14:41:38,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

:ThunderbirdWarning
tasklist|find /i "thunderbird.exe">nul
if %errorlevel% EQU 0 (
  echo Warning: Thunderbird is running^G
  rem Pause, so you can first decide what to do
  pause)
goto :EOF

:Latin1ToIbm
setlocal enableextensions
set filein_=%~1
set fileout_=%~2
set octset_=\206\204\224\201\202\207\221\244\217\216\231\232\220\200\222\245\240\242
"C:\_F\FTOOLS\unxtr.exe" %octset_% < "%filein_%" > "%fileout_%"
endlocal & goto :EOF

:Ibm2Latin1
setlocal enableextensions
set filein_=%~1
set fileout_=%~2
set octset_=\206\204\224\201\202\207\221\244\217\216\231\232\220\200\222\245\240\242
"C:\_F\FTOOLS\unxtr.exe" %octset_% < "%filein_%" > "%fileout_%"
endlocal & goto :EOF

:IbmStr2Latin1
setlocal
set tempfile1_=%temp_%\IbmStr2Latin1tmp1.txt
set tempfile2_=%temp_%\IbmStr2Latin1tmp2.txt
echo %~1 > "%tempfile1_%"
call :Ibm2Latin1 "%tempfile1_%" "%tempfile2_%"
for /f "usebackq tokens=*" %%a in (`type "%tempfile2_%"`) do set return_=%%a
for %%f in ("%tempfile1_%" "%tempfile2_%") do if exist %%f del %%f
endlocal & set "%2=%return_%" & goto :EOF


:
call :AssignTemp temp_
set keyword_=%~1
call :IbmStr2Latin1 "%keyword_%" keywordLat1_
call :ShowVarValue keyword_
call :ShowVarValue keywordLat1_
:
E.g.
C:\_M>C:\TEST\CMDFAQ.CMD "Sderfjrden Vaasa"
The value of keyword_ is Sderfjrden Vaasa
The value of keywordLat1_ is Sderfjrden Vaasa

:StrToLower
rem Poison characters not allowed
setlocal enableextensions
set return_=
set str_=%~1
for /f "usebackq tokens=*" %%a in (`
  echo %str_%^|^
  unxtr ABCDEFGHIJKLMNOPQRSTUVWXYZ\217\216\231^
        abcdefghijklmnopqrstuvwxyz\206\204\224`) do (
        set return_=%%a)
endlocal & set "%2=%return_%" & goto :EOF

:
set unxtr_=unxtr.exe
call :CheckExistenceAtPath Program "%unxtr_%" found_
if not defined found_ goto _out
:
call :StrToLower "%~1" lowstr_
call :ShowVarValue lowstr_
:
... Whatever else ...
:
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

E.g.
C:\_M>C:\TEST\CMDFAQ.CMD "Sderfjrden Vaasa"
The value of lowstr_ is sderfjrden vaasa

:RemoveLeadingZeros
setlocal enableextensions
  for /f "tokens=* delims=0 " %%a in ('echo %~1') do set return_=%%a
endlocal & set "%2=%return_%" & goto :EOF

:RemoveTrailingSpaces
setlocal
  set return_=
  >"%temp_%\tmp$$$.vbs" echo WScript.Echo Trim("%~1")
  for /f "tokens=* delims=" %%a in (
    'cscript //nologo "%temp_%\tmp$$$.vbs"') do set return_=%%a
  for %%f in ("%temp%_\tmp$$$.vbs") do if exist %%f del %%f
endlocal & set "%2=%return_%" & goto :EOF

:: Add leading blanks. Also see #Item 127.
:FuncRightJustify [String] [MaxLength] [ReturnedResult]
setlocal enableextensions enabledelayedexpansion
  set MaxLength=%~2
  set string_=            %1
  set string_=!string_:~-%MaxLength%!
endlocal & set "%3=%string_%" & goto :EOF

:: Add a leading zeros
:AddLeadingZeros
setlocal enableextensions enabledelayedexpansion
  set MaxLength=%~2
  set number_=000000000000%1
  set number_=!number_:~-%MaxLength%!
endlocal & set "%3=%number_%" & goto :EOF

:TestForInteger
setlocal enableextensions
set number_=%~1
set isInteger=true
echo %number_%|findstr "[^-0-9]">nul
if %errorlevel% EQU 0 set isInteger=
if "%number_%"=="" set isInteger=true
:: Allow negative integers
echo %number_%|find "-">nul
if %errorlevel% EQU 0 if not "%number_:~0,1%"=="-" set isInteger=
endlocal & set "%2=%isInteger%" & goto :EOF

rem This test is not foolproof
call :TestForInteger "%~1" isint_
if not defined isint_ (echo Error: %~1 is not an integer & goto :EOF)

:SmallDelay
ping -n 1 127.0.0.1>nul
goto :EOF

:GetLatest [Full filepath with wildcards]
setlocal enableextensions
set template_=%~1
set templatePath=%~dp1
set return_=
for /f "usebackq delims=" %%f in (
  `dir /a:-d /b /o:d "%template_%"`) do (
    set return_=%templatePath%%%~nxf)
endlocal & set "%2=%return_%" & goto :EOF

:
set searchFor=%~1
call :GetLatest "%searchFor%" latest_
call :ShowVarValue searchFor
call :ShowVarValue latest_
:
C:\_M>C:\TEST\CMDFAQ.CMD "C:\_H\PHOTO\HME2014A\*.JPG"
The value of searchFor is C:\_H\PHOTO\HME2014A\*.JPG
The value of latest_ is C:\_H\PHOTO\HME2014A\T2014123103.JPG

:FilesCount
setlocal
set template_=%~1
for /f "usebackq tokens=1" %%a in (
  `dir /a:-d "%template_%"^|findstr /c:" File\(s\) "`) do (
    set count_=%%a)
if not defined count_ set count_=0
endlocal & set "%2=%count_%" & goto :EOF

:
set searchFor=%~1
call :FilesCount "%searchFor%" count_
call :ShowVarValue count_
:
C:\_M>C:\TEST\CMDFAQ.CMD "C:\_H\PHOTO\HME2014A\*.JPG"
The value of count_ is 749

:GetRidOfThumbs [TargetFolder]
setlocal enableextensions
set folder_=%~1
dir /a:h /b /s "%folder_%\Thumbs.db" 2>&1 |find /i "%folder_%\Thumbs.db"
if %errorlevel% GTR 0 goto _eofGetRidOfThumbs
if exist "%temp_%\" pushd "%temp_%"
attrib -h -s "%folder_%\Thumbs.db"
if exist "%folder_%\Thumbs.db" del /p "%folder_%\Thumbs.db"
if exist "%folder_%\Thumbs.db" attrib +h +s +a "%folder_%\Thumbs.db"
if exist "%temp_%\" popd
:_eofGetRidOfThumbs
endlocal & goto :EOF

call :AssignTemp temp_
call :GetRidOfThumbs "C:\_H\RAW"

:IsWild
setlocal
set return_=
echo %~1|findstr "[*?]">nul
if %errorlevel% GTR 0 goto _endIsWild
echo %~1
echo Wildcards are not allowed in the file name^G
set return_=true
:_endIsWild
endlocal & set "%2=%return_%" & goto :EOF

:
:: Avoiding wildcards
call :IsWild "%~1" wild_
if defined wild_ goto _out
:
whatever
:
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

:IsSwitch
setlocal
set return_=false
echo %~1|findstr /b "[/]">nul
if %errorlevel% EQU 0 set return_=true
endlocal & set "%2=%return_%" & goto :EOF

:
:: Testing the parameter given in calling the script
call :IsSwitch "%~1" isswitch_
if "%isswitch_%"=="true" echo Parameter "%~1" is a switch
if "%isswitch_%"=="false" echo Parameter "%~1" is not a switch
:
whatever
:
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

:GetDateModifiedInUnxtouchFormat
setlocal enableextensions
call :AssignTemp temp_
set vbs_=%temp_%\GetDateModified.vbs
set skip=
>"%vbs_%" findstr "'%skip%VBSDATEMOD" "%~f0"
for /f "usebackq tokens=1-6 delims= " %%a in (`
  cscript //nologo "%vbs_%" "%~1"`) do (
    set yyyyMod=%%a
    set mmMod=%%b
    set ddMod=%%c
    set hhMod=%%d
    set mnMod=%%e
    set ssMod=%%f)
for %%f in ("%vbs_%") do if exist %%f del %%f
set return_=%mmMod%%ddMod%%hhMod%%mnMod%%yyyyMod%.%ssMod%
endlocal & set "%2=%return_%" & goto :EOF
'
'A Visual Basic Script to get a file's date modified in UNIX touch format

Set arg = WScript.Arguments 'VBSDATEMOD
Set fso = CreateObject("Scripting.FileSystemObject") 'VBSDATEMOD
Filename = arg(0) 'VBSDATEMOD
Set f = fso.GetFile(Filename) 'VBSDATEMOD
yyyy = DatePart("yyyy",f.DateLastModified) 'VBSDATEMOD
mm = Right(0 & DatePart("m",f.DateLastModified), 2) 'VBSDATEMOD
dd = Right(0 & DatePart("d",f.DateLastModified), 2) 'VBSDATEMOD
hh = Right(0 & DatePart("h",f.DateLastModified), 2) 'VBSDATEMOD
mn = Right(0 & DatePart("n",f.DateLastModified), 2) 'VBSDATEMOD
ss = Right(0 & DatePart("s",f.DateLastModified), 2) 'VBSDATEMOD
WScript.Echo yyyy & " " & mm & " " & dd & " " & hh & " " & mn & " " & ss 'VBSDATEMOD

@echo off & setlocal enableextensions
:
:: Get a file's modified date
call :GetDateModifiedInUnxtouchFormat "C:\_G\WWW\~NETIKKA\SALMTI02\INFO\tscmd300.php" unxdate_
call :ShowVarValue unxdate_
:
:: Reset a file's modified date from another's
call :GetDateModifiedInUnxtouchFormat "C:\_F\FHELP\OHJEITA.TXT" datemod_
C:\_F\FTOOLS\unxtouch.exe -t %datemod_% "C:\_Z\ohjeita.text"
:
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

C:\_M>C:\TEST\CMDFAQ.CMD
The value of unxdate_ is 032118112015.09

:CopyFoldToM
echo xcopy /d/f/v/i "%~1" "%~2\"
setlocal enableextensions enabledelayedexpansion
call :AskQuestionWithYdefault "Do [Y/n]?" reply_
if "!reply_!"=="n" goto _out
endlocal
xcopy /d/f/v/i "%~1" "%~2\"
echo.
echo "%~2\"
dir "%~2\" | findstr /c:" File(s) "
goto :EOF

:ConvertFoldToM
:: Copy a folder and its contents to a destination
:: Convert any IBM .txt files into Latin1 .text files
:: Preserve the original files' datetime stamps
echo Copy with txt to text from "%~1" to "%~2\"
setlocal enableextensions enabledelayedexpansion
call :AskQuestionWithYdefault "Do [Y/n]?" reply_
if "!reply_!"=="n" goto _out
if not exist "%~2\" mkdir "%~2"
for /f "usebackq delims=" %%f in (`
  dir /a:-d /s /b "%~1"`) do (
    if /i "%%~xf"==".txt" (
      rem The %%~dpnxf demonstrates file name expansion
      rem %%~ff would do the same
      call :Ibm2Latin1 "%%~dpnxf" "%~2\%%~nf.text"
      dir /s /b "%~2\%%~nf.text"
      call :GetDateModifiedInUnxtouchFormat "%%~dpnxf" datemod_
      C:\_F\FTOOLS\unxtouch.exe -t !datemod_! "%~2\%%~nf.text"
      )
    if /i not "%%~xf"==".txt" xcopy /d/f/v/i "%%~dpnxf" "%~2\"
    )
echo.
echo "%~2\"
dir "%~2\" | findstr /c:" File(s) "
endlocal & goto :EOF

:
set doit_=
if /i "%~1"=="/7" set doit_=true
if /i "%~1"=="/t2017" set doit_=true
if /i "%~1"=="t2017" set doit_=true
if defined doit_ (
  set switchok_=true
  call :ConvertFoldToM "C:\_D\TILIT\2017\*.*" "C:\_M\_Local\TILIT\2017"
  goto _out)
:

:CheckExifExistence
setlocal enableextensions
set return_=
"%jhead_%" -ft "%~1"|find "contains no Exif timestamp" > nul
if %errorlevel% EQU 1 set return_=true
endlocal & set "%2=%return_%" & goto :EOF

@echo off & setlocal enableextensions
set filename_=%~1
set jhead_=C:\_F\BOX\BOXTOOLS\jhead.exe
call :CheckExistence "Program (get it at http://www.sentex.net/~mwandel/jhead/)" "%jhead_%" found_
if not defined found_ goto _out
call :IsWild "%~1" wild_
if defined wild_ goto _out
call :CheckExistence File "%filename_%" found_
if not defined found_ goto _out
:
call :CheckExifExistence "%filename_%" foundExif_
if defined foundExif_ (
  echo Exif data found in "%filename_%"
  ) else (
  echo No Exif data found in "%filename_%")
:
:_out
if not defined cmdbox if defined PauseIfFromDesktop pause
endlocal & goto :EOF

C:\_M>C:\TEST\CMDFAQ.CMD "C:\_M\T2015042901.JPG"
Exif data found in "C:\_M\T2015042901.JPG"

:ShowOneExif
setlocal
rem http://www.sentex.net/~mwandel/jhead/
set jhead_=C:\_F\BOX\BOXTOOLS\jhead297.exe
echo.
%jhead_% "%~1" | findstr /b /c:"File name    :"
%jhead_% "%~1" | findstr /b /c:"File size    :"
%jhead_% "%~1" | findstr /b /c:"Date/Time    :"
%jhead_% "%~1" | findstr /b /c:"Resolution   :"
endlocal & goto :EOF

@echo off & setlocal enableextensions
:: Decompose the filename into two parts to handle a flat path only
:: because dir /b /s would traverse also the subfolders
set filepath_=C:\_H\PHOTO\HME2017A
set filebase_=*.JPG
pushd "%filepath_%"
for /f "usebackq tokens=*" %%f in (`
  dir /a:-d /b "%filebase_%"`) do (
    call :ShowOneExif "%filepath_%\%%~f")
popd
endlocal & goto :EOF

C:\_M>C:\TEST\CMDFAQ.CMD

File name     : C:\_H\PHOTO\HME2017A\T2017040902.JPG
File size     : 136910 bytes
Date/Time     : 2017:04:09 14:56:12
Resolution    : 1024 x 768

File name     : C:\_H\PHOTO\HME2017A\T2017040903.JPG
File size     : 109450 bytes
Date/Time     : 2017:04:09 14:57:50
Resolution    : 1024 x 768

:: alternatively
set fullname_=C:\_H\PHOTO\HME2017A\*.JPG
for /f "usebackq tokens=*" %%f in (`
  attrib "%fullname_%" ^|^
   unxgawk "{printf\"%%s\n\",strftime(substr($0,14))}"`) do (
    call :ShowOneExif "%%~ff")

:GetDateThen
setlocal
:: https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html
for /f "tokens=1-3 delims= " %%a in ('
unxgawk "BEGIN{printf\"%%s\n\",strftime(\"%%Y %%m %%d\",systime()-(%1*24*60*60))}"') do (
  set YYYY=%%a
  set MM=%%b
  set DD=%%c)
set dateThen_=%YYYY%%MM%%DD%
endlocal & set "%2=%dateThen_%" & goto :EOF

:
call :GetDateThen 7 then_
echo A week ago it was %then_%
:

:WeekdayNumberNow
setlocal
set temp_=%temp%
if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
echo>"%temp_%\tmpwd$$$.vbs" WScript.Echo Weekday(Date,vbMonday)
for /f %%d in ('cscript //nologo "%temp_%\tmpwd$$$.vbs"') do set return_=%%d
for %%f in ("%temp_%\tmpwd$$$.vbs") do if exist %%f del %%f
endlocal & set "%1=%return_%" & goto :EOF

:FinWeekday
setlocal enableextensions enabledelayedexpansion
set WeekdayArray=SuMaTiKeToPeLa
set /a i_=2*%~1
set return_=!WeekdayArray:~%i_%,2!
endlocal & set "%2=%return_%" & goto :EOF

:FinMonth
setlocal enableextensions enabledelayedexpansion
set MonthArray=TamHelMaaHuhTouKesHeiEloSyyLokMarJou
set /a i_=3*(%~1-1)
set return_=!MonthArray:~%i_%,3!
endlocal & set "%2=%return_%" & goto :EOF

@echo off & setlocal enableextensions enabledelayedexpansion
https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html
for /f "usebackq" %%d in (`
  unxgawk "BEGIN{printf\"%%s\n\",strftime(\"%%A\")}"`) do (
    set wd_=%%d)
for /f "usebackq tokens=1-6 delims= " %%a in (`
  unxgawk "BEGIN{printf\"%%s\n\",strftime(\"%%Y %%m %%d %%H %%M %%S\")}"`) do (
    set YYYY=%%a
    set MM=%%b
    set DD=%%c
    set HH=%%d
    set MN=%%e
    set SS=%%f)
for /f "usebackq" %%a in (`
  unxgawk "BEGIN{printf\"%%s\n\",strftime(\"%%A\")}"`) do (
    set wd_=%%a)
echo Today is %wd_% %DD%.%MM%.%YYYY% %HH%:%MN%:%SS%
:
call :WeekdayNumberNow wdnum_
call :FinWeekday %wdnum_% dayname_
echo wdnum_=%wdnum_% is %dayname_% for short in Finnish
echo.
:
for /L %%d in (0,1,6) do (
  call :FinWeekday %%d dayname_
  echo %%d !dayname_!)
for /L %%m in (1,1,12) do (
  call :FinMonth %%m monthname_
  echo %%m !monthname_!)
endlocal & goto :EOF

C:\_M>C:\TEST\CMDFAQ.CMD
Today is Tuesday 28.02.2017 10:49:13
wdnum_=2 is Ti for short in Finnish

0 Su
1 Ma
2 Ti
3 Ke
4 To
5 Pe
6 La
1 Tam
2 Hel
3 Maa
4 Huh
5 Tou
6 Kes
7 Hei
8 Elo
9 Syy
10 Lok
11 Mar
12 Jou

:CurrentScript
setlocal
set d_=%~d1
if "%d_%"=="c:" set d_=C:
if "%d_%"=="d:" set d_=D:
echo "%d_%%~pnx1"
echo.
dir "%d_%%~pnx1"|findstr /i "%~nx1"
endlocal & goto :EOF

:: On demand, display the full filename of the current script
if /i "%~1"=="/0" (
  call :ProgramTitle
  echo/
  call :CurrentScript "%~f0"
  goto _out)
or
:: On demand, display the full filename of the current script
if /i "%~1"=="/0" (call :ProgramTitle & echo. & call :CurrentScript "%~f0" & goto _out)

:TimeDiff
setlocal enableextensions
call :Trim %1 hh1
call :Trim %2 mi1
call :Trim %3 ss1
call :Trim %4 hh2
call :Trim %5 mi2
call :Trim %6 ss2
set /a diffSec=60*60*%hh2%+60*%mi2%+%ss2%-(60*60*%hh1%+60*%mi1%+%ss1%)
if %diffSec% LSS 0 set /a diffSec=%diffSec%+24*60*60
set /a h=(%diffSec%/3600)
set /a m=(%diffSec%/60)-60*%h%
set /a s=%diffSec%-60*(%diffSec%/60)
set h=0%h%
set h=%h:~-2%
set m=0%m%
set m=%m:~-2%
set s=0%s%
set s=%s:~-2%
endlocal&set "%7=%h%"&set "%8=%m%"&set "%9=%s%"&goto :EOF

:Trim
setlocal enableextensions
echo %1|findstr [123456789]>nul
if %errorlevel% EQU 0 (
  for /f "tokens=* delims=0 " %%a in ('echo %~1') do (
    set Return_=%%a)
  ) else (set Return_=0)
endlocal & set "%2=%Return_%" & goto :EOF

::
rem datet.cmd code is available in tscmd.zip
call datet /q
set beginat_=%DatetDD%.%DatetMM%.%DatetYYYY% %DatetHH%:%DatetMI%:%DatetSS%
set DatetHHb=%DatetHH%
set DatetMIb=%DatetMI%
set DatetSSb=%DatetSS%
:
Whatever
:
call datet /q
set endat_=%DatetDD%.%DatetMM%.%DatetYYYY% %DatetHH%:%DatetMI%:%DatetSS%
echo.
echo Start: %beginat_%
echo End: %endat_%
call :TimeDiff %DatetHHb% %DatetMIb% %DatetSSb% %DatetHH% %DatetMI% %DatetSS% hh_ mi_ ss_
echo Elapsed: %hh_%:%mi_%:%ss_%
:

C:\_M>C:\TEST\CMDFAQ.CMD
:
Start: 13.09.2016 10:38:20
End:   13.09.2016 10:38:41
Elapsed: 00:21
:

:DetabFile
set sed_=unxsed.exe
"%sed_%" -e "s/\t/        /g" "%~1"
goto :EOF

:
call :DetabFile "C:\_M\mail.eml"
:

:: Prune excessive old file versions from a set
:PurgeOneSet
setlocal enableextensions enabledelayedexpansion
echo Called :PurgeOneSet
set sourcedir_=%~1
set template_=%sourcedir_%\%~2
set dumptodir_=C:\_M\TEMP
if not exist "%sourcedir_%\" (
  echo Source folder "!sourcedir_!" not found, exiting^G
  endlocal & goto :EOF)
if not exist "%dumptodir_%\" (
  echo Target folder "!dumptodir_!" not found, exiting^G
  endlocal & goto :EOF)
rem echo "%template_%"
call :FilesCount "%template_%" count_
if %count_% LEQ %skip_% (
  echo "%template_%"
  echo Information: Only %count_% files, PURGE not needed
  echo/
  goto _endPurgeOneSet)
echo.
for /f "delims=" %%f in (
  'dir /a:-d /b /o:-d "%template_%"') do (
    echo "%sourcedir_%\%%~nf%%~xf")
echo Delete all but the %skipverbal_% latest versions?
call :AskQuestionWithNdefault "Continue [y,N]?" reply_
if "!reply_!"=="n" goto _dirPurgeOneSet
for /f "skip=%skip_% delims=" %%f in (
  'dir /a:-d /b /o:-d "%template_%"') do (
    echo move /-y "%sourcedir_%\%%~nf%%~xf" "!dumptodir_!\"
    move /-y "%sourcedir_%\%%~nf%%~xf" "!dumptodir_!\")
:_dirPurgeOneSet
for /f "delims=" %%f in (
'dir /a:-d /b /o:-d "%template_%"') do (
echo "%sourcedir_%\%%~nf%%~xf")
:_endPurgeOneSet
endlocal & goto :EOF

:
set skip_=5
set skipverbal_=five
:
call :PurgeOneSet "C:\_I\BACKUPTS\FF3" "bookmarksTS*.json"
:

Also see the list of modules in #Item18